diff --git a/.mailmap b/.mailmap index c5ecfb54fca52..da8044de405a6 100644 --- a/.mailmap +++ b/.mailmap @@ -117,6 +117,9 @@ Jason Toffaletti Jason Toffaletti Jauhien Piatlicki Jauhien Piatlicki Jay True Jeremy Letang +Jeremy Stucki +Jeremy Stucki +Jeremy Stucki Jethro Beekman Jihyun Yu Jihyun Yu jihyun @@ -181,12 +184,19 @@ Neil Pankey Nick Platt Nicole Mazzuca Nif Ward -Oliver Schneider oli-obk -Oliver Schneider Oliver 'ker' Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider -Oliver Schneider Oliver Schneider +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer +Oliver Scherer Ožbolt Menegatti gareins Paul Faria Paul Faria Peer Aramillo Irizar parir diff --git a/Cargo.lock b/Cargo.lock index 660f2ba237008..e0d30647809a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,7 +185,7 @@ dependencies = [ "serde", "serde_json", "time", - "toml 0.4.10", + "toml", ] [[package]] @@ -202,7 +202,7 @@ name = "build-manifest" version = "0.1.0" dependencies = [ "serde", - "toml 0.4.10", + "toml", ] [[package]] @@ -287,7 +287,7 @@ dependencies = [ "git2-curl", "glob", "hex", - "home 0.4.2", + "home 0.5.0", "ignore", "im-rc", "jobserver", @@ -316,7 +316,7 @@ dependencies = [ "tar", "tempfile", "termcolor", - "toml 0.5.3", + "toml", "unicode-width", "url 2.1.0", "walkdir", @@ -442,7 +442,7 @@ dependencies = [ "semver", "serde", "smallvec", - "toml 0.5.3", + "toml", "unicode-normalization", "url 2.1.0", ] @@ -946,6 +946,7 @@ name = "error_index_generator" version = "0.0.0" dependencies = [ "rustdoc", + "walkdir", ] [[package]] @@ -1138,10 +1139,12 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.19" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ + "rustc-std-workspace-core", + "rustc-std-workspace-std", "unicode-width", ] @@ -1157,9 +1160,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb400360e8a4d61b10e648285bbfa919bbf9519d0d5d5720354456f44349226" +checksum = "327d698f86a7ebdfeb86a4238ccdb004828939d3a3555b6ead679541d14e36c0" dependencies = [ "bitflags", "libc", @@ -1172,9 +1175,9 @@ dependencies = [ [[package]] name = "git2-curl" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2293de73491c3dc4174c5949ef53d2cc037b27613f88d72032e3f5237247a7dd" +checksum = "cd6527e480187ce19aaf4fa6acfb7657b25628ce31cb8ffabdfca3bf731524c5" dependencies = [ "curl", "git2", @@ -1279,9 +1282,9 @@ dependencies = [ [[package]] name = "home" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "013e4e6e9134211bb4d6bf53dd8cfb75d9e2715cc33614b9c0827718c6fbe0b8" +checksum = "c07c315e106bd6f83f026a20ddaeef2706782e490db1dcdd37caad38a0e895b3" dependencies = [ "scopeguard 1.0.0", "winapi 0.3.6", @@ -1579,9 +1582,9 @@ checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +checksum = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" dependencies = [ "rustc-std-workspace-core", ] @@ -1601,9 +1604,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c179ed6d19cd3a051e68c177fbbc214e79ac4724fac3a850ec9f3d3eb8a5578" +checksum = "8c2078aec6f4b16d1b89f6a72e4f6eb1e75ffa85312023291e89c6d3087bc8fb" dependencies = [ "cc", "libc", @@ -1665,9 +1668,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ "cfg-if", ] @@ -1785,7 +1788,7 @@ dependencies = [ "serde_json", "shlex", "tempfile", - "toml 0.5.3", + "toml", "toml-query", ] @@ -1989,6 +1992,7 @@ dependencies = [ "compiletest_rs", "directories", "env_logger 0.6.0", + "getrandom", "hex", "log", "num-traits", @@ -2374,6 +2378,9 @@ dependencies = [ [[package]] name = "proc_macro" version = "0.0.0" +dependencies = [ + "std", +] [[package]] name = "profiler_builtins" @@ -2760,7 +2767,7 @@ dependencies = [ "tokio", "tokio-process", "tokio-timer", - "toml 0.5.3", + "toml", "url 1.7.2", "walkdir", ] @@ -3062,6 +3069,13 @@ dependencies = [ "core", ] +[[package]] +name = "rustc-std-workspace-std" +version = "1.0.0" +dependencies = [ + "std", +] + [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -3218,6 +3232,7 @@ dependencies = [ "rustc_data_structures", "serialize", "syntax_pos", + "term_size", "termcolor", "unicode-width", ] @@ -3564,7 +3579,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.4" +version = "1.4.6" dependencies = [ "annotate-snippets", "atty", @@ -3590,7 +3605,7 @@ dependencies = [ "serde_json", "structopt", "term 0.6.0", - "toml 0.5.3", + "toml", "unicode-segmentation", "unicode-width", "unicode_categories", @@ -4067,6 +4082,10 @@ dependencies = [ [[package]] name = "term" version = "0.0.0" +dependencies = [ + "core", + "std", +] [[package]] name = "term" @@ -4089,6 +4108,17 @@ dependencies = [ "winapi 0.3.6", ] +[[package]] +name = "term_size" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" +dependencies = [ + "kernel32-sys", + "libc", + "winapi 0.2.8", +] + [[package]] name = "termcolor" version = "1.0.4" @@ -4113,8 +4143,13 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ + "core", "getopts", + "libc", + "panic_abort", + "panic_unwind", "proc_macro", + "std", "term 0.0.0", ] @@ -4382,15 +4417,6 @@ dependencies = [ "tokio-reactor", ] -[[package]] -name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -dependencies = [ - "serde", -] - [[package]] name = "toml" version = "0.5.3" @@ -4411,7 +4437,7 @@ dependencies = [ "is-match", "lazy_static 1.3.0", "regex", - "toml 0.5.3", + "toml", "toml-query_derive", ] @@ -4491,9 +4517,14 @@ checksum = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" [[package]] name = "unicode-width" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +checksum = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", + "rustc-std-workspace-std", +] [[package]] name = "unicode-xid" diff --git a/Cargo.toml b/Cargo.toml index ccd7e8b7654a6..a242f090fbc07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ rustc-workspace-hack = { path = 'src/tools/rustc-workspace-hack' } # here rustc-std-workspace-core = { path = 'src/tools/rustc-std-workspace-core' } rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' } +rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' } [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } diff --git a/config.toml.example b/config.toml.example index a3ec4f2044cbd..30e2ee1b9babf 100644 --- a/config.toml.example +++ b/config.toml.example @@ -382,11 +382,6 @@ # This is the name of the directory in which codegen backends will get installed #codegen-backends-dir = "codegen-backends" -# Flag indicating whether `libstd` calls an imported function to handle basic IO -# when targeting 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 - # Indicates whether LLD will be compiled and made available in the sysroot for # rustc to execute. #lld = false diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 589ee9276a5a3..c27c318f5ad07 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -44,7 +44,7 @@ cc = "1.0.35" libc = "0.2" serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" -toml = "0.4" +toml = "0.5" lazy_static = "1.3.0" time = "0.1" petgraph = "0.4.13" diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index bd1a87c5744d3..138b7f4b26104 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -5,9 +5,6 @@ //! parent directory, and otherwise documentation can be found throughout the `build` //! directory in each respective module. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; use bootstrap::{Config, Build}; diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index ce92ce0269671..8cb48df14bfef 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -15,9 +15,6 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; use std::ffi::OsString; use std::io; @@ -124,8 +121,9 @@ fn main() { if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none() { - // When extending this list, search for `NO-RUSTC-WRAPPER` and add the new lints - // there as well, some code doesn't go through this `rustc` wrapper. + // When extending this list, add the new lints to the RUSTFLAGS of the + // build_bootstrap function of src/bootstrap/bootstrap.py as well as + // some code doesn't go through this `rustc` wrapper. cmd.arg("-Dwarnings"); cmd.arg("-Drust_2018_idioms"); cmd.arg("-Dunused_lifetimes"); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ff38ee8788f56..a13ff69a7b56f 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -2,12 +2,10 @@ //! //! See comments in `src/bootstrap/rustc.rs` for more information. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::env; use std::process::Command; use std::path::PathBuf; +use std::ffi::OsString; fn main() { let args = env::args_os().skip(1).collect::>(); @@ -47,7 +45,9 @@ fn main() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { - cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + let mut arg = OsString::from("-Clinker="); + arg.push(&linker); + cmd.arg(arg); } // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 86901792d7974..4162fe1df5086 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -320,7 +320,7 @@ class RustBuild(object): def __init__(self): self.cargo_channel = '' self.date = '' - self._download_url = 'https://static.rust-lang.org' + self._download_url = '' self.rustc_channel = '' self.build = '' self.build_dir = os.path.join(os.getcwd(), "build") @@ -631,6 +631,8 @@ def build_bootstrap(self): target_linker = self.get_toml("linker", build_section) if target_linker is not None: env["RUSTFLAGS"] += "-C linker=" + target_linker + " " + if self.get_toml("deny-warnings", "rust") != "false": + env["RUSTFLAGS"] += "-Dwarnings -Drust_2018_idioms -Dunused_lifetimes " env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] @@ -731,9 +733,19 @@ def update_submodules(self): self.update_submodule(module[0], module[1], recorded_submodules) print("Submodules updated in %.2f seconds" % (time() - start_time)) + def set_normal_environment(self): + """Set download URL for normal environment""" + if 'RUSTUP_DIST_SERVER' in os.environ: + self._download_url = os.environ['RUSTUP_DIST_SERVER'] + else: + self._download_url = 'https://static.rust-lang.org' + def set_dev_environment(self): """Set download URL for development environment""" - self._download_url = 'https://dev-static.rust-lang.org' + if 'RUSTUP_DEV_DIST_SERVER' in os.environ: + self._download_url = os.environ['RUSTUP_DEV_DIST_SERVER'] + else: + self._download_url = 'https://dev-static.rust-lang.org' def check_vendored_status(self): """Check that vendoring is configured properly""" @@ -826,6 +838,8 @@ def bootstrap(help_triggered): if 'dev' in data: build.set_dev_environment() + else: + build.set_normal_environment() build.update_submodules() diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 955809e80747b..4f5de1ecd2b44 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -337,7 +337,6 @@ impl<'a> Builder<'a> { match kind { Kind::Build => describe!( compile::Std, - compile::Test, compile::Rustc, compile::CodegenBackend, compile::StartupObjects, @@ -363,7 +362,6 @@ impl<'a> Builder<'a> { ), Kind::Check | Kind::Clippy | Kind::Fix => describe!( check::Std, - check::Test, check::Rustc, check::CodegenBackend, check::Rustdoc @@ -425,8 +423,6 @@ impl<'a> Builder<'a> { doc::TheBook, doc::Standalone, doc::Std, - doc::Test, - doc::WhitelistedRustc, doc::Rustc, doc::Rustdoc, doc::ErrorIndex, @@ -801,7 +797,7 @@ impl<'a> Builder<'a> { } match mode { - Mode::Std | Mode::Test | Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolTest=> {}, + Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}, Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { // Build proc macros both for the host and the target if target != compiler.host && cmd != "check" { @@ -852,7 +848,6 @@ impl<'a> Builder<'a> { // things still build right, please do! match mode { Mode::Std => metadata.push_str("std"), - Mode::Test => metadata.push_str("test"), _ => {}, } cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); @@ -875,8 +870,7 @@ impl<'a> Builder<'a> { } if cmd == "clippy" { - extra_args.push_str("-Zforce-unstable-if-unmarked -Zunstable-options \ - --json-rendered=termcolor"); + extra_args.push_str("-Zforce-unstable-if-unmarked"); } if !extra_args.is_empty() { @@ -949,9 +943,9 @@ impl<'a> Builder<'a> { let debuginfo_level = match mode { Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, - Mode::Std | Mode::Test => self.config.rust_debuginfo_level_std, + Mode::Std => self.config.rust_debuginfo_level_std, Mode::ToolBootstrap | Mode::ToolStd | - Mode::ToolTest | Mode::ToolRustc => self.config.rust_debuginfo_level_tools, + Mode::ToolRustc => self.config.rust_debuginfo_level_tools, }; cargo.env("RUSTC_DEBUGINFO_LEVEL", debuginfo_level.to_string()); @@ -1151,7 +1145,6 @@ impl<'a> Builder<'a> { match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) { (Mode::Std, Some(n), _) | - (Mode::Test, Some(n), _) | (_, _, Some(n)) => { cargo.env("RUSTC_CODEGEN_UNITS", n.to_string()); } diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index d1542b1fca6b7..2bb90fdb04edc 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -365,27 +365,6 @@ fn dist_with_same_targets_and_hosts() { }, ] ); - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - ] - ); assert_eq!( first(builder.cache.all::()), &[ @@ -415,7 +394,47 @@ fn build_default() { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert!(!builder.cache.all::().is_empty()); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Std { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); assert!(!builder.cache.all::().is_empty()); assert_eq!( first(builder.cache.all::()), @@ -450,63 +469,61 @@ fn build_default() { }, ] ); +} + +#[test] +fn build_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.skip_only_host_steps = true; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); assert_eq!( - first(builder.cache.all::()), + first(builder.cache.all::()), &[ - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b, }, - compile::Test { + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c, }, - compile::Test { + compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c, }, ] ); -} - -#[test] -fn build_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; - let build = Build::new(config); - let mut builder = Builder::new(&build); - builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); - - assert!(!builder.cache.all::().is_empty()); assert_eq!( first(builder.cache.all::()), &[ @@ -541,48 +558,6 @@ fn build_with_target_flag() { }, ] ); - - assert_eq!( - first(builder.cache.all::()), - &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ] - ); } #[test] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 6e6fea6b831a7..205a80c3a3a9e 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,6 +1,6 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, +use crate::compile::{run_cargo, std_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; use crate::builder::{RunConfig, Builder, Kind, ShouldRun, Step}; use crate::tool::{prepare_tool_cargo, SourceType}; @@ -34,7 +34,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("std") + run.all_krates("test") } fn make_run(run: RunConfig<'_>) { @@ -92,7 +92,7 @@ impl Step for Rustc { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - builder.ensure(Test { target }); + builder.ensure(Std { target }); let mut cargo = builder.cargo(compiler, Mode::Rustc, target, cargo_subcommand(builder.kind)); @@ -159,47 +159,6 @@ impl Step for CodegenBackend { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Test { - pub target: Interned, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("test") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(0, builder.config.build); - let target = self.target; - - builder.ensure(Std { target }); - - let mut cargo = builder.cargo(compiler, Mode::Test, target, cargo_subcommand(builder.kind)); - test_cargo(builder, &compiler, target, &mut cargo); - - builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target)); - run_cargo(builder, - &mut cargo, - args(builder.kind), - &libtest_stamp(builder, compiler, target), - true); - - let libdir = builder.sysroot_libdir(compiler, target); - let hostdir = builder.sysroot_libdir(compiler, compiler.host); - add_to_sysroot(builder, &libdir, &hostdir, &libtest_stamp(builder, compiler, target)); - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustdoc { pub target: Interned, @@ -258,16 +217,6 @@ pub fn libstd_stamp( builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } -/// Cargo's output path for libtest in a given stage, compiled by a particular -/// compiler for the specified target. -pub fn libtest_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned, -) -> PathBuf { - builder.cargo_out(compiler, Mode::Test, target).join(".libtest-check.stamp") -} - /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp( diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 96987d081594f..9d57a4f00d780 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -39,7 +39,7 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("std") + run.all_krates("test") } fn make_run(run: RunConfig<'_>) { @@ -216,7 +216,7 @@ pub fn std_cargo(builder: &Builder<'_>, cargo.arg("--features").arg(features) .arg("--manifest-path") - .arg(builder.src.join("src/libstd/Cargo.toml")); + .arg(builder.src.join("src/libtest/Cargo.toml")); if target.contains("musl") { if let Some(p) = builder.musl_root(target) { @@ -358,129 +358,6 @@ impl Step for StartupObjects { } } -#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] -pub struct Test { - pub target: Interned, - pub compiler: Compiler, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.all_krates("test") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - compiler: run.builder.compiler(run.builder.top_stage, run.host), - target: run.target, - }); - } - - /// Builds libtest. - /// - /// This will build libtest and supporting libraries for a particular stage of - /// the build using the `compiler` targeting the `target` architecture. The - /// artifacts created will also be linked into the sysroot directory. - fn run(self, builder: &Builder<'_>) { - let target = self.target; - let compiler = self.compiler; - - builder.ensure(Std { compiler, target }); - - if builder.config.keep_stage.contains(&compiler.stage) { - builder.info("Warning: Using a potentially old libtest. This may not behave well."); - builder.ensure(TestLink { - compiler, - target_compiler: compiler, - target, - }); - return; - } - - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - if compiler_to_use != compiler { - builder.ensure(Test { - compiler: compiler_to_use, - target, - }); - builder.info( - &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target)); - builder.ensure(TestLink { - compiler: compiler_to_use, - target_compiler: compiler, - target, - }); - return; - } - - let mut cargo = builder.cargo(compiler, Mode::Test, target, "build"); - test_cargo(builder, &compiler, target, &mut cargo); - - builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, - &compiler.host, target)); - run_cargo(builder, - &mut cargo, - vec![], - &libtest_stamp(builder, compiler, target), - false); - - builder.ensure(TestLink { - compiler: builder.compiler(compiler.stage, builder.config.build), - target_compiler: compiler, - target, - }); - } -} - -/// Same as `std_cargo`, but for libtest -pub fn test_cargo(builder: &Builder<'_>, - _compiler: &Compiler, - _target: Interned, - cargo: &mut Command) { - if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { - cargo.env("MACOSX_DEPLOYMENT_TARGET", target); - } - cargo.arg("--manifest-path") - .arg(builder.src.join("src/libtest/Cargo.toml")); -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct TestLink { - pub compiler: Compiler, - pub target_compiler: Compiler, - pub target: Interned, -} - -impl Step for TestLink { - type Output = (); - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - /// Same as `std_link`, only for libtest - fn run(self, builder: &Builder<'_>) { - let compiler = self.compiler; - let target_compiler = self.target_compiler; - let target = self.target; - builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", - target_compiler.stage, - compiler.stage, - &compiler.host, - target_compiler.host, - target)); - add_to_sysroot( - builder, - &builder.sysroot_libdir(target_compiler, target), - &builder.sysroot_libdir(target_compiler, compiler.host), - &libtest_stamp(builder, compiler, target) - ); - } -} - #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { pub target: Interned, @@ -512,7 +389,7 @@ impl Step for Rustc { let compiler = self.compiler; let target = self.target; - builder.ensure(Test { compiler, target }); + builder.ensure(Std { compiler, target }); if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); @@ -541,7 +418,7 @@ impl Step for Rustc { } // Ensure that build scripts and proc macros have a std / libproc_macro to link against. - builder.ensure(Test { + builder.ensure(Std { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); @@ -872,16 +749,6 @@ pub fn libstd_stamp( builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") } -/// Cargo's output path for libtest in a given stage, compiled by a particular -/// compiler for the specified target. -pub fn libtest_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned, -) -> PathBuf { - builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp") -} - /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp( diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index a5bfafdfdb4dc..43d9264eaca92 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -122,7 +122,6 @@ pub struct Config { // libstd features pub backtrace: bool, // support for RUST_BACKTRACE - pub wasm_syscall: bool, // misc pub low_priority: bool, @@ -318,7 +317,6 @@ struct Rust { save_toolstates: Option, codegen_backends: Option>, codegen_backends_dir: Option, - wasm_syscall: Option, lld: Option, lldb: Option, llvm_tools: Option, @@ -558,7 +556,6 @@ impl Config { if let Some(true) = rust.incremental { config.incremental = true; } - set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 213ceb194a814..0f4ac63651ca9 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -678,12 +678,7 @@ impl Step for Std { if builder.hosts.iter().any(|t| t == target) { builder.ensure(compile::Rustc { compiler, target }); } else { - if builder.no_std(target) == Some(true) { - // the `test` doesn't compile for no-std targets - builder.ensure(compile::Std { compiler, target }); - } else { - builder.ensure(compile::Test { compiler, target }); - } + builder.ensure(compile::Std { compiler, target }); } let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); @@ -912,6 +907,7 @@ impl Step for Src { "src/libproc_macro", "src/tools/rustc-std-workspace-core", "src/tools/rustc-std-workspace-alloc", + "src/tools/rustc-std-workspace-std", "src/librustc", "src/libsyntax", ]; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 36229720e42cd..6faedc80ad3f5 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -375,7 +375,7 @@ impl Step for Standalone { up_to_date(&footer, &html) && up_to_date(&favicon, &html) && up_to_date(&full_toc, &html) && - up_to_date(&version_info, &html) && + (builder.config.dry_run || up_to_date(&version_info, &html)) && (builder.config.dry_run || up_to_date(&rustdoc, &html)) { continue } @@ -413,7 +413,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("std").default_condition(builder.config.docs) + run.all_krates("test").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -478,138 +478,12 @@ impl Step for Std { builder.run(&mut cargo); builder.cp_r(&my_out, &out); }; - for krate in &["alloc", "core", "std"] { + for krate in &["alloc", "core", "std", "proc_macro", "test"] { run_cargo_rustdoc_for(krate); } } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct Test { - stage: u32, - target: Interned, -} - -impl Step for Test { - type Output = (); - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.krate("test").default_condition(builder.config.docs) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Test { - stage: run.builder.top_stage, - target: run.target, - }); - } - - /// Compile all libtest documentation. - /// - /// This will generate all documentation for libtest and its dependencies. This - /// is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let target = self.target; - builder.info(&format!("Documenting stage{} test ({})", stage, target)); - let out = builder.doc_out(target); - t!(fs::create_dir_all(&out)); - let compiler = builder.compiler_for(stage, builder.config.build, target); - - // Build libstd docs so that we generate relative links - builder.ensure(Std { stage, target }); - - builder.ensure(compile::Test { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Test) - .join(target).join("doc"); - - // See docs in std above for why we symlink - let my_out = builder.crate_doc_out(target); - t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - - let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc"); - compile::test_cargo(builder, &compiler, target, &mut cargo); - - cargo.arg("--no-deps") - .arg("-p").arg("test") - .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) - .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); - - builder.run(&mut cargo); - builder.cp_r(&my_out, &out); - } -} - -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct WhitelistedRustc { - stage: u32, - target: Interned, -} - -impl Step for WhitelistedRustc { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - run.krate("rustc-main").default_condition(builder.config.docs) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(WhitelistedRustc { - stage: run.builder.top_stage, - target: run.target, - }); - } - - /// Generates whitelisted compiler crate documentation. - /// - /// This will generate all documentation for crates that are whitelisted - /// to be included in the standard documentation. This documentation is - /// included in the standard Rust documentation, so we should always - /// document it and symlink to merge with the rest of the std and test - /// documentation. We don't build other compiler documentation - /// here as we want to be able to keep it separate from the standard - /// documentation. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { - let stage = self.stage; - let target = self.target; - builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); - let out = builder.doc_out(target); - t!(fs::create_dir_all(&out)); - let compiler = builder.compiler_for(stage, builder.config.build, target); - - // Build libstd docs so that we generate relative links - builder.ensure(Std { stage, target }); - - builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Rustc) - .join(target).join("doc"); - - // See docs in std above for why we symlink - let my_out = builder.crate_doc_out(target); - t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - - let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); - compile::rustc_cargo(builder, &mut cargo); - - // We don't want to build docs for internal compiler dependencies in this - // step (there is another step for that). Therefore, we whitelist the crates - // for which docs must be built. - for krate in &["proc_macro"] { - cargo.arg("-p").arg(krate) - .env("RUSTDOC_RESOURCE_SUFFIX", crate::channel::CFG_RELEASE_NUM) - .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); - } - - builder.run(&mut cargo); - builder.cp_r(&my_out, &out); - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustc { stage: u32, @@ -825,8 +699,7 @@ impl Step for ErrorIndex { index.arg(crate::channel::CFG_RELEASE_NUM); // FIXME: shouldn't have to pass this env var - index.env("CFG_BUILD", &builder.config.build) - .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); + index.env("CFG_BUILD", &builder.config.build); builder.run(&mut index); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b72aa78f3de19..5d7581c8211be 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,9 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - #![feature(core_intrinsics)] #![feature(drain_filter)] @@ -297,9 +294,6 @@ pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. Std, - /// Build libtest, placing output in the "stageN-test" directory. - Test, - /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, @@ -315,7 +309,6 @@ pub enum Mode { /// Compile a tool which uses all libraries we compile (up to rustc). /// Doesn't use the stage0 compiler libraries like "other", and includes /// tools like rustdoc, cargo, rls, etc. - ToolTest, ToolStd, ToolRustc, } @@ -502,9 +495,6 @@ impl Build { if self.config.profiler { features.push_str(" profiler"); } - if self.config.wasm_syscall { - features.push_str(" wasm_syscall"); - } features } @@ -536,11 +526,10 @@ impl Build { fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf { let suffix = match mode { Mode::Std => "-std", - Mode::Test => "-test", Mode::Rustc => "-rustc", Mode::Codegen => "-codegen", Mode::ToolBootstrap => "-bootstrap-tools", - Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "-tools", + Mode::ToolStd | Mode::ToolRustc => "-tools", }; self.out.join(&*compiler.host) .join(format!("stage{}{}", compiler.stage, suffix)) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c2c134bfd1d7d..97b28ed9e96c8 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1040,21 +1040,10 @@ impl Step for Compiletest { builder.ensure(compile::Rustc { compiler, target }); } - if builder.no_std(target) == Some(true) { - // the `test` doesn't compile for no-std targets - builder.ensure(compile::Std { compiler, target }); - } else { - builder.ensure(compile::Test { compiler, target }); - } - - if builder.no_std(target) == Some(true) { - // for no_std run-make (e.g., thumb*), - // we need a host compiler which is called by cargo. - builder.ensure(compile::Std { compiler, target: compiler.host }); - } + builder.ensure(compile::Std { compiler, target }); + // ensure that `libproc_macro` is available on the host. + builder.ensure(compile::Std { compiler, target: compiler.host }); - // HACK(eddyb) ensure that `libproc_macro` is available on the host. - builder.ensure(compile::Test { compiler, target: compiler.host }); // Also provide `rust_test_helpers` for the host. builder.ensure(native::TestHelpers { target: compiler.host }); @@ -1399,7 +1388,7 @@ impl Step for DocTest { fn run(self, builder: &Builder<'_>) { let compiler = self.compiler; - builder.ensure(compile::Test { + builder.ensure(compile::Std { compiler, target: compiler.host, }); @@ -1535,8 +1524,7 @@ impl Step for ErrorIndex { ); tool.arg("markdown") .arg(&output) - .env("CFG_BUILD", &builder.config.build) - .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); + .env("CFG_BUILD", &builder.config.build); builder.info(&format!("Testing error-index stage{}", compiler.stage)); let _time = util::timeit(&builder); @@ -1710,8 +1698,7 @@ impl Step for Crate { fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run = run.krate("test"); - for krate in run.builder.in_tree_crates("std") { + for krate in run.builder.in_tree_crates("test") { if !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) { run = run.path(krate.local_path(&builder).to_str().unwrap()); } @@ -1735,14 +1722,9 @@ impl Step for Crate { }); }; - for krate in builder.in_tree_crates("std") { - if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Std, krate); - } - } for krate in builder.in_tree_crates("test") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Test, krate); + make(Mode::Std, krate); } } } @@ -1762,7 +1744,7 @@ impl Step for Crate { let test_kind = self.test_kind; let krate = self.krate; - builder.ensure(compile::Test { compiler, target }); + builder.ensure(compile::Std { compiler, target }); builder.ensure(RemoteCopyLibs { compiler, target }); // If we're not doing a full bootstrap but we're testing a stage2 @@ -1776,9 +1758,6 @@ impl Step for Crate { Mode::Std => { compile::std_cargo(builder, &compiler, target, &mut cargo); } - Mode::Test => { - compile::test_cargo(builder, &compiler, target, &mut cargo); - } Mode::Rustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(builder, &mut cargo); @@ -1832,16 +1811,6 @@ impl Step for Crate { .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 !builder.config.wasm_syscall { - builder.info( - "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"); @@ -1980,7 +1949,7 @@ impl Step for RemoteCopyLibs { return; } - builder.ensure(compile::Test { compiler, target }); + builder.ensure(compile::Std { compiler, target }); builder.info(&format!("REMOTE copy libs to emulator ({})", target)); t!(fs::create_dir_all(builder.out.join("tmp"))); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index df7eb7c455d02..54fe26f18e741 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -577,12 +577,6 @@ impl Step for Cargo { } fn run(self, builder: &Builder<'_>) -> PathBuf { - // Cargo depends on procedural macros, so make sure the host - // libstd/libproc_macro is available. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -650,31 +644,10 @@ macro_rules! tool_extended { tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; - CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", { - // Clippy depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; - Clippy, clippy, "src/tools/clippy", "clippy-driver", { - // Clippy depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; + CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", {}; + Clippy, clippy, "src/tools/clippy", "clippy-driver", {}; Miri, miri, "src/tools/miri", "miri", {}; - CargoMiri, miri, "src/tools/miri", "cargo-miri", { - // Miri depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); - }; + CargoMiri, miri, "src/tools/miri", "cargo-miri", {}; Rls, rls, "src/tools/rls", "rls", { let clippy = builder.ensure(Clippy { compiler: self.compiler, @@ -684,12 +657,6 @@ tool_extended!((self, builder), if clippy.is_some() { self.extra_features.push("clippy".to_owned()); } - // RLS depends on procedural macros, so make sure that's built for - // the compiler itself. - builder.ensure(compile::Test { - compiler: self.compiler, - target: builder.config.build, - }); }; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; ); diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index a1aa18922b5c5..f035a7119188a 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -1,6 +1,3 @@ -// NO-RUSTC-WRAPPER -#![deny(warnings, rust_2018_idioms, unused_lifetimes)] - use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -262,7 +259,7 @@ pub fn native_lib_boilerplate( if !up_to_date(Path::new("build.rs"), ×tamp) || !up_to_date(src_dir, ×tamp) { Ok(NativeLibBoilerplate { src_dir: src_dir.to_path_buf(), - out_dir: out_dir, + out_dir, }) } else { Err(()) diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index ae2ea8ef95a6a..105791194628b 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -104,9 +104,7 @@ ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu -# FIXME: temporarily disable the redox builder, -# see: https://github.com/rust-lang/rust/issues/63160 -# ENV TARGETS=$TARGETS,x86_64-unknown-redox +ENV TARGETS=$TARGETS,x86_64-unknown-redox ENV TARGETS=$TARGETS,thumbv6m-none-eabi ENV TARGETS=$TARGETS,thumbv7m-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabi @@ -132,7 +130,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \ AR_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-ar \ CXX_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-g++ - + ENV RUST_CONFIGURE_ARGS \ --musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ diff --git a/src/ci/docker/dist-various-1/install-mipsel-musl.sh b/src/ci/docker/dist-various-1/install-mipsel-musl.sh index 9ae41218ee4fb..de8c359d16757 100755 --- a/src/ci/docker/dist-various-1/install-mipsel-musl.sh +++ b/src/ci/docker/dist-various-1/install-mipsel-musl.sh @@ -5,7 +5,7 @@ mkdir /usr/local/mipsel-linux-musl # Note that this originally came from: # https://downloads.openwrt.org/snapshots/trunk/malta/generic/ # OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2 -URL="https://rust-lang-ci2.s3.amazonaws.com/libc" +URL="https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc" FILE="OpenWrt-Toolchain-malta-le_gcc-5.3.0_musl-1.1.15.Linux-x86_64.tar.bz2" curl -L "$URL/$FILE" | tar xjf - -C /usr/local/mipsel-linux-musl --strip-components=2 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index c5da1e11915d3..432ca26686c11 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit c5da1e11915d3f28266168baaf55822f7e3fe999 +Subproject commit 432ca26686c11d396eed6a59499f93ce1bf2433c diff --git a/src/doc/nomicon b/src/doc/nomicon index 8a7d05615e5bc..38b9a76bc8b59 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 8a7d05615e5bc0a7fb961b4919c44f5221ee54da +Subproject commit 38b9a76bc8b59ac862663807fc51c9b757337fd6 diff --git a/src/doc/reference b/src/doc/reference index b4b3536839042..d191a0cdd3b92 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b4b3536839042a6743fc76f0d9ad2a812020aeaa +Subproject commit d191a0cdd3b92648e0f1e53b13140a14677cc65b diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index f2c15ba5ee89a..580839d90aacd 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit f2c15ba5ee89ae9469a2cf60494977749901d764 +Subproject commit 580839d90aacd537f0293697096fa8355bc4e673 diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 6f4ba673ff9d4..6e25a3d0d3573 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 6f4ba673ff9d4613e98415bc095347a6a0031e9c +Subproject commit 6e25a3d0d3573eb42b2e2339f1219e969d1b3dee diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d774e465118b3..5eea9c8687900 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -304,3 +304,10 @@ to customize the output: Note that it is invalid to combine the `--json` argument with the `--color` argument, and it is required to combine `--json` with `--error-format=json`. + +## `@path`: load command-line flags from a path + +If you specify `@path` on the command-line, then it will open `path` and read +command line options from it. These options are one per line; a blank line indicates +an empty option. The file can use Unix or Windows style line endings, and must be +encoded as UTF-8. diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index a6e4e166d7bc6..d3dfc3197e2f6 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -208,7 +208,7 @@ error: missing documentation for a function To fix the lint, add documentation to all items. -## single-use-lifetime +## single-use-lifetimes This lint detects lifetimes that are only used once. Some example code that triggers this lint: diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 6e32468b64dee..993fc8412836e 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -311,19 +311,6 @@ When `rustdoc` receives this flag, it will print an extra "Version (version)" in the crate root's docs. You can use this flag to differentiate between different versions of your library's documentation. -### `--linker`: control the linker used for documentation tests - -Using this flag looks like this: - -```bash -$ rustdoc --test src/lib.rs -Z unstable-options --linker foo -$ rustdoc --test README.md -Z unstable-options --linker foo -``` - -When `rustdoc` runs your documentation tests, it needs to compile and link the tests as executables -before running them. This flag can be used to change the linker used on these executables. It's -equivalent to passing `-C linker=foo` to `rustc`. - ### `--sort-modules-by-appearance`: control how items on module pages are sorted Using this flag looks like this: diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index 2a89c0d321d6a..262a53eabe3c7 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -15,113 +15,7 @@ const buffer = fs.readFileSync(process.argv[2]); Error.stackTraceLimit = 20; 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) { - 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 - // one day this is not necessary and something will automatically do this. - fmod: function(x, y) { return x % y; }, - exp2: function(x) { return Math.pow(2, x); }, - exp2f: function(x) { return Math.pow(2, x); }, - ldexp: function(x, y) { return x * Math.pow(2, y); }, - ldexpf: function(x, y) { return x * Math.pow(2, y); }, - sin: Math.sin, - sinf: Math.sin, - cos: Math.cos, - cosf: Math.cos, - log: Math.log, - log2: Math.log2, - log10: Math.log10, - log10f: Math.log10, - - 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; - } - } -}; - -let instance = new WebAssembly.Instance(m, imports); -memory = instance.exports.memory; +let instance = new WebAssembly.Instance(m, {}); try { instance.exports.main(); } catch (e) { diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index a14a3fe9994ab..816a71f255798 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -276,7 +276,7 @@ impl LinkedList { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> Self { + pub const fn new() -> Self { LinkedList { head: None, tail: None, diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 7315963cc8b1d..a4a0fbb194dd4 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1810,7 +1810,7 @@ impl VecDeque { other } - /// Moves all the elements of `other` into `Self`, leaving `other` empty. + /// Moves all the elements of `other` into `self`, leaving `other` empty. /// /// # Panics /// @@ -1847,7 +1847,7 @@ impl VecDeque { /// /// let mut buf = VecDeque::new(); /// buf.extend(1..5); - /// buf.retain(|&x| x%2 == 0); + /// buf.retain(|&x| x % 2 == 0); /// assert_eq!(buf, [2, 4]); /// ``` /// diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index d2798955c46a9..d5dc2d4b8688d 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -291,6 +291,7 @@ use crate::raw_vec::RawVec; /// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve /// [owned slice]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(all(not(bootstrap), not(test)), rustc_diagnostic_item = "vec_type")] pub struct Vec { buf: RawVec, len: usize, diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index cb9feb074dd70..607427a85d67a 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -1012,8 +1012,10 @@ mod impls { impl Ord for $t { #[inline] fn cmp(&self, other: &$t) -> Ordering { - if *self == *other { Equal } - else if *self < *other { Less } + // The order here is important to generate more optimal assembly. + // See for more info. + if *self < *other { Less } + else if *self == *other { Equal } else { Greater } } } diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 641621f492baf..402a7b2c95a46 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -104,22 +104,17 @@ pub const fn identity(x: T) -> T { x } /// If you need to do a costly conversion it is better to implement [`From`] with type /// `&T` or write a custom function. /// -/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects: +/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in few aspects: /// -/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either +/// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either /// a reference or a value. -/// - `Borrow` also requires that `Hash`, `Eq` and `Ord` for borrowed value are +/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for borrowed value are /// equivalent to those of the owned value. For this reason, if you want to -/// borrow only a single field of a struct you can implement `AsRef`, but not `Borrow`. -/// -/// [`Borrow`]: ../../std/borrow/trait.Borrow.html +/// borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`]. /// /// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// /// # Generic Implementations /// /// - `AsRef` auto-dereferences if the inner type is a reference or a mutable @@ -132,9 +127,16 @@ pub const fn identity(x: T) -> T { x } /// converted to the specified type `T`. /// /// For example: By creating a generic function that takes an `AsRef` we express that we -/// want to accept all references that can be converted to `&str` as an argument. -/// Since both [`String`] and `&str` implement `AsRef` we can accept both as input argument. +/// want to accept all references that can be converted to [`&str`] as an argument. +/// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. /// +/// [`Option`]: ../../std/option/enum.Option.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Borrow`]: ../../std/borrow/trait.Borrow.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Ord`]: ../../std/cmp/trait.Ord.html +/// [`&str`]: ../../std/primitive.str.html /// [`String`]: ../../std/string/struct.String.html /// /// ``` diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index bd31d25dd034b..7e35188bc1082 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -518,7 +518,8 @@ impl Display for Arguments<'_> { label="`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`", )] #[doc(alias = "{:?}")] -#[lang = "debug_trait"] +#[cfg_attr(boostrap_stdarch_ignore_this, lang = "debug_trait")] +#[cfg_attr(not(boostrap_stdarch_ignore_this), rustc_diagnostic_item = "debug_trait")] pub trait Debug { /// Formats the value using the given formatter. /// diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 3b2b28217f9b3..6439fa0e0c8b8 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -104,11 +104,19 @@ pub fn spin_loop() { } } -/// A function that is opaque to the optimizer, to allow benchmarks to -/// pretend to use outputs to assist in avoiding dead-code -/// elimination. +/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what +/// `black_box` could do. /// -/// This function is a no-op, and does not even read from `dummy`. +/// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html +/// +/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can +/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined +/// behavior in the calling code. This property makes `black_box` useful for writing code in which +/// certain optimizations are not desired, such as benchmarks. +/// +/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The +/// extent to which it can block optimisations may vary depending upon the platform and code-gen +/// backend used. Programs cannot rely on `black_box` for *correctness* in any way. #[inline] #[unstable(feature = "test", issue = "50297")] #[allow(unreachable_code)] // this makes #[cfg] a bit easier below. diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index a63434abd6c9f..f50781890ab22 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -1309,7 +1309,7 @@ impl DoubleEndedIterator for Peekable where I: DoubleEndedIterator { Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try { match self.peeked.take() { - Some(None) => return Try::from_ok(init), + Some(None) => Try::from_ok(init), Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { @@ -1326,7 +1326,7 @@ impl DoubleEndedIterator for Peekable where I: DoubleEndedIterator { where Fold: FnMut(Acc, Self::Item) -> Acc, { match self.peeked { - Some(None) => return init, + Some(None) => init, Some(Some(v)) => { let acc = self.iter.rfold(init, &mut fold); fold(acc, v) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 6c88a766a2f10..ffaca029a8a78 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -734,7 +734,6 @@ pub(crate) mod builtin { #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] - #[rustc_macro_transparency = "opaque"] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) @@ -747,7 +746,6 @@ pub(crate) mod builtin { #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] - #[rustc_macro_transparency = "opaque"] macro_rules! format_args_nl { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) @@ -1235,7 +1233,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test($item:item) { /* compiler built-in */ } /// Attribute macro applied to a function to turn it into a benchmark test. @@ -1243,7 +1240,6 @@ pub(crate) mod builtin { reason = "`bench` is a part of custom test frameworks which are unstable")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro bench($item:item) { /* compiler built-in */ } /// An implementation detail of the `#[test]` and `#[bench]` macros. @@ -1251,26 +1247,22 @@ pub(crate) mod builtin { reason = "custom test frameworks are an unstable feature")] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } /// Attribute macro applied to a static to register it as a global allocator. #[stable(feature = "global_allocator", since = "1.28.0")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] - #[rustc_macro_transparency = "semitransparent"] pub macro global_allocator($item:item) { /* compiler built-in */ } /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics, libstd_sys_internals)] pub macro RustcDecodable($item:item) { /* compiler built-in */ } /// Unstable implementation detail of the `rustc` compiler, do not use. #[rustc_builtin_macro] - #[cfg_attr(boostrap_stdarch_ignore_this, rustc_macro_transparency = "semitransparent")] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(core_intrinsics)] pub macro RustcEncodable($item:item) { /* compiler built-in */ } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8ff78166a9f2d..22e7573eca65b 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -315,7 +315,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// let abs_difference = (x.recip() - (1.0 / x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d45c04f45afc2..bbe1d04078060 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -327,7 +327,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// let abs_difference = (x.recip() - (1.0 / x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index fd129a306d1c5..59a10ae99bb6a 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -18,6 +18,8 @@ macro_rules! sh_impl_signed { } } } + forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { @@ -41,6 +43,8 @@ macro_rules! sh_impl_signed { } } } + forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { @@ -64,6 +68,8 @@ macro_rules! sh_impl_unsigned { Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32)) } } + forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShlAssign<$f> for Wrapping<$t> { @@ -83,6 +89,8 @@ macro_rules! sh_impl_unsigned { Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32)) } } + forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f, + #[stable(feature = "wrapping_ref_ops", since = "1.39.0")] } #[stable(feature = "op_assign_traits", since = "1.8.0")] impl ShrAssign<$f> for Wrapping<$t> { diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index b9552eaa1a0e5..4a0a2720fe441 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -185,14 +185,6 @@ pub trait FnMut : FnOnce { /// /// # Examples /// -/// ## Calling a by-value closure -/// -/// ``` -/// let x = 5; -/// let square_x = move || x * x; -/// assert_eq!(square_x(), 25); -/// ``` -/// /// ## Using a `FnOnce` parameter /// /// ``` diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index bfbbb15c8d488..931768564ca3c 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -3026,8 +3026,7 @@ macro_rules! len { if size == 0 { // This _cannot_ use `unchecked_sub` because we depend on wrapping // to represent the length of long ZST slice iterators. - let diff = ($self.end as usize).wrapping_sub(start as usize); - diff + ($self.end as usize).wrapping_sub(start as usize) } else { // We know that `start <= end`, so can do better than `offset_from`, // which needs to deal in signed. By setting appropriate flags here diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f20cb7bfbc3bd..5e5b5593fd8a7 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2170,6 +2170,7 @@ impl str { #[inline(always)] #[rustc_const_unstable(feature="const_str_as_bytes")] pub const fn as_bytes(&self) -> &[u8] { + #[repr(C)] union Slices<'a> { str: &'a str, slice: &'a [u8], @@ -3557,7 +3558,7 @@ impl str { /// A string is a sequence of bytes. `start` in this context means the first /// position of that byte string; for a left-to-right language like English or /// Russian, this will be left side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the right side. + /// Arabic or Hebrew, this will be the right side. /// /// # Examples /// @@ -3594,7 +3595,7 @@ impl str { /// A string is a sequence of bytes. `end` in this context means the last /// position of that byte string; for a left-to-right language like English or /// Russian, this will be right side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the left side. + /// Arabic or Hebrew, this will be the left side. /// /// # Examples /// @@ -3761,7 +3762,7 @@ impl str { /// A string is a sequence of bytes. `start` in this context means the first /// position of that byte string; for a left-to-right language like English or /// Russian, this will be left side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the right side. + /// Arabic or Hebrew, this will be the right side. /// /// # Examples /// @@ -3800,7 +3801,7 @@ impl str { /// A string is a sequence of bytes. `end` in this context means the last /// position of that byte string; for a left-to-right language like English or /// Russian, this will be right side, and for right-to-left languages like - /// like Arabic or Hebrew, this will be the left side. + /// Arabic or Hebrew, this will be the left side. /// /// # Examples /// diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index b3d0ee94f0e12..187bdac80019d 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -6,3 +6,6 @@ edition = "2018" [lib] path = "lib.rs" + +[dependencies] +std = { path = "../libstd" } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index c0f7714ca211a..d408fef75153e 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -19,12 +19,15 @@ #![feature(nll)] #![feature(staged_api)] +#![feature(allow_internal_unstable)] #![feature(const_fn)] +#![feature(decl_macro)] #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(optin_builtin_traits)] #![feature(mem_take)] #![feature(non_exhaustive)] +#![feature(rustc_attrs)] #![feature(specialization)] #![recursion_limit="256"] @@ -222,11 +225,10 @@ pub mod token_stream { /// /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. -/// -/// This is a dummy macro, the actual implementation is in `quote::quote`.` #[unstable(feature = "proc_macro_quote", issue = "54722")] -#[macro_export] -macro_rules! quote { () => {} } +#[allow_internal_unstable(proc_macro_def_site)] +#[cfg_attr(not(bootstrap), rustc_builtin_macro)] +pub macro quote ($($t:tt)*) { /* compiler built-in */ } #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index e3d31b78f4a09..144e2d6bac43b 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -57,9 +57,9 @@ macro_rules! quote { } /// Quote a `TokenStream` into a `TokenStream`. -/// This is the actual `quote!()` proc macro. +/// This is the actual implementation of the `quote!()` proc macro. /// -/// It is manually loaded in `CStore::load_macro_untracked`. +/// It is loaded by the compiler in `register_builtin_macros`. #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index e8c3914e695ad..b3a561ef74be7 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -25,6 +25,16 @@ macro_rules! arena_types { [] adt_def: rustc::ty::AdtDef, [] steal_mir: rustc::ty::steal::Steal>, [] mir: rustc::mir::Body<$tcx>, + [] steal_promoted: rustc::ty::steal::Steal< + rustc_data_structures::indexed_vec::IndexVec< + rustc::mir::Promoted, + rustc::mir::Body<$tcx> + > + >, + [] promoted: rustc_data_structures::indexed_vec::IndexVec< + rustc::mir::Promoted, + rustc::mir::Body<$tcx> + >, [] tables: rustc::ty::TypeckTables<$tcx>, [] const_allocs: rustc::mir::interpret::Allocation, [] vtable_method: Option<( @@ -84,6 +94,10 @@ macro_rules! arena_types { rustc::hir::def_id::CrateNum > >, + [few] diagnostic_items: rustc_data_structures::fx::FxHashMap< + syntax::symbol::Symbol, + rustc::hir::def_id::DefId, + >, [few] resolve_lifetimes: rustc::middle::resolve_lifetime::ResolveLifetimes, [decode] generic_predicates: rustc::ty::GenericPredicates<'tcx>, [few] lint_levels: rustc::lint::LintLevelMap, diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index a200a058f4f99..2d09013f675a7 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2231,7 +2231,7 @@ register_diagnostics! { E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions - E0628, // generators cannot have explicit arguments + E0628, // generators cannot have explicit parameters E0631, // type mismatch in closure arguments E0637, // "'_" is not a valid lifetime bound E0657, // `impl Trait` can only capture lifetimes bound at the fn level @@ -2239,7 +2239,7 @@ register_diagnostics! { E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders E0697, // closures cannot be static E0707, // multiple elided lifetimes used in arguments of `async fn` - E0708, // `async` non-`move` closures with arguments are not currently supported + E0708, // `async` non-`move` closures with parameters are not currently supported E0709, // multiple different lifetimes used in arguments of `async fn` E0710, // an unknown tool name found in scoped lint E0711, // a feature has been declared with conflicting stability attributes diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index fa274f831b795..bbde3510e29f9 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -210,8 +210,8 @@ pub trait Visitor<'v> : Sized { } } - fn visit_arg(&mut self, arg: &'v Arg) { - walk_arg(self, arg) + fn visit_param(&mut self, param: &'v Param) { + walk_param(self, param) } /// Visits the top-level item and (optionally) nested items / impl items. See @@ -400,7 +400,7 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_hir_id } pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { - walk_list!(visitor, visit_arg, &body.arguments); + walk_list!(visitor, visit_param, &body.params); visitor.visit_expr(&body.value); } @@ -454,10 +454,10 @@ pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef) visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id) } -pub fn walk_arg<'v, V: Visitor<'v>>(visitor: &mut V, arg: &'v Arg) { - visitor.visit_id(arg.hir_id); - visitor.visit_pat(&arg.pat); - walk_list!(visitor, visit_attribute, &arg.attrs); +pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param) { + visitor.visit_id(param.hir_id); + visitor.visit_pat(¶m.pat); + walk_list!(visitor, visit_attribute, ¶m.attrs); } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7ec3210613727..5e2aebfd3187b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -510,12 +510,12 @@ impl<'a> LoweringContext<'a> { &f.generic_params ); // Mirrors visit::walk_fn_decl - for argument in &f.decl.inputs { + for parameter in &f.decl.inputs { // We don't lower the ids of argument patterns self.with_hir_id_owner(None, |this| { - this.visit_pat(&argument.pat); + this.visit_pat(¶meter.pat); }); - self.visit_ty(&argument.ty) + self.visit_ty(¶meter.ty) } self.visit_fn_ret_ty(&f.decl.output) } @@ -735,7 +735,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn collect_in_band_defs( &mut self, parent_id: DefId, @@ -880,7 +880,7 @@ impl<'a> LoweringContext<'a> { /// /// Presuming that in-band lifetimes are enabled, then /// `self.anonymous_lifetime_mode` will be updated to match the - /// argument while `f` is running (and restored afterwards). + /// parameter while `f` is running (and restored afterwards). fn add_in_band_defs( &mut self, generics: &Generics, @@ -1080,7 +1080,7 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => (true, ImplTraitContext::OpaqueTy(None)), - // We are in the argument position, but not within a dyn type: + // We are in the parameter position, but not within a dyn type: // // fn foo(x: impl Iterator) // @@ -1204,7 +1204,7 @@ impl<'a> LoweringContext<'a> { unsafety: this.lower_unsafety(f.unsafety), abi: f.abi, decl: this.lower_fn_decl(&f.decl, None, false, None), - arg_names: this.lower_fn_args_to_names(&f.decl), + param_names: this.lower_fn_params_to_names(&f.decl), })) }, ) @@ -2093,12 +2093,12 @@ impl<'a> LoweringContext<'a> { } } - fn lower_fn_args_to_names(&mut self, decl: &FnDecl) -> hir::HirVec { + fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> hir::HirVec { decl.inputs .iter() - .map(|arg| match arg.pat.node { + .map(|param| match param.pat.node { PatKind::Ident(_, ident, _) => ident, - _ => Ident::new(kw::Invalid, arg.pat.span), + _ => Ident::new(kw::Invalid, param.pat.span), }) .collect() } @@ -2136,11 +2136,11 @@ impl<'a> LoweringContext<'a> { let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| { decl.inputs .iter() - .map(|arg| { + .map(|param| { if let Some((_, ibty)) = &mut in_band_ty_params { - this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty)) + this.lower_ty_direct(¶m.ty, ImplTraitContext::Universal(ibty)) } else { - this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed()) + this.lower_ty_direct(¶m.ty, ImplTraitContext::disallowed()) } }) .collect::>() @@ -2205,7 +2205,7 @@ impl<'a> LoweringContext<'a> { // // type OpaqueTy = impl Future; // - // `inputs`: lowered types of arguments to the function (used to collect lifetimes) + // `inputs`: lowered types of parameters to the function (used to collect lifetimes) // `output`: unlowered output type (`T` in `-> T`) // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index ff0c44a23874b..bd217831faabf 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -724,7 +724,7 @@ impl LoweringContext<'_> { self.sess, fn_decl_span, E0628, - "generators cannot have explicit arguments" + "generators cannot have explicit parameters" ); self.sess.abort_if_errors(); } @@ -775,7 +775,7 @@ impl LoweringContext<'_> { this.sess, fn_decl_span, E0708, - "`async` non-`move` closures with arguments are not currently supported", + "`async` non-`move` closures with parameters are not currently supported", ) .help( "consider using `let` statements to manually capture \ diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 4f9a9ed5673c7..4e432f4981d23 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -720,7 +720,7 @@ impl LoweringContext<'_> { ( // Disallow impl Trait in foreign items this.lower_fn_decl(fdec, None, false, None), - this.lower_fn_args_to_names(fdec), + this.lower_fn_params_to_names(fdec), ) }, ); @@ -827,7 +827,7 @@ impl LoweringContext<'_> { ), ), TraitItemKind::Method(ref sig, None) => { - let names = self.lower_fn_args_to_names(&sig.decl); + let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = self.lower_method_sig( &i.generics, sig, @@ -1028,10 +1028,10 @@ impl LoweringContext<'_> { } } - fn record_body(&mut self, arguments: HirVec, value: hir::Expr) -> hir::BodyId { + fn record_body(&mut self, params: HirVec, value: hir::Expr) -> hir::BodyId { let body = hir::Body { generator_kind: self.generator_kind, - arguments, + params, value, }; let id = body.id(); @@ -1041,21 +1041,21 @@ impl LoweringContext<'_> { fn lower_body( &mut self, - f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), + f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec, hir::Expr), ) -> hir::BodyId { let prev_gen_kind = self.generator_kind.take(); - let (arguments, result) = f(self); - let body_id = self.record_body(arguments, result); + let (parameters, result) = f(self); + let body_id = self.record_body(parameters, result); self.generator_kind = prev_gen_kind; body_id } - fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { - hir::Arg { - attrs: self.lower_attrs(&arg.attrs), - hir_id: self.lower_node_id(arg.id), - pat: self.lower_pat(&arg.pat), - span: arg.span, + fn lower_param(&mut self, param: &Param) -> hir::Param { + hir::Param { + attrs: self.lower_attrs(¶m.attrs), + hir_id: self.lower_node_id(param.id), + pat: self.lower_pat(¶m.pat), + span: param.span, } } @@ -1065,7 +1065,7 @@ impl LoweringContext<'_> { body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, ) -> hir::BodyId { self.lower_body(|this| ( - decl.inputs.iter().map(|x| this.lower_arg(x)).collect(), + decl.inputs.iter().map(|x| this.lower_param(x)).collect(), body(this), )) } @@ -1093,10 +1093,10 @@ impl LoweringContext<'_> { }; self.lower_body(|this| { - let mut arguments: Vec = Vec::new(); + let mut parameters: Vec = Vec::new(); let mut statements: Vec = Vec::new(); - // Async function arguments are lowered into the closure body so that they are + // Async function parameters are lowered into the closure body so that they are // captured and so that the drop order matches the equivalent non-async functions. // // from: @@ -1121,13 +1121,13 @@ impl LoweringContext<'_> { // // If `` is a simple ident, then it is lowered to a single // `let = ;` statement as an optimization. - for (index, argument) in decl.inputs.iter().enumerate() { - let argument = this.lower_arg(argument); - let span = argument.pat.span; + for (index, parameter) in decl.inputs.iter().enumerate() { + let parameter = this.lower_param(parameter); + let span = parameter.pat.span; // Check if this is a binding pattern, if so, we can optimize and avoid adding a - // `let = __argN;` statement. In this case, we do not rename the argument. - let (ident, is_simple_argument) = match argument.pat.node { + // `let = __argN;` statement. In this case, we do not rename the parameter. + let (ident, is_simple_parameter) = match parameter.pat.node { hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) => (ident, true), _ => { @@ -1142,32 +1142,32 @@ impl LoweringContext<'_> { let desugared_span = this.mark_span_with_reason(DesugaringKind::Async, span, None); - // Construct an argument representing `__argN: ` to replace the argument of the + // Construct a parameter representing `__argN: ` to replace the parameter of the // async function. // - // If this is the simple case, this argument will end up being the same as the - // original argument, but with a different pattern id. + // If this is the simple case, this parameter will end up being the same as the + // original parameter, but with a different pattern id. let mut stmt_attrs = ThinVec::new(); - stmt_attrs.extend(argument.attrs.iter().cloned()); - let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident); - let new_argument = hir::Arg { - attrs: argument.attrs, - hir_id: argument.hir_id, - pat: new_argument_pat, - span: argument.span, + stmt_attrs.extend(parameter.attrs.iter().cloned()); + let (new_parameter_pat, new_parameter_id) = this.pat_ident(desugared_span, ident); + let new_parameter = hir::Param { + attrs: parameter.attrs, + hir_id: parameter.hir_id, + pat: new_parameter_pat, + span: parameter.span, }; - if is_simple_argument { + if is_simple_parameter { // If this is the simple case, then we only insert one statement that is // `let = ;`. We re-use the original argument's pattern so that // `HirId`s are densely assigned. - let expr = this.expr_ident(desugared_span, ident, new_argument_id); + let expr = this.expr_ident(desugared_span, ident, new_parameter_id); let stmt = this.stmt_let_pat( stmt_attrs, desugared_span, Some(P(expr)), - argument.pat, + parameter.pat, hir::LocalSource::AsyncFn ); statements.push(stmt); @@ -1179,7 +1179,7 @@ impl LoweringContext<'_> { // let = __argN; // ``` // - // The first statement moves the argument into the closure and thus ensures + // The first statement moves the parameter into the closure and thus ensures // that the drop order is correct. // // The second statement creates the bindings that the user wrote. @@ -1189,7 +1189,7 @@ impl LoweringContext<'_> { // statement. let (move_pat, move_id) = this.pat_ident_binding_mode( desugared_span, ident, hir::BindingAnnotation::Mutable); - let move_expr = this.expr_ident(desugared_span, ident, new_argument_id); + let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); let move_stmt = this.stmt_let_pat( ThinVec::new(), desugared_span, @@ -1199,13 +1199,13 @@ impl LoweringContext<'_> { ); // Construct the `let = __argN;` statement. We re-use the original - // argument's pattern so that `HirId`s are densely assigned. + // parameter's pattern so that `HirId`s are densely assigned. let pattern_expr = this.expr_ident(desugared_span, ident, move_id); let pattern_stmt = this.stmt_let_pat( stmt_attrs, desugared_span, Some(P(pattern_expr)), - argument.pat, + parameter.pat, hir::LocalSource::AsyncFn ); @@ -1213,7 +1213,7 @@ impl LoweringContext<'_> { statements.push(pattern_stmt); }; - arguments.push(new_argument); + parameters.push(new_parameter); } let async_expr = this.make_async_expr( @@ -1222,7 +1222,7 @@ impl LoweringContext<'_> { let body = this.lower_block_with_stmts(body, false, statements); this.expr_block(body, ThinVec::new()) }); - (HirVec::from(arguments), this.expr(body.span, async_expr, ThinVec::new())) + (HirVec::from(parameters), this.expr(body.span, async_expr, ThinVec::new())) }) } diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index effe2c0cc6a76..773bb8dde0690 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -363,11 +363,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.currently_in_body = prev_in_body; } - fn visit_arg(&mut self, arg: &'hir Arg) { - let node = Node::Arg(arg); - self.insert(arg.pat.span, arg.hir_id, node); - self.with_parent(arg.hir_id, |this| { - intravisit::walk_arg(this, arg); + fn visit_param(&mut self, param: &'hir Param) { + let node = Node::Param(param); + self.insert(param.pat.span, param.hir_id, node); + self.with_parent(param.hir_id, |this| { + intravisit::walk_param(this, param); }); } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index d725afa405212..17bcb1d085968 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -154,7 +154,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { }); } - fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &'a Variant) { let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.as_interned_str()), v.span); @@ -162,12 +162,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { if let Some(ctor_hir_id) = v.data.ctor_id() { this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); } - visit::walk_variant(this, v, g, item_id) + visit::walk_variant(this, v) }); } - fn visit_variant_data(&mut self, data: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, data: &'a VariantData) { for (index, field) in data.fields().iter().enumerate() { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| sym::integer(index)); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 7292428ec378c..eb8be6e6e3cbc 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -360,7 +360,7 @@ impl<'hir> Map<'hir> { Node::Pat(_) | Node::Binding(_) | Node::Local(_) | - Node::Arg(_) | + Node::Param(_) | Node::Arm(_) | Node::Lifetime(_) | Node::Visibility(_) | @@ -514,8 +514,7 @@ impl<'hir> Map<'hir> { &self.forest.krate.attrs } - pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, HirId) - { + pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, HirId) { let hir_id = self.as_local_hir_id(module).unwrap(); self.read(hir_id); match self.find_entry(hir_id).unwrap().node { @@ -525,7 +524,7 @@ impl<'hir> Map<'hir> { .. }) => (m, span, hir_id), Node::Crate => (&self.forest.krate.module, self.forest.krate.span, hir_id), - _ => panic!("not a module") + node => panic!("not a module: {:?}", node), } } @@ -679,6 +678,16 @@ impl<'hir> Map<'hir> { } } + /// Wether `hir_id` corresponds to a `mod` or a crate. + pub fn is_hir_id_module(&self, hir_id: HirId) -> bool { + match self.lookup(hir_id) { + Some(Entry { node: Node::Item(Item { node: ItemKind::Mod(_), .. }), .. }) | + Some(Entry { node: Node::Crate, .. }) => true, + _ => false, + } + } + + /// If there is some error when walking the parents (e.g., a node does not /// have a parent in the map or a node can't be found), then we return the /// last good `HirId` we found. Note that reaching the crate root (`id == 0`), @@ -955,7 +964,7 @@ impl<'hir> Map<'hir> { pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] { self.read(id); // reveals attributes on the node let attrs = match self.find_entry(id).map(|entry| entry.node) { - Some(Node::Arg(a)) => Some(&a.attrs[..]), + Some(Node::Param(a)) => Some(&a.attrs[..]), Some(Node::Local(l)) => Some(&l.attrs[..]), Some(Node::Item(i)) => Some(&i.attrs[..]), Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]), @@ -1019,7 +1028,7 @@ impl<'hir> Map<'hir> { pub fn span(&self, hir_id: HirId) -> Span { self.read(hir_id); // reveals span from node match self.find_entry(hir_id).map(|entry| entry.node) { - Some(Node::Arg(arg)) => arg.span, + Some(Node::Param(param)) => param.span, Some(Node::Item(item)) => item.span, Some(Node::ForeignItem(foreign_item)) => foreign_item.span, Some(Node::TraitItem(trait_method)) => trait_method.span, @@ -1214,7 +1223,7 @@ impl<'hir> print::PpAnn for Map<'hir> { Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat) } } } @@ -1222,7 +1231,7 @@ impl<'hir> print::PpAnn for Map<'hir> { impl<'a> print::State<'a> { pub fn print_node(&mut self, node: Node<'_>) { match node { - Node::Arg(a) => self.print_arg(&a), + Node::Param(a) => self.print_param(&a), Node::Item(a) => self.print_item(&a), Node::ForeignItem(a) => self.print_foreign_item(&a), Node::TraitItem(a) => self.print_trait_item(a), @@ -1364,8 +1373,8 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { Some(Node::Pat(_)) => { format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } - Some(Node::Arg(_)) => { - format!("arg {}{}", map.hir_to_pretty_string(id), id_str) + Some(Node::Param(_)) => { + format!("param {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Arm(_)) => { format!("arm {}{}", map.hir_to_pretty_string(id), id_str) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 983048188527f..d2c45a5af8598 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1030,7 +1030,7 @@ pub enum Mutability { } impl Mutability { - /// Returns `MutMutable` only if both arguments are mutable. + /// Returns `MutMutable` only if both `self` and `other` are mutable. pub fn and(self, other: Self) -> Self { match self { MutMutable => other, @@ -1324,7 +1324,7 @@ pub struct BodyId { /// /// Here, the `Body` associated with `foo()` would contain: /// -/// - an `arguments` array containing the `(x, y)` pattern +/// - an `params` array containing the `(x, y)` pattern /// - a `value` containing the `x + y` expression (maybe wrapped in a block) /// - `generator_kind` would be `None` /// @@ -1332,7 +1332,7 @@ pub struct BodyId { /// map using `body_owner_def_id()`. #[derive(RustcEncodable, RustcDecodable, Debug)] pub struct Body { - pub arguments: HirVec, + pub params: HirVec, pub value: Expr, pub generator_kind: Option, } @@ -1644,7 +1644,7 @@ pub enum LocalSource { /// A desugared `for _ in _ { .. }` loop. ForLoopDesugar, /// When lowering async functions, we create locals within the `async move` so that - /// all arguments are dropped after the future is polled. + /// all parameters are dropped after the future is polled. /// /// ```ignore (pseudo-Rust) /// async fn foo( @ x: Type) { @@ -1940,7 +1940,7 @@ pub struct BareFnTy { pub abi: Abi, pub generic_params: HirVec, pub decl: P, - pub arg_names: HirVec, + pub param_names: HirVec, } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] @@ -2027,9 +2027,9 @@ pub struct InlineAsm { pub dialect: AsmDialect, } -/// Represents an argument in a function header. +/// Represents a parameter in a function header. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] -pub struct Arg { +pub struct Param { pub attrs: HirVec, pub hir_id: HirId, pub pat: P, @@ -2039,9 +2039,9 @@ pub struct Arg { /// Represents the header (not the body) of a function declaration. #[derive(RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct FnDecl { - /// The types of the function's arguments. + /// The types of the function's parameters. /// - /// Additional argument data is stored in the function's [body](Body::arguments). + /// Additional argument data is stored in the function's [body](Body::parameters). pub inputs: HirVec, pub output: FunctionRetTy, pub c_variadic: bool, @@ -2721,7 +2721,7 @@ impl CodegenFnAttrs { #[derive(Copy, Clone, Debug)] pub enum Node<'hir> { - Arg(&'hir Arg), + Param(&'hir Param), Item(&'hir Item), ForeignItem(&'hir ForeignItem), TraitItem(&'hir TraitItem), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 632a13f9183b2..21cc72efee4a3 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -33,7 +33,7 @@ pub enum Nested { TraitItem(hir::TraitItemId), ImplItem(hir::ImplItemId), Body(hir::BodyId), - BodyArgPat(hir::BodyId, usize) + BodyParamPat(hir::BodyId, usize) } pub trait PpAnn { @@ -62,7 +62,7 @@ impl PpAnn for hir::Crate { Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat) + Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat) } } } @@ -318,7 +318,7 @@ impl<'a> State<'a> { } hir::TyKind::BareFn(ref f) => { self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params, - &f.arg_names[..]); + &f.param_names[..]); } hir::TyKind::Def(..) => {}, hir::TyKind::Path(ref qpath) => { @@ -1290,7 +1290,7 @@ impl<'a> State<'a> { hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { self.print_capture_clause(capture_clause); - self.print_closure_args(&decl, body); + self.print_closure_params(&decl, body); self.s.space(); // this is a bare expression @@ -1775,7 +1775,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - pub fn print_arg(&mut self, arg: &hir::Arg) { + pub fn print_param(&mut self, arg: &hir::Param) { self.print_outer_attributes(&arg.attrs); self.print_pat(&arg.pat); } @@ -1864,7 +1864,7 @@ impl<'a> State<'a> { s.s.word(":"); s.s.space(); } else if let Some(body_id) = body_id { - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); s.s.word(":"); s.s.space(); } @@ -1881,13 +1881,13 @@ impl<'a> State<'a> { self.print_where_clause(&generics.where_clause) } - fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { + fn print_closure_params(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) { self.s.word("|"); let mut i = 0; self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); - s.ann.nested(s, Nested::BodyArgPat(body_id, i)); + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); i += 1; if let hir::TyKind::Infer = ty.node { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 60b338010b0db..fb981d961129f 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -331,13 +331,13 @@ impl<'a> HashStable> for hir::Body { hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Body { - arguments, + params, value, generator_kind, } = self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| { - arguments.hash_stable(hcx, hasher); + params.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher); generator_kind.hash_stable(hcx, hasher); }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 7003f71c8baa0..05e2c7854b49c 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -402,7 +402,6 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnData { parent -> _, call_site, def_site, - default_transparency, allow_internal_unstable, allow_internal_unsafe, local_inner_macros, diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 0ddc9211f9811..be7669fcad875 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -168,25 +168,21 @@ impl<'a> HashStable> for mir::interpret::AllocId { } } -// Allocations treat their relocations specially -impl<'a> HashStable> for mir::interpret::Allocation { +// `Relocations` with default type parameters is a sorted map. +impl<'a, Tag> HashStable> +for mir::interpret::Relocations +where + Tag: HashStable>, +{ fn hash_stable( &self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { - let mir::interpret::Allocation { - bytes, relocations, undef_mask, align, mutability, - extra: _, - } = self; - bytes.hash_stable(hcx, hasher); - relocations.len().hash_stable(hcx, hasher); - for reloc in relocations.iter() { + self.len().hash_stable(hcx, hasher); + for reloc in self.iter() { reloc.hash_stable(hcx, hasher); } - undef_mask.hash_stable(hcx, hasher); - align.hash_stable(hcx, hasher); - mutability.hash_stable(hcx, hasher); } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 84687b8cab5c0..e684ccfeeb7ed 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1636,6 +1636,9 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { Error0644("closure/generator type that references itself") } + TypeError::IntrinsicCast => { + Error0308("cannot coerce intrinsics to function pointers") + } _ => Error0308("mismatched types"), }, } @@ -1650,7 +1653,7 @@ impl<'tcx> ObligationCause<'tcx> { hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", _ => "match arms have compatible types", }, - IfExpression { .. } => "if and else have compatible types", + IfExpression { .. } => "if and else have incompatible types", IfExpressionWithNoElse => "if missing an else returns ()", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`start` function has the correct type", diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 3267505708b81..7068fe3601a62 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -78,12 +78,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { } fn visit_body(&mut self, body: &'tcx Body) { - for argument in &body.arguments { + for param in &body.params { if let (None, Some(ty)) = ( self.found_arg_pattern, - self.node_matches_type(argument.hir_id), + self.node_matches_type(param.hir_id), ) { - self.found_arg_pattern = Some(&*argument.pat); + self.found_arg_pattern = Some(&*param.pat); self.found_ty = Some(ty); } } @@ -150,12 +150,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, highlight: Option, - ) -> String { + ) -> (String, Option) { if let ty::Infer(ty::TyVar(ty_vid)) = ty.sty { let ty_vars = self.type_variables.borrow(); - if let TypeVariableOriginKind::TypeParameterDefinition(name) = - ty_vars.var_origin(ty_vid).kind { - return name.to_string(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { + return (name.to_string(), Some(var_origin.span)); } } @@ -165,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - s + (s, None) } pub fn need_type_info_err( @@ -175,7 +175,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let name = self.extract_type_name(&ty, None); + let (name, name_sp) = self.extract_type_name(&ty, None); let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); let ty_to_string = |ty: Ty<'tcx>| -> String { @@ -200,6 +200,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { pattern.span + } else if let Some(span) = name_sp { + // `span` here lets us point at `sum` instead of the entire right hand side expr: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | ^^^ cannot infer type for `S` + span } else { span }; @@ -325,6 +333,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; err.span_label(pattern.span, msg); } + // Instead of the following: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | --^^^--------- cannot infer type for `S` + // | + // = note: type must be known at this point + // We want: + // error[E0282]: type annotations needed + // --> file2.rs:3:15 + // | + // 3 | let _ = x.sum() as f64; + // | ^^^ cannot infer type for `S` + // | + // = note: type must be known at this point + let span = name_sp.unwrap_or(span); if !err.span.span_labels().iter().any(|span_label| { span_label.label.is_some() && span_label.span == span }) && local_visitor.found_arg_pattern.is_none() @@ -342,7 +367,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let name = self.extract_type_name(&ty, None); + let name = self.extract_type_name(&ty, None).0; let mut err = struct_span_err!( self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind, ); diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 6bd2c04d51281..979815fa7f184 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -2,7 +2,7 @@ //! where both the regions are anonymous. use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::nice_region_error::util::AnonymousArgInfo; +use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::util::common::ErrorReported; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { @@ -59,13 +59,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let ty_sub = self.find_anon_type(sub, &bregion_sub)?; debug!( - "try_report_anon_anon_conflict: found_arg1={:?} sup={:?} br1={:?}", + "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", ty_sub, sup, bregion_sup ); debug!( - "try_report_anon_anon_conflict: found_arg2={:?} sub={:?} br2={:?}", + "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}", ty_sup, sub, bregion_sub @@ -74,24 +74,24 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let (ty_sup, ty_fndecl_sup) = ty_sup; let (ty_sub, ty_fndecl_sub) = ty_sub; - let AnonymousArgInfo { - arg: anon_arg_sup, .. - } = self.find_arg_with_region(sup, sup)?; - let AnonymousArgInfo { - arg: anon_arg_sub, .. - } = self.find_arg_with_region(sub, sub)?; + let AnonymousParamInfo { + param: anon_param_sup, .. + } = self.find_param_with_region(sup, sup)?; + let AnonymousParamInfo { + param: anon_param_sub, .. + } = self.find_param_with_region(sub, sub)?; let sup_is_ret_type = self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup); let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_arg_sup.pat.simple_ident() { + let span_label_var1 = match anon_param_sup.pat.simple_ident() { Some(simple_ident) => format!(" from `{}`", simple_ident), None => String::new(), }; - let span_label_var2 = match anon_arg_sub.pat.simple_ident() { + let span_label_var2 = match anon_param_sub.pat.simple_ident() { Some(simple_ident) => format!(" into `{}`", simple_ident), None => String::new(), }; diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 51bee49b70fc0..604115cfc3711 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -6,7 +6,7 @@ use crate::ty; use errors::{Applicability, DiagnosticBuilder}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// When given a `ConcreteFailure` for a function with arguments containing a named region and + /// When given a `ConcreteFailure` for a function with parameters containing a named region and /// an anonymous region, emit an descriptive diagnostic error. pub(super) fn try_report_named_anon_conflict(&self) -> Option> { let (span, sub, sup) = self.get_regions(); @@ -24,23 +24,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // only introduced anonymous regions in parameters) as well as a // version new_ty of its type where the anonymous region is replaced // with the named one.//scope_def_id - let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub) + let (named, anon, anon_param_info, region_info) = if self.is_named_region(sub) && self.tcx().is_suitable_region(sup).is_some() - && self.find_arg_with_region(sup, sub).is_some() + && self.find_param_with_region(sup, sub).is_some() { ( sub, sup, - self.find_arg_with_region(sup, sub).unwrap(), + self.find_param_with_region(sup, sub).unwrap(), self.tcx().is_suitable_region(sup).unwrap(), ) } else if self.is_named_region(sup) && self.tcx().is_suitable_region(sub).is_some() - && self.find_arg_with_region(sub, sup).is_some() + && self.find_param_with_region(sub, sup).is_some() { ( sup, sub, - self.find_arg_with_region(sub, sup).unwrap(), + self.find_param_with_region(sub, sup).unwrap(), self.tcx().is_suitable_region(sub).unwrap(), ) } else { @@ -49,20 +49,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: named = {:?}", named); debug!( - "try_report_named_anon_conflict: anon_arg_info = {:?}", - anon_arg_info + "try_report_named_anon_conflict: anon_param_info = {:?}", + anon_param_info ); debug!( "try_report_named_anon_conflict: region_info = {:?}", region_info ); - let (arg, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( - anon_arg_info.arg, - anon_arg_info.arg_ty, - anon_arg_info.arg_ty_span, - anon_arg_info.bound_region, - anon_arg_info.is_first, + let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( + anon_param_info.param, + anon_param_info.param_ty, + anon_param_info.param_ty_span, + anon_param_info.bound_region, + anon_param_info.is_first, region_info.def_id, region_info.is_impl_item, ); @@ -95,7 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - let (error_var, span_label_var) = match arg.pat.simple_ident() { + let (error_var, span_label_var) = match param.pat.simple_ident() { Some(simple_ident) => ( format!("the type of `{}`", simple_ident), format!("the type of `{}`", simple_ident), diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index f33f917392653..668c99da0034f 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -10,37 +10,37 @@ use syntax_pos::Span; // The struct contains the information about the anonymous region // we are searching for. #[derive(Debug)] -pub(super) struct AnonymousArgInfo<'tcx> { - // the argument corresponding to the anonymous region - pub arg: &'tcx hir::Arg, - // the type corresponding to the anonymopus region argument - pub arg_ty: Ty<'tcx>, +pub(super) struct AnonymousParamInfo<'tcx> { + // the parameter corresponding to the anonymous region + pub param: &'tcx hir::Param, + // the type corresponding to the anonymopus region parameter + pub param_ty: Ty<'tcx>, // the ty::BoundRegion corresponding to the anonymous region pub bound_region: ty::BoundRegion, - // arg_ty_span contains span of argument type - pub arg_ty_span : Span, + // param_ty_span contains span of parameter type + pub param_ty_span : Span, // corresponds to id the argument is the first parameter // in the declaration pub is_first: bool, } impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - // This method walks the Type of the function body arguments using + // This method walks the Type of the function body parameters using // `fold_regions()` function and returns the - // &hir::Arg of the function argument corresponding to the anonymous + // &hir::Param of the function parameter corresponding to the anonymous // region and the Ty corresponding to the named region. // Currently only the case where the function declaration consists of // one named region and one anonymous region is handled. // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` - // Here, we would return the hir::Arg for y, we return the type &'a + // Here, we would return the hir::Param for y, we return the type &'a // i32, which is the type of y but with the anonymous region replaced // with 'a, the corresponding bound region and is_first which is true if - // the hir::Arg is the first argument in the function declaration. - pub(super) fn find_arg_with_region( + // the hir::Param is the first parameter in the function declaration. + pub(super) fn find_param_with_region( &self, anon_region: Region<'tcx>, replace_region: Region<'tcx>, - ) -> Option> { + ) -> Option> { let (id, bound_region) = match *anon_region { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), ty::ReEarlyBound(ebr) => ( @@ -57,16 +57,16 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let owner_id = hir.body_owner(body_id); let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); if let Some(tables) = self.tables { - body.arguments + body.params .iter() .enumerate() - .filter_map(|(index, arg)| { + .filter_map(|(index, param)| { // May return None; sometimes the tables are not yet populated. let ty_hir_id = fn_decl.inputs[index].hir_id; - let arg_ty_span = hir.span(ty_hir_id); - let ty = tables.node_type_opt(arg.hir_id)?; + let param_ty_span = hir.span(ty_hir_id); + let ty = tables.node_type_opt(param.hir_id)?; let mut found_anon_region = false; - let new_arg_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { + let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { if *r == *anon_region { found_anon_region = true; replace_region @@ -76,10 +76,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }); if found_anon_region { let is_first = index == 0; - Some(AnonymousArgInfo { - arg: arg, - arg_ty: new_arg_ty, - arg_ty_span : arg_ty_span, + Some(AnonymousParamInfo { + param: param, + param_ty: new_param_ty, + param_ty_span : param_ty_span, bound_region: bound_region, is_first: is_first, }) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e1d77a97c1160..cc28567e2fc9e 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1460,7 +1460,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem); + let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); // this can get called from typeck (by euv), and moves_by_default // rightly refuses to work with inference variables, but diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8d4cd51e4608c..368f5bb64fe6c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -62,6 +62,7 @@ #![feature(log_syntax)] #![feature(mem_take)] #![feature(associated_type_bounds)] +#![feature(rustc_attrs)] #![recursion_limit="512"] @@ -109,6 +110,7 @@ pub mod middle { pub mod cstore; pub mod dead; pub mod dependency_format; + pub mod diagnostic_items; pub mod entry; pub mod exported_symbols; pub mod free_region; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 6801fa8d8dbe5..affda256322a4 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -966,10 +966,10 @@ for LateContextAndPass<'a, 'tcx, T> { self.context.tables = old_tables; } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |cx| { - lint_callback!(cx, check_arg, arg); - hir_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |cx| { + lint_callback!(cx, check_param, param); + hir_visit::walk_param(cx, param); }); } @@ -1040,13 +1040,13 @@ for LateContextAndPass<'a, 'tcx, T> { fn visit_variant_data(&mut self, s: &'tcx hir::VariantData, - name: ast::Name, - g: &'tcx hir::Generics, - item_id: hir::HirId, + _: ast::Name, + _: &'tcx hir::Generics, + _: hir::HirId, _: Span) { - lint_callback!(self, check_struct_def, s, name, g, item_id); + lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); - lint_callback!(self, check_struct_def_post, s, name, g, item_id); + lint_callback!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { @@ -1061,9 +1061,9 @@ for LateContextAndPass<'a, 'tcx, T> { g: &'tcx hir::Generics, item_id: hir::HirId) { self.with_lint_attrs(v.id, &v.attrs, |cx| { - lint_callback!(cx, check_variant, v, g); + lint_callback!(cx, check_variant, v); hir_visit::walk_variant(cx, v, g, item_id); - lint_callback!(cx, check_variant_post, v, g); + lint_callback!(cx, check_variant_post, v); }) } @@ -1163,10 +1163,10 @@ for LateContextAndPass<'a, 'tcx, T> { } impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { - fn visit_arg(&mut self, arg: &'a ast::Arg) { - self.with_lint_attrs(arg.id, &arg.attrs, |cx| { - run_early_pass!(cx, check_arg, arg); - ast_visit::walk_arg(cx, arg); + fn visit_param(&mut self, param: &'a ast::Param) { + self.with_lint_attrs(param.id, ¶m.attrs, |cx| { + run_early_pass!(cx, check_param, param); + ast_visit::walk_param(cx, param); }); } @@ -1214,18 +1214,13 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_fn_post, fk, decl, span, id); } - fn visit_variant_data(&mut self, - s: &'a ast::VariantData, - ident: ast::Ident, - g: &'a ast::Generics, - item_id: ast::NodeId, - _: Span) { - run_early_pass!(self, check_struct_def, s, ident, g, item_id); + fn visit_variant_data(&mut self, s: &'a ast::VariantData) { + run_early_pass!(self, check_struct_def, s); if let Some(ctor_hir_id) = s.ctor_id() { self.check_id(ctor_hir_id); } ast_visit::walk_struct_def(self, s); - run_early_pass!(self, check_struct_def_post, s, ident, g, item_id); + run_early_pass!(self, check_struct_def_post, s); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { @@ -1235,11 +1230,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> }) } - fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(item_id, &v.attrs, |cx| { - run_early_pass!(cx, check_variant, v, g); - ast_visit::walk_variant(cx, v, g, item_id); - run_early_pass!(cx, check_variant_post, v, g); + fn visit_variant(&mut self, v: &'a ast::Variant) { + self.with_lint_attrs(v.id, &v.attrs, |cx| { + run_early_pass!(cx, check_variant, v); + ast_visit::walk_variant(cx, v); + run_early_pass!(cx, check_variant_post, v); }) } diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index be73b305e2c50..13834eaf40f57 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -159,29 +159,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind { } fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool { - if segment.ident.name == sym::TyKind { - if let Some(res) = segment.res { - if let Some(did) = res.opt_def_id() { - return cx.match_def_path(did, TYKIND_PATH); - } + if let Some(res) = segment.res { + if let Some(did) = res.opt_def_id() { + return cx.tcx.is_diagnostic_item(sym::TyKind, did); } } false } -const TYKIND_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::sty, sym::TyKind]; -const TY_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::Ty]; -const TYCTXT_PATH: &[Symbol] = &[sym::rustc, sym::ty, sym::context, sym::TyCtxt]; - fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty) -> Option { match &ty.node { TyKind::Path(qpath) => { if let QPath::Resolved(_, path) = qpath { let did = path.res.opt_def_id()?; - if cx.match_def_path(did, TY_PATH) { + if cx.tcx.is_diagnostic_item(sym::Ty, did) { return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.match_def_path(did, TYCTXT_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2b58627cdea56..a3518b2b478ad 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -206,7 +206,7 @@ macro_rules! declare_lint_pass { macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( $macro!($args, [$hir], [ - fn check_arg(a: &$hir hir::Arg); + fn check_param(a: &$hir hir::Param); fn check_body(a: &$hir hir::Body); fn check_body_post(a: &$hir hir::Body); fn check_name(a: Span, b: ast::Name); @@ -248,21 +248,11 @@ macro_rules! late_lint_methods { fn check_trait_item_post(a: &$hir hir::TraitItem); fn check_impl_item(a: &$hir hir::ImplItem); fn check_impl_item_post(a: &$hir hir::ImplItem); - fn check_struct_def( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); - fn check_struct_def_post( - a: &$hir hir::VariantData, - b: ast::Name, - c: &$hir hir::Generics, - d: hir::HirId - ); + fn check_struct_def(a: &$hir hir::VariantData); + fn check_struct_def_post(a: &$hir hir::VariantData); fn check_struct_field(a: &$hir hir::StructField); - fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); - fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant(a: &$hir hir::Variant); + fn check_variant_post(a: &$hir hir::Variant); fn check_lifetime(a: &$hir hir::Lifetime); fn check_path(a: &$hir hir::Path, b: hir::HirId); fn check_attribute(a: &$hir ast::Attribute); @@ -359,7 +349,7 @@ macro_rules! declare_combined_late_lint_pass { macro_rules! early_lint_methods { ($macro:path, $args:tt) => ( $macro!($args, [ - fn check_arg(a: &ast::Arg); + fn check_param(a: &ast::Param); fn check_ident(a: ast::Ident); fn check_crate(a: &ast::Crate); fn check_crate_post(a: &ast::Crate); @@ -395,21 +385,11 @@ macro_rules! early_lint_methods { fn check_trait_item_post(a: &ast::TraitItem); fn check_impl_item(a: &ast::ImplItem); fn check_impl_item_post(a: &ast::ImplItem); - fn check_struct_def( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); - fn check_struct_def_post( - a: &ast::VariantData, - b: ast::Ident, - c: &ast::Generics, - d: ast::NodeId - ); + fn check_struct_def(a: &ast::VariantData); + fn check_struct_def_post(a: &ast::VariantData); fn check_struct_field(a: &ast::StructField); - fn check_variant(a: &ast::Variant, b: &ast::Generics); - fn check_variant_post(a: &ast::Variant, b: &ast::Generics); + fn check_variant(a: &ast::Variant); + fn check_variant_post(a: &ast::Variant); fn check_lifetime(a: &ast::Lifetime); fn check_path(a: &ast::Path, b: ast::NodeId); fn check_attribute(a: &ast::Attribute); @@ -812,9 +792,9 @@ impl intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir()) } - fn visit_arg(&mut self, arg: &'tcx hir::Arg) { - self.with_lint_attrs(arg.hir_id, &arg.attrs, |builder| { - intravisit::walk_arg(builder, arg); + fn visit_param(&mut self, param: &'tcx hir::Param) { + self.with_lint_attrs(param.hir_id, ¶m.attrs, |builder| { + intravisit::walk_param(builder, param); }); } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 8ce8bb52566c6..d4805a7c78322 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -30,10 +30,11 @@ fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool { Some(Node::Item(..)) | Some(Node::ImplItem(..)) | Some(Node::ForeignItem(..)) | - Some(Node::TraitItem(..)) => - true, - _ => - false + Some(Node::TraitItem(..)) | + Some(Node::Variant(..)) | + Some(Node::AnonConst(..)) | + Some(Node::Pat(..)) => true, + _ => false } } @@ -75,7 +76,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(res.def_id()); } _ if self.in_pat => {}, - Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | + Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { let variant_id = self.tcx.parent(ctor_def_id).unwrap(); @@ -92,6 +93,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(variant_id); } } + Res::SelfTy(t, i) => { + if let Some(t) = t { + self.check_def_id(t); + } + if let Some(i) = i { + self.check_def_id(i); + } + } Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} _ => { self.check_def_id(res.def_id()); @@ -271,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { let res = self.tables.qpath_res(path, pat.hir_id); self.handle_field_pattern_match(pat, res, fields); } - PatKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { + PatKind::Path(ref qpath) => { let res = self.tables.qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -298,6 +307,11 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } intravisit::walk_ty(self, ty); } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + self.live_symbols.insert(c.hir_id); + intravisit::walk_anon_const(self, c); + } } fn has_allow_dead_code_or_lang_attr( diff --git a/src/librustc/middle/diagnostic_items.rs b/src/librustc/middle/diagnostic_items.rs new file mode 100644 index 0000000000000..dfae169b27824 --- /dev/null +++ b/src/librustc/middle/diagnostic_items.rs @@ -0,0 +1,123 @@ +//! Detecting diagnostic items. +//! +//! Diagnostic items are items that are not language-inherent, but can reasonably be expected to +//! exist for diagnostic purposes. This allows diagnostic authors to refer to specific items +//! directly, without having to guess module paths and crates. +//! Examples are: +//! +//! * Traits like `Debug`, that have no bearing on language semantics +//! +//! * Compiler internal types like `Ty` and `TyCtxt` + +use crate::hir::def_id::{DefId, LOCAL_CRATE}; +use crate::ty::TyCtxt; +use crate::util::nodemap::FxHashMap; + +use syntax::ast; +use syntax::symbol::{Symbol, sym}; +use crate::hir::itemlikevisit::ItemLikeVisitor; +use crate::hir; + +struct DiagnosticItemCollector<'tcx> { + // items from this crate + items: FxHashMap, + tcx: TyCtxt<'tcx>, +} + +impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + self.observe_item(&item.attrs, item.hir_id); + } + + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { + self.observe_item(&trait_item.attrs, trait_item.hir_id); + } + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) { + self.observe_item(&impl_item.attrs, impl_item.hir_id); + } +} + +impl<'tcx> DiagnosticItemCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { + DiagnosticItemCollector { + tcx, + items: Default::default(), + } + } + + fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) { + if let Some(name) = extract(attrs) { + let def_id = self.tcx.hir().local_def_id(hir_id); + // insert into our table + collect_item(self.tcx, &mut self.items, name, def_id); + } + } +} + +fn collect_item( + tcx: TyCtxt<'_>, + items: &mut FxHashMap, + name: Symbol, + item_def_id: DefId, +) { + // Check for duplicates. + if let Some(original_def_id) = items.insert(name, item_def_id) { + if original_def_id != item_def_id { + let mut err = match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.struct_span_err( + span, + &format!("duplicate diagnostic item found: `{}`.", name)), + None => tcx.sess.struct_err(&format!( + "duplicate diagnostic item in crate `{}`: `{}`.", + tcx.crate_name(item_def_id.krate), + name)), + }; + if let Some(span) = tcx.hir().span_if_local(original_def_id) { + span_note!(&mut err, span, "first defined here."); + } else { + err.note(&format!("first defined in crate `{}`.", + tcx.crate_name(original_def_id.krate))); + } + err.emit(); + } + } +} + +/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. +fn extract(attrs: &[ast::Attribute]) -> Option { + attrs.iter().find_map(|attr| { + if attr.check_name(sym::rustc_diagnostic_item) { + attr.value_str() + } else { + None + } + }) +} + +/// Traverse and collect the diagnostic items in the current +pub fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = DiagnosticItemCollector::new(tcx); + + // Collect diagnostic items in this crate. + tcx.hir().krate().visit_all_item_likes(&mut collector); + + tcx.arena.alloc(collector.items) +} + + +/// Traverse and collect all the diagnostic items in all crates. +pub fn collect_all<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx FxHashMap { + // Initialize the collector. + let mut collector = FxHashMap::default(); + + // Collect diagnostic items in other crates. + for &cnum in tcx.crates().iter().chain(std::iter::once(&LOCAL_CRATE)) { + for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { + collect_item(tcx, &mut collector, name, def_id); + } + } + + tcx.arena.alloc(collector) +} diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a274d7bbee5f7..222c2a405d65b 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -313,9 +313,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { pub fn consume_body(&mut self, body: &hir::Body) { debug!("consume_body(body={:?})", body); - for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.pat_ty_adjusted(&arg.pat)); - debug!("consume_body: arg_ty = {:?}", arg_ty); + for param in &body.params { + let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat)); + debug!("consume_body: param_ty = {:?}", param_ty); let fn_body_scope_r = self.tcx().mk_region(ty::ReScope( @@ -323,13 +323,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { id: body.value.hir_id.local_id, data: region::ScopeData::Node })); - let arg_cmt = Rc::new(self.mc.cat_rvalue( - arg.hir_id, - arg.pat.span, - fn_body_scope_r, // Args live only as long as the fn body. - arg_ty)); + let param_cmt = Rc::new(self.mc.cat_rvalue( + param.hir_id, + param.pat.span, + fn_body_scope_r, // Parameters live only as long as the fn body. + param_ty)); - self.walk_irrefutable_pat(arg_cmt, &arg.pat); + self.walk_irrefutable_pat(param_cmt, ¶m.pat); } self.consume_expr(&body.value); diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index c5c8639324358..6b04600eb75f8 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -367,8 +367,6 @@ language_item_table! { MaybeUninitLangItem, "maybe_uninit", maybe_uninit, Target::Union; - DebugTraitLangItem, "debug_trait", debug_trait, Target::Trait; - // Align offset for stride != 1, must not panic. AlignOffsetLangItem, "align_offset", align_offset_fn, Target::Fn; @@ -381,9 +379,13 @@ language_item_table! { impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally abort compilation. - pub fn require_lang_item(&self, lang_item: LangItem) -> DefId { + pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { - self.sess.fatal(&msg) + if let Some(span) = span { + self.sess.span_fatal(span, &msg) + } else { + self.sess.fatal(&msg) + } }) } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 9c9e8c0bca3b8..00013bfc574f4 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -242,7 +242,7 @@ struct LocalInfo { #[derive(Copy, Clone, Debug)] enum VarKind { - Arg(HirId, ast::Name), + Param(HirId, ast::Name), Local(LocalInfo), CleanExit } @@ -298,7 +298,7 @@ impl IrMaps<'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { + Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) => { self.variable_map.insert(node_id, v); }, CleanExit => {} @@ -320,7 +320,7 @@ impl IrMaps<'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Arg(_, name) => { + Local(LocalInfo { name, .. }) | Param(_, name) => { name.to_string() }, CleanExit => "".to_owned() @@ -330,7 +330,7 @@ impl IrMaps<'tcx> { fn variable_is_shorthand(&self, var: Variable) -> bool { match self.var_kinds[var.get()] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, - Arg(..) | CleanExit => false + Param(..) | CleanExit => false } } @@ -371,13 +371,13 @@ fn visit_fn<'tcx>( let body = ir.tcx.hir().body(body_id); - for arg in &body.arguments { - let is_shorthand = match arg.pat.node { + for param in &body.params { + let is_shorthand = match param.pat.node { crate::hir::PatKind::Struct(..) => true, _ => false, }; - arg.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding argument {:?}", hir_id); + param.pat.each_binding(|_bm, hir_id, _x, ident| { + debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, @@ -385,7 +385,7 @@ fn visit_fn<'tcx>( is_shorthand: true, }) } else { - Arg(hir_id, ident.name) + Param(hir_id, ident.name) }; fn_maps.add_variable(var); }) @@ -1525,8 +1525,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) { - for arg in &body.arguments { - arg.pat.each_binding(|_bm, hir_id, _, ident| { + for param in &body.params { + param.pat.each_binding(|_bm, hir_id, _, ident| { let sp = ident.span; let var = self.variable(hir_id, sp); // Ignore unused self. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 3d100d2fbf833..28aa86ef9afb2 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1383,8 +1383,8 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { // The arguments and `self` are parented to the fn. self.cx.var_parent = self.cx.parent.take(); - for argument in &body.arguments { - self.visit_pat(&argument.pat); + for param in &body.params { + self.visit_pat(¶m.pat); } // The body of the every fn is a root scope. diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index f5b0af61693be..8836a632a7ca8 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2557,7 +2557,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } = info; let help_name = if let Some(ident) = parent.and_then(|body| { - self.tcx.hir().body(body).arguments[index].pat.simple_ident() + self.tcx.hir().body(body).params[index].pat.simple_ident() }) { format!("`{}`", ident) } else { diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index 84b4cd914563e..df1d9a987011d 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -13,18 +13,33 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_target::abi::HasDataLayout; use std::borrow::Cow; -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +// NOTE: When adding new fields, make sure to adjust the Snapshot impl in +// `src/librustc_mir/interpret/snapshot.rs`. +#[derive( + Clone, + Debug, + Eq, + PartialEq, + PartialOrd, + Ord, + Hash, + RustcEncodable, + RustcDecodable, + HashStable, +)] pub struct Allocation { /// The actual bytes of the allocation. - /// Note that the bytes of a pointer represent the offset of the pointer - pub bytes: Vec, + /// Note that the bytes of a pointer represent the offset of the pointer. + bytes: Vec, /// Maps from byte addresses to extra data for each pointer. /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting /// at the given offset. - pub relocations: Relocations, - /// Denotes undefined memory. Reading from undefined memory is forbidden in miri - pub undef_mask: UndefMask, + relocations: Relocations, + /// Denotes which part of this allocation is initialized. + undef_mask: UndefMask, + /// The size of the allocation. Currently, must always equal `bytes.len()`. + pub size: Size, /// The alignment of the allocation to detect unaligned reads. pub align: Align, /// Whether the allocation is mutable. @@ -85,11 +100,12 @@ impl Allocation { /// Creates a read-only allocation initialized by the given bytes pub fn from_bytes<'a>(slice: impl Into>, align: Align) -> Self { let bytes = slice.into().into_owned(); - let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true); + let size = Size::from_bytes(bytes.len() as u64); Self { bytes, relocations: Relocations::new(), - undef_mask, + undef_mask: UndefMask::new(size, true), + size, align, mutability: Mutability::Immutable, extra: (), @@ -106,6 +122,7 @@ impl Allocation { bytes: vec![0; size.bytes() as usize], relocations: Relocations::new(), undef_mask: UndefMask::new(size, false), + size, align, mutability: Mutability::Mutable, extra: (), @@ -113,6 +130,31 @@ impl Allocation { } } +/// Raw accessors. Provide access to otherwise private bytes. +impl Allocation { + pub fn len(&self) -> usize { + self.size.bytes() as usize + } + + /// Looks at a slice which may describe undefined bytes or describe a relocation. This differs + /// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the + /// edges) at all. It further ignores `AllocationExtra` callbacks. + /// This must not be used for reads affecting the interpreter execution. + pub fn inspect_with_undef_and_ptr_outside_interpreter(&self, range: Range) -> &[u8] { + &self.bytes[range] + } + + /// Returns the undef mask. + pub fn undef_mask(&self) -> &UndefMask { + &self.undef_mask + } + + /// Returns the relocation list. + pub fn relocations(&self) -> &Relocations { + &self.relocations + } +} + impl<'tcx> rustc_serialize::UseSpecializedDecodable for &'tcx Allocation {} /// Byte accessors @@ -132,9 +174,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { ); let end = end.bytes() as usize; assert!( - end <= self.bytes.len(), + end <= self.len(), "Out-of-bounds access at offset {}, size {} in allocation of size {}", - offset.bytes(), size.bytes(), self.bytes.len() + offset.bytes(), size.bytes(), self.len() ); (offset.bytes() as usize)..end } @@ -422,7 +464,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Relocations impl<'tcx, Tag: Copy, Extra> Allocation { /// Returns all relocations overlapping with the given ptr-offset pair. - pub fn relocations( + pub fn get_relocations( &self, cx: &impl HasDataLayout, ptr: Pointer, @@ -443,7 +485,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if self.relocations(cx, ptr, size).is_empty() { + if self.get_relocations(cx, ptr, size).is_empty() { Ok(()) } else { throw_unsup!(ReadPointerAsBytes) @@ -465,7 +507,7 @@ impl<'tcx, Tag: Copy, Extra> Allocation { // Find the start and end of the given range and its outermost relocations. let (first, last) = { // Find all relocations overlapping the given range. - let relocations = self.relocations(cx, ptr, size); + let relocations = self.get_relocations(cx, ptr, size); if relocations.is_empty() { return Ok(()); } @@ -536,6 +578,94 @@ impl<'tcx, Tag, Extra> Allocation { } } +/// Run-length encoding of the undef mask. +/// Used to copy parts of a mask multiple times to another allocation. +pub struct AllocationDefinedness { + /// The definedness of the first range. + initial: bool, + /// The lengths of ranges that are run-length encoded. + /// The definedness of the ranges alternate starting with `initial`. + ranges: smallvec::SmallVec::<[u64; 1]>, +} + +/// Transferring the definedness mask to other allocations. +impl Allocation { + /// Creates a run-length encoding of the undef_mask. + pub fn compress_undef_range( + &self, + src: Pointer, + size: Size, + ) -> AllocationDefinedness { + // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), + // a naive undef mask copying algorithm would repeatedly have to read the undef mask from + // the source and write it to the destination. Even if we optimized the memory accesses, + // we'd be doing all of this `repeat` times. + // Therefor we precompute a compressed version of the undef mask of the source value and + // then write it back `repeat` times without computing any more information from the source. + + // a precomputed cache for ranges of defined/undefined bits + // 0000010010001110 will become + // [5, 1, 2, 1, 3, 3, 1] + // where each element toggles the state + + let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); + let initial = self.undef_mask.get(src.offset); + let mut cur_len = 1; + let mut cur = initial; + + for i in 1..size.bytes() { + // FIXME: optimize to bitshift the current undef block's bits and read the top bit + if self.undef_mask.get(src.offset + Size::from_bytes(i)) == cur { + cur_len += 1; + } else { + ranges.push(cur_len); + cur_len = 1; + cur = !cur; + } + } + + ranges.push(cur_len); + + AllocationDefinedness { ranges, initial, } + } + + /// Apply multiple instances of the run-length encoding to the undef_mask. + pub fn mark_compressed_undef_range( + &mut self, + defined: &AllocationDefinedness, + dest: Pointer, + size: Size, + repeat: u64, + ) { + // an optimization where we can just overwrite an entire range of definedness bits if + // they are going to be uniformly `1` or `0`. + if defined.ranges.len() <= 1 { + self.undef_mask.set_range_inbounds( + dest.offset, + dest.offset + size * repeat, + defined.initial, + ); + return; + } + + for mut j in 0..repeat { + j *= size.bytes(); + j += dest.offset.bytes(); + let mut cur = defined.initial; + for range in &defined.ranges { + let old_j = j; + j += range; + self.undef_mask.set_range_inbounds( + Size::from_bytes(old_j), + Size::from_bytes(j), + cur, + ); + cur = !cur; + } + } + } +} + /// Relocations #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Relocations(SortedMap); @@ -566,6 +696,59 @@ impl DerefMut for Relocations { } } +/// A partial, owned list of relocations to transfer into another allocation. +pub struct AllocationRelocations { + relative_relocations: Vec<(Size, (Tag, AllocId))>, +} + +impl Allocation { + pub fn prepare_relocation_copy( + &self, + cx: &impl HasDataLayout, + src: Pointer, + size: Size, + dest: Pointer, + length: u64, + ) -> AllocationRelocations { + let relocations = self.get_relocations(cx, src, size); + if relocations.is_empty() { + return AllocationRelocations { relative_relocations: Vec::new() }; + } + + let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + + for i in 0..length { + new_relocations.extend( + relocations + .iter() + .map(|&(offset, reloc)| { + // compute offset for current repetition + let dest_offset = dest.offset + (i * size); + ( + // shift offsets from source allocation to destination allocation + offset + dest_offset - src.offset, + reloc, + ) + }) + ); + } + + AllocationRelocations { + relative_relocations: new_relocations, + } + } + + /// Apply a relocation copy. + /// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected + /// to be clear of relocations. + pub fn mark_relocation_range( + &mut self, + relocations: AllocationRelocations, + ) { + self.relocations.insert_presorted(relocations.relative_relocations); + } +} + //////////////////////////////////////////////////////////////////////////////// // Undefined byte tracking //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 11701a6637744..5ac99ba147000 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -108,11 +108,6 @@ pub struct Body<'tcx> { /// needn't) be tracked across crates. pub source_scope_local_data: ClearCrossCrate>, - /// Rvalues promoted from this function, such as borrows of constants. - /// Each of them is the Body of a constant with the fn's type parameters - /// in scope, but a separate set of locals. - pub promoted: IndexVec>, - /// Yields type of the function, if it is a generator. pub yield_ty: Option>, @@ -174,7 +169,6 @@ impl<'tcx> Body<'tcx> { basic_blocks: IndexVec>, source_scopes: IndexVec, source_scope_local_data: ClearCrossCrate>, - promoted: IndexVec>, yield_ty: Option>, local_decls: LocalDecls<'tcx>, user_type_annotations: CanonicalUserTypeAnnotations<'tcx>, @@ -196,7 +190,6 @@ impl<'tcx> Body<'tcx> { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop: None, generator_layout: None, @@ -418,7 +411,6 @@ impl_stable_hash_for!(struct Body<'tcx> { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop, generator_layout, @@ -1555,7 +1547,7 @@ pub struct Statement<'tcx> { #[cfg(target_arch = "x86_64")] static_assert_size!(Statement<'_>, 56); -impl<'tcx> Statement<'tcx> { +impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_nop(&mut self) { @@ -1677,7 +1669,7 @@ pub struct InlineAsm<'tcx> { pub inputs: Box<[(Span, Operand<'tcx>)]>, } -impl<'tcx> Debug for Statement<'tcx> { +impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; match self.kind { @@ -1737,23 +1729,32 @@ pub enum PlaceBase<'tcx> { } /// We store the normalized type to avoid requiring normalization when reading MIR -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Static<'tcx> { pub ty: Ty<'tcx>, - pub kind: StaticKind, + pub kind: StaticKind<'tcx>, + /// The `DefId` of the item this static was declared in. For promoted values, usually, this is + /// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in. + /// However, after inlining, that might no longer be the case as inlined `Place`s are copied + /// into the calling frame. + pub def_id: DefId, } #[derive( - Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable, + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, RustcEncodable, RustcDecodable, )] -pub enum StaticKind { - Promoted(Promoted), - Static(DefId), +pub enum StaticKind<'tcx> { + /// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize + /// it. Usually, these substs are just the identity substs for the item. However, the inliner + /// will adjust these substs when it inlines a function based on the substs at the callsite. + Promoted(Promoted, SubstsRef<'tcx>), + Static, } impl_stable_hash_for!(struct Static<'tcx> { ty, - kind + kind, + def_id }); /// The `Projection` data structure defines things of the form `base.x`, `*b` or `b[index]`. @@ -2047,7 +2048,7 @@ impl<'p, 'tcx> Iterator for ProjectionsIter<'p, 'tcx> { impl<'p, 'tcx> FusedIterator for ProjectionsIter<'p, 'tcx> {} -impl<'tcx> Debug for Place<'tcx> { +impl Debug for Place<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { self.iterate(|_place_base, place_projections| { // FIXME: remove this collect once we have migrated to slices @@ -2114,10 +2115,12 @@ impl Debug for PlaceBase<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { PlaceBase::Local(id) => write!(fmt, "{:?}", id), - PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static(def_id) }) => { + PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => { write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty) } - PlaceBase::Static(box self::Static { ty, kind: StaticKind::Promoted(promoted) }) => { + PlaceBase::Static(box self::Static { + ty, kind: StaticKind::Promoted(promoted, _), def_id: _ + }) => { write!(fmt, "({:?}: {:?})", promoted, ty) } } @@ -3032,7 +3035,6 @@ BraceStructTypeFoldableImpl! { basic_blocks, source_scopes, source_scope_local_data, - promoted, yield_ty, generator_drop, generator_layout, @@ -3226,13 +3228,63 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { Place { - base: self.base.clone(), + base: self.base.fold_with(folder), projection: self.projection.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.projection.visit_with(visitor) + self.base.visit_with(visitor) || self.projection.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match self { + PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)), + PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match self { + PlaceBase::Local(local) => local.visit_with(visitor), + PlaceBase::Static(static_) => (**static_).visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + Static { + ty: self.ty.fold_with(folder), + kind: self.kind.fold_with(folder), + def_id: self.def_id, + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + let Static { ty, kind, def_id: _ } = self; + + ty.visit_with(visitor) || kind.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + match self { + StaticKind::Promoted(promoted, substs) => + StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder)), + StaticKind::Static => StaticKind::Static + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match self { + StaticKind::Promoted(promoted, substs) => + promoted.visit_with(visitor) || substs.visit_with(visitor), + StaticKind::Static => { false } + } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 2d16e7bcc8371..821367e9ea12c 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -708,7 +708,7 @@ macro_rules! make_mir_visitor { PlaceBase::Local(local) => { self.visit_local(local, context, location); } - PlaceBase::Static(box Static { kind: _, ty }) => { + PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => { self.visit_ty(& $($mutability)? *ty, TyContext::Location(location)); } } @@ -724,10 +724,6 @@ macro_rules! make_mir_visitor { } match & $($mutability)? proj.elem { - ProjectionElem::Deref => { - } - ProjectionElem::Subslice { from: _, to: _ } => { - } ProjectionElem::Field(_field, ty) => { self.visit_ty(ty, TyContext::Location(location)); } @@ -738,11 +734,12 @@ macro_rules! make_mir_visitor { location ); } + ProjectionElem::Deref | + ProjectionElem::Subslice { from: _, to: _ } | ProjectionElem::ConstantIndex { offset: _, min_length: _, - from_end: _ } => { - } - ProjectionElem::Downcast(_name, _variant_index) => { + from_end: _ } | + ProjectionElem::Downcast(_, _) => { } } } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 5ab1b90642a6a..ef838114f6c36 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -110,7 +110,11 @@ rustc_queries! { no_hash } - query mir_validated(_: DefId) -> &'tcx Steal> { + query mir_validated(_: DefId) -> + ( + &'tcx Steal>, + &'tcx Steal>> + ) { no_hash } @@ -125,7 +129,17 @@ rustc_queries! { } } - query promoted_mir(key: DefId) -> &'tcx IndexVec> { } + query promoted_mir(key: DefId) -> &'tcx IndexVec> { + cache_on_disk_if { key.is_local() } + load_cached(tcx, id) { + let promoted: Option< + rustc_data_structures::indexed_vec::IndexVec< + crate::mir::Promoted, + crate::mir::Body<'tcx> + >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); + promoted.map(|p| &*tcx.arena.alloc(p)) + } + } } TypeChecking { @@ -790,7 +804,7 @@ rustc_queries! { } BorrowChecking { - // Lifetime resolution. See `middle::resolve_lifetimes`. + /// Lifetime resolution. See `middle::resolve_lifetimes`. query resolve_lifetimes(_: CrateNum) -> &'tcx ResolveLifetimes { desc { "resolving lifetimes" } } @@ -832,13 +846,30 @@ rustc_queries! { -> &'tcx [(Symbol, Option)] { desc { "calculating the lib features defined in a crate" } } + /// Returns the lang items defined in another crate by loading it from metadata. + // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid + // of that argument? query get_lang_items(_: CrateNum) -> &'tcx LanguageItems { eval_always desc { "calculating the lang items map" } } + + /// Returns all diagnostic items defined in all crates + query all_diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + eval_always + desc { "calculating the diagnostic items map" } + } + + /// Returns the lang items defined in another crate by loading it from metadata. query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] { desc { "calculating the lang items defined in a crate" } } + + /// Returns the diagnostic items defined in a crate + query diagnostic_items(_: CrateNum) -> &'tcx FxHashMap { + desc { "calculating the diagnostic items map in a crate" } + } + query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] { desc { "calculating the missing lang items in a crate" } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8e3b910e0da3a..740d9db7edcf7 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1292,6 +1292,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), continue_parse_after_error: bool = (false, parse_bool, [TRACKED], "attempt to recover from parse errors (experimental)"), dep_tasks: bool = (false, parse_bool, [UNTRACKED], @@ -1719,13 +1721,7 @@ pub fn rustc_short_optgroups() -> Vec { static, framework, or dylib (the default).", "[KIND=]NAME", ), - opt::multi_s( - "", - "crate-type", - "Comma separated list of types of crates - for the compiler to emit", - "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", - ), + make_crate_type_option(), opt::opt_s( "", "crate-name", @@ -2506,6 +2502,16 @@ pub fn build_session_options_and_crate_config( ) } +pub fn make_crate_type_option() -> RustcOptGroup { + opt::multi_s( + "", + "crate-type", + "Comma separated list of types of crates + for the compiler to emit", + "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]", + ) +} + pub fn parse_crate_types_from_list(list_list: Vec) -> Result, String> { let mut crate_types: Vec = Vec::new(); for unparsed_crate_type in &list_list { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 61dac678912df..f01883d9634cd 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1055,6 +1055,7 @@ fn default_emitter( Some(source_map.clone()), short, sopts.debugging_opts.teach, + sopts.debugging_opts.terminal_width, ), Some(dst) => EmitterWriter::new( dst, @@ -1062,6 +1063,7 @@ fn default_emitter( short, false, // no teach messages when writing to a buffer false, // no colors when writing to a buffer + None, // no terminal width ), }; Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) @@ -1375,7 +1377,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), @@ -1389,7 +1391,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); - Box::new(EmitterWriter::stderr(color_config, None, short, false)) + Box::new(EmitterWriter::stderr(color_config, None, short, false, None)) } config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(pretty, json_rendered)), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index ba92e851141a6..b38e1f5f83937 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1,20 +1,21 @@ use super::{ + ConstEvalFailure, + EvaluationResult, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, + ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, - TraitNotObjectSafe, - ConstEvalFailure, + Overflow, PredicateObligation, SelectionContext, SelectionError, - ObjectSafetyViolation, - Overflow, + TraitNotObjectSafe, }; use crate::hir; @@ -35,7 +36,7 @@ use crate::util::nodemap::{FxHashMap, FxHashSet}; use errors::{Applicability, DiagnosticBuilder}; use std::fmt; use syntax::ast; -use syntax::symbol::sym; +use syntax::symbol::{sym, kw}; use syntax_pos::{DUMMY_SP, Span, ExpnKind}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { @@ -657,19 +658,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, E0277, "{}", - message.unwrap_or_else(|| - format!("the trait bound `{}` is not satisfied{}", - trait_ref.to_predicate(), post_message) - )); + message.unwrap_or_else(|| format!( + "the trait bound `{}` is not satisfied{}", + trait_ref.to_predicate(), + post_message, + ))); let explanation = if obligation.cause.code == ObligationCauseCode::MainFunctionType { "consider using `()`, or a `Result`".to_owned() } else { - format!("{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty()) + format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty(), + ) }; if let Some(ref s) = label { @@ -686,6 +690,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); + self.suggest_fn_call(&obligation, &mut err, &trait_ref); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); @@ -953,6 +958,57 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + fn suggest_fn_call( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut DiagnosticBuilder<'tcx>, + trait_ref: &ty::Binder>, + ) { + let self_ty = trait_ref.self_ty(); + match self_ty.sty { + ty::FnDef(def_id, _) => { + // We tried to apply the bound to an `fn`. Check whether calling it would evaluate + // to a type that *would* satisfy the trait binding. If it would, suggest calling + // it: `bar(foo)` -> `bar(foo)`. This case is *very* likely to be hit if `foo` is + // `async`. + let output_ty = self_ty.fn_sig(self.tcx).output(); + let new_trait_ref = ty::TraitRef { + def_id: trait_ref.def_id(), + substs: self.tcx.mk_substs_trait(output_ty.skip_binder(), &[]), + }; + let obligation = Obligation::new( + obligation.cause.clone(), + obligation.param_env, + new_trait_ref.to_predicate(), + ); + match self.evaluate_obligation(&obligation) { + Ok(EvaluationResult::EvaluatedToOk) | + Ok(EvaluationResult::EvaluatedToOkModuloRegions) | + Ok(EvaluationResult::EvaluatedToAmbig) => { + if let Some(hir::Node::Item(hir::Item { + ident, + node: hir::ItemKind::Fn(.., body_id), + .. + })) = self.tcx.hir().get_if_local(def_id) { + let body = self.tcx.hir().body(*body_id); + err.help(&format!( + "use parentheses to call the function: `{}({})`", + ident, + body.params.iter() + .map(|arg| match &arg.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "))); + } + } + _ => {} + } + } + _ => {} + } + } + /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. fn suggest_remove_reference( @@ -1044,7 +1100,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { node: hir::ExprKind::Closure(_, ref _decl, id, span, _), .. }) => { - (self.tcx.sess.source_map().def_span(span), self.tcx.hir().body(id).arguments.iter() + (self.tcx.sess.source_map().def_span(span), + self.tcx.hir().body(id).params.iter() .map(|arg| { if let hir::Pat { node: hir::PatKind::Tuple(ref args, _), @@ -1534,17 +1591,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note("only the last element of a tuple may have a dynamically sized type"); } ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", - data)); + err.note(&format!( + "required so that the projection `{}` is well-formed", + data, + )); } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(&format!("required so that reference `{}` does not outlive its referent", - ref_ty)); + err.note(&format!( + "required so that reference `{}` does not outlive its referent", + ref_ty, + )); } ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(&format!("required so that the lifetime bound of `{}` for `{}` \ - is satisfied", - region, object_ty)); + err.note(&format!( + "required so that the lifetime bound of `{}` for `{}` is satisfied", + region, + object_ty, + )); } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.def_path_str(item_def_id); @@ -1552,7 +1615,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(sp) = tcx.hir().span_if_local(item_def_id) { let sp = tcx.sess.source_map().def_span(sp); - err.span_note(sp, &msg); + err.span_label(sp, &msg); } else { err.note(&msg); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 72df45df92314..87a23f655a8f3 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -15,7 +15,6 @@ use super::util; use crate::hir::def_id::DefId; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::mir::interpret::{GlobalId, ConstValue}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_macros::HashStable; use syntax::ast::Ident; @@ -397,40 +396,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { - let tcx = self.selcx.tcx().global_tcx(); - let param_env = self.param_env; - if !param_env.has_local_value() { - if substs.needs_infer() || substs.has_placeholders() { - let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); - let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(tcx, substs); - return evaluated; - } - } - } else { - if !substs.has_local_value() { - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return evaluated; - } - } - } - } - } - } - constant + constant.eval(self.selcx.tcx(), self.param_env) } } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 2ffcd0fd4d941..c31ff3ab1b55d 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -5,11 +5,10 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; -use crate::mir::interpret::{GlobalId, ConstValue}; use crate::traits::project::Normalized; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::{Subst, InternalSubsts}; +use crate::ty::subst::Subst; use crate::ty::{self, Ty, TyCtxt}; use super::NoSolution; @@ -191,40 +190,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { - let tcx = self.infcx.tcx.global_tcx(); - let param_env = self.param_env; - if !param_env.has_local_value() { - if substs.needs_infer() || substs.has_placeholders() { - let identity_substs = InternalSubsts::identity_for_item(tcx, def_id); - let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(tcx, substs); - return evaluated; - } - } - } else { - if !substs.has_local_value() { - let instance = ty::Instance::resolve(tcx, param_env, def_id, substs); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return evaluated; - } - } - } - } - } - } - constant + constant.eval(self.infcx.tcx, self.param_env) } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d4ae366262cbf..217c887d5254e 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -3513,7 +3513,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can only make objects from sized types. let tr = ty::TraitRef { - def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem), + def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: tcx.mk_substs_trait(source, &[]), }; nested.push(predicate_to_obligation(tr.to_predicate())); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e72efdb057ab1..17c9e520bcea2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -21,7 +21,7 @@ use crate::middle::cstore::EncodedMetadata; use crate::middle::lang_items; use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use crate::middle::stability; -use crate::mir::{Body, interpret, ProjectionKind}; +use crate::mir::{Body, interpret, ProjectionKind, Promoted}; use crate::mir::interpret::{ConstValue, Allocation, Scalar}; use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst}; use crate::ty::ReprOptions; @@ -978,6 +978,7 @@ pub struct FreeRegionInfo { /// /// [rustc guide]: https://rust-lang.github.io/rustc-guide/ty.html #[derive(Copy, Clone)] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyCtxt")] pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } @@ -1096,6 +1097,16 @@ impl<'tcx> TyCtxt<'tcx> { self.arena.alloc(Steal::new(mir)) } + pub fn alloc_steal_promoted(self, promoted: IndexVec>) -> + &'tcx Steal>> { + self.arena.alloc(Steal::new(promoted)) + } + + pub fn intern_promoted(self, promoted: IndexVec>) -> + &'tcx IndexVec> { + self.arena.alloc(promoted) + } + pub fn alloc_adt_def( self, did: DefId, @@ -1298,10 +1309,22 @@ impl<'tcx> TyCtxt<'tcx> { self.get_lib_features(LOCAL_CRATE) } + /// Obtain all lang items of this crate and all dependencies (recursively) pub fn lang_items(self) -> &'tcx middle::lang_items::LanguageItems { self.get_lang_items(LOCAL_CRATE) } + /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to + /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. + pub fn get_diagnostic_item(self, name: Symbol) -> Option { + self.all_diagnostic_items(LOCAL_CRATE).get(&name).copied() + } + + /// Check whether the diagnostic item with the given `name` has the given `DefId`. + pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { + self.diagnostic_items(did.krate).get(&name) == Some(&did) + } + pub fn stability(self) -> &'tcx stability::Index<'tcx> { self.stability_index(LOCAL_CRATE) } @@ -2375,13 +2398,19 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); + let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem, None); + self.mk_generic_adt(def_id, ty) + } + + #[inline] + pub fn mk_lang_item(self, ty: Ty<'tcx>, item: lang_items::LangItem) -> Ty<'tcx> { + let def_id = self.require_lang_item(item, None); self.mk_generic_adt(def_id, ty) } #[inline] pub fn mk_maybe_uninit(self, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem); + let def_id = self.require_lang_item(lang_items::MaybeUninitLangItem, None); self.mk_generic_adt(def_id, ty) } @@ -2886,6 +2915,14 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(id, LOCAL_CRATE); tcx.arena.alloc(middle::lang_items::collect(tcx)) }; + providers.diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect(tcx) + }; + providers.all_diagnostic_items = |tcx, id| { + assert_eq!(id, LOCAL_CRATE); + middle::diagnostic_items::collect_all(tcx) + }; providers.maybe_unused_trait_import = |tcx, id| { tcx.maybe_unused_trait_imports.contains(&id) }; diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index d6d17a67e01e9..fe8f94ab1d314 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -46,6 +46,8 @@ pub enum TypeError<'tcx> { ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), + + IntrinsicCast, } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -179,6 +181,9 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ConstMismatch(ref values) => { write!(f, "expected `{}`, found `{}`", values.expected, values.found) } + IntrinsicCast => { + write!(f, "cannot coerce intrinsics to function pointers") + } } } } @@ -247,13 +252,15 @@ impl<'tcx> ty::TyS<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_type_err(self, - db: &mut DiagnosticBuilder<'_>, - err: &TypeError<'tcx>, - sp: Span) { + pub fn note_and_explain_type_err( + self, + db: &mut DiagnosticBuilder<'_>, + err: &TypeError<'tcx>, + sp: Span, + ) { use self::TypeError::*; - match err.clone() { + match err { Sorts(values) => { let expected_str = values.expected.sort_string(self); let found_str = values.found.sort_string(self); @@ -261,6 +268,16 @@ impl<'tcx> TyCtxt<'tcx> { db.note("no two closures, even if identical, have the same type"); db.help("consider boxing your closure and/or using it as a trait object"); } + if expected_str == found_str && expected_str == "opaque type" { // Issue #63167 + db.note("distinct uses of `impl Trait` result in different opaque types"); + let e_str = values.expected.to_string(); + let f_str = values.found.to_string(); + if &e_str == &f_str && &e_str == "impl std::future::Future" { + // FIXME: use non-string based check. + db.help("if both `Future`s have the same `Output` type, consider \ + `.await`ing on both of them"); + } + } if let (ty::Infer(ty::IntVar(_)), ty::Float(_)) = (&values.found.sty, &values.expected.sty) // Issue #53280 { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index c71e1ea4e5859..a26fa72f33041 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -327,7 +327,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); + let def_id = tcx.require_lang_item(DropInPlaceFnLangItem, None); let substs = tcx.intern_substs(&[ty.into()]); Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap() } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 8febcfd0754c9..5ec4754c4535b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -273,14 +273,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { repr: &ReprOptions, kind: StructKind) -> Result> { let dl = self.data_layout(); - let packed = repr.packed(); - if packed && repr.align > 0 { + let pack = repr.pack; + if pack.is_some() && repr.align.is_some() { bug!("struct cannot be packed and aligned"); } - let pack = Align::from_bytes(repr.pack as u64).unwrap(); - - let mut align = if packed { + let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align @@ -303,7 +301,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let optimizing = &mut inverse_memory_index[..end]; let field_align = |f: &TyLayout<'_>| { - if packed { f.align.abi.min(pack) } else { f.align.abi } + if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; match kind { StructKind::AlwaysSized | @@ -334,7 +332,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut largest_niche_available = 0; if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - let prefix_align = if packed { + let prefix_align = if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align @@ -355,7 +353,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - let field_align = if packed { + let field_align = if let Some(pack) = pack { field.align.min(AbiAndPrefAlign::new(pack)) } else { field.align @@ -379,10 +377,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .ok_or(LayoutError::SizeOverflow(ty))?; } - if repr.align > 0 { - let repr_align = repr.align as u64; - align = align.max(AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap())); - debug!("univariant repr_align: {:?}", repr_align); + if let Some(repr_align) = repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); } debug!("univariant min_size: {:?}", offset); @@ -730,23 +726,18 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }).collect::, _>>()?; if def.is_union() { - let packed = def.repr.packed(); - if packed && def.repr.align > 0 { - bug!("Union cannot be packed and aligned"); + if def.repr.pack.is_some() && def.repr.align.is_some() { + bug!("union cannot be packed and aligned"); } - let pack = Align::from_bytes(def.repr.pack as u64).unwrap(); - - let mut align = if packed { + let mut align = if def.repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; - if def.repr.align > 0 { - let repr_align = def.repr.align as u64; - align = align.max( - AbiAndPrefAlign::new(Align::from_bytes(repr_align).unwrap())); + if let Some(repr_align) = def.repr.align { + align = align.max(AbiAndPrefAlign::new(repr_align)); } let optimize = !def.repr.inhibit_union_abi_opt(); @@ -755,13 +746,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let index = VariantIdx::new(0); for field in &variants[index] { assert!(!field.is_unsized()); - - let field_align = if packed { - field.align.min(AbiAndPrefAlign::new(pack)) - } else { - field.align - }; - align = align.max(field_align); + align = align.max(field.align); // If all non-ZST fields have the same ABI, forward this ABI if optimize && !field.is_zst() { @@ -796,6 +781,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { size = cmp::max(size, field.size); } + if let Some(pack) = def.repr.pack { + align = align.min(AbiAndPrefAlign::new(pack)); + } + return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::Single { index }, fields: FieldPlacement::Union(variants[index].len()), @@ -1637,7 +1626,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; let adt_kind = adt_def.adt_kind(); - let adt_packed = adt_def.repr.packed(); + let adt_packed = adt_def.repr.pack.is_some(); let build_variant_info = |n: Option, flds: &[ast::Name], diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0b81f193df409..56505c04f0f0c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -33,6 +33,7 @@ use arena::SyncDroplessArena; use crate::session::DataTypeKind; use rustc_serialize::{self, Encodable, Encoder}; +use rustc_target::abi::Align; use std::cell::RefCell; use std::cmp::{self, Ordering}; use std::fmt; @@ -580,6 +581,7 @@ impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { } } +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "Ty")] pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> rustc_serialize::UseSpecializedEncodable for Ty<'tcx> {} @@ -2057,8 +2059,8 @@ impl_stable_hash_for!(struct ReprFlags { #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, - pub align: u32, - pub pack: u32, + pub align: Option, + pub pack: Option, pub flags: ReprFlags, } @@ -2073,18 +2075,19 @@ impl ReprOptions { pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; - let mut max_align = 0; - let mut min_pack = 0; + let mut max_align: Option = None; + let mut min_pack: Option = None; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) { flags.insert(match r { attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { - min_pack = if min_pack > 0 { - cmp::min(pack, min_pack) + let pack = Align::from_bytes(pack as u64).unwrap(); + min_pack = Some(if let Some(min_pack) = min_pack { + min_pack.min(pack) } else { pack - }; + }); ReprFlags::empty() }, attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, @@ -2094,7 +2097,7 @@ impl ReprOptions { ReprFlags::empty() }, attr::ReprAlign(align) => { - max_align = cmp::max(align, max_align); + max_align = max_align.max(Some(Align::from_bytes(align as u64).unwrap())); ReprFlags::empty() }, }); @@ -2113,7 +2116,7 @@ impl ReprOptions { #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } #[inline] - pub fn packed(&self) -> bool { self.pack > 0 } + pub fn packed(&self) -> bool { self.pack.is_some() } #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } #[inline] @@ -2133,8 +2136,12 @@ impl ReprOptions { /// Returns `true` if this `#[repr()]` should inhibit struct field reordering /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr()`. pub fn inhibit_struct_field_reordering_opt(&self) -> bool { - self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.pack == 1 || - self.int.is_some() + if let Some(pack) = self.pack { + if pack.bytes() == 1 { + return true; + } + } + self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() } /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. @@ -2588,12 +2595,12 @@ impl<'tcx> ClosureKind { pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { match *self { - ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem), + ClosureKind::Fn => tcx.require_lang_item(FnTraitLangItem, None), ClosureKind::FnMut => { - tcx.require_lang_item(FnMutTraitLangItem) + tcx.require_lang_item(FnMutTraitLangItem, None) } ClosureKind::FnOnce => { - tcx.require_lang_item(FnOnceTraitLangItem) + tcx.require_lang_item(FnOnceTraitLangItem, None) } } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index bf6741dde43b5..a72ecdb5745bb 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -944,10 +944,16 @@ pub trait PrettyPrinter<'tcx>: .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap()) }, (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => { - Some(&data.bytes[start..end]) + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active slice reference here). We don't use this + // result to affect interpreter execution. + Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) }, (ConstValue::Slice { data, start, end }, ty::Str) => { - let slice = &data.bytes[start..end]; + // The `inspect` here is okay since we checked the bounds, and there are no + // relocations (we have an active `str` reference here). We don't use this + // result to affect interpreter execution. + let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end); let s = ::std::str::from_utf8(slice) .expect("non utf8 str from miri"); p!(write("{:?}", s)); diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 8bf01970eb592..674f8944f261a 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -20,10 +20,10 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::mem; -use syntax::ast::NodeId; +use syntax::ast::{Ident, NodeId}; use syntax::source_map::{SourceMap, StableSourceFileId}; use syntax_pos::{BytePos, Span, DUMMY_SP, SourceFile}; -use syntax_pos::hygiene::{ExpnId, SyntaxContext, ExpnData}; +use syntax_pos::hygiene::{ExpnId, SyntaxContext}; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -591,10 +591,11 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { // FIXME(mw): This method does not restore `ExpnData::parent` or // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things // don't seem to be used after HIR lowering, so everything should be fine - // as long as incremental compilation does not kick in before that. + // until we want incremental compilation to serialize Spans that we need + // full hygiene information for. let location = || Span::with_root_ctxt(lo, hi); - let recover_from_expn_data = |this: &Self, expn_data, pos| { - let span = location().fresh_expansion(expn_data); + let recover_from_expn_data = |this: &Self, expn_data, transparency, pos| { + let span = location().fresh_expansion_with_transparency(expn_data, transparency); this.synthetic_syntax_contexts.borrow_mut().insert(pos, span.ctxt()); span }; @@ -603,9 +604,9 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { location() } TAG_EXPN_DATA_INLINE => { - let expn_data = Decodable::decode(self)?; + let (expn_data, transparency) = Decodable::decode(self)?; recover_from_expn_data( - self, expn_data, AbsoluteBytePos::new(self.opaque.position()) + self, expn_data, transparency, AbsoluteBytePos::new(self.opaque.position()) ) } TAG_EXPN_DATA_SHORTHAND => { @@ -614,9 +615,9 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { if let Some(ctxt) = cached_ctxt { Span::new(lo, hi, ctxt) } else { - let expn_data = - self.with_position(pos.to_usize(), |this| ExpnData::decode(this))?; - recover_from_expn_data(self, expn_data, pos) + let (expn_data, transparency) = + self.with_position(pos.to_usize(), |this| Decodable::decode(this))?; + recover_from_expn_data(self, expn_data, transparency, pos) } } _ => { @@ -626,6 +627,13 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + // FIXME: Handle hygiene in incremental + bug!("Trying to decode Ident for incremental"); + } +} + // This impl makes sure that we get a runtime error when we try decode a // DefIndex that is not contained in a DefId. Such a case would be problematic // because we would not know how to transform the DefIndex to the current @@ -819,7 +827,7 @@ where if span_data.ctxt == SyntaxContext::root() { TAG_NO_EXPN_DATA.encode(self) } else { - let (expn_id, expn_data) = span_data.ctxt.outer_expn_with_data(); + let (expn_id, transparency, expn_data) = span_data.ctxt.outer_mark_with_data(); if let Some(pos) = self.expn_data_shorthands.get(&expn_id).cloned() { TAG_EXPN_DATA_SHORTHAND.encode(self)?; pos.encode(self) @@ -827,12 +835,25 @@ where TAG_EXPN_DATA_INLINE.encode(self)?; let pos = AbsoluteBytePos::new(self.position()); self.expn_data_shorthands.insert(expn_id, pos); - expn_data.encode(self) + (expn_data, transparency).encode(self) } } } } +impl<'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'a, 'tcx, E> +where + E: 'a + ty_codec::TyEncoder, +{ + fn specialized_encode(&mut self, _: &Ident) -> Result<(), Self::Error> { + // We don't currently encode enough information to ensure hygiene works + // with incremental, so panic rather than risk incremental bugs. + + // FIXME: Handle hygiene in incremental + bug!("Trying to encode Ident for incremental") + } +} + impl<'a, 'tcx, E> ty_codec::TyEncoder for CacheEncoder<'a, 'tcx, E> where E: 'a + ty_codec::TyEncoder, diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 945e3e158eafb..565447dd7e1af 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -8,7 +8,7 @@ use crate::hir::def_id::DefId; use crate::ty::subst::{Kind, UnpackedKind, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::mir::interpret::{ConstValue, Scalar, GlobalId}; +use crate::mir::interpret::{ConstValue, Scalar}; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; @@ -551,26 +551,8 @@ pub fn super_relate_consts>( let tcx = relation.tcx(); let eagerly_eval = |x: &'tcx ty::Const<'tcx>| { - if let ConstValue::Unevaluated(def_id, substs) = x.val { - // FIXME(eddyb) get the right param_env. - let param_env = ty::ParamEnv::empty(); - if !substs.has_local_value() { - let instance = ty::Instance::resolve( - tcx.global_tcx(), - param_env, - def_id, - substs, - ); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - if let Ok(ct) = tcx.const_eval(param_env.and(cid)) { - return ct.val; - } - } - } + if !x.val.has_local_value() { + return x.eval(tcx, relation.param_env()).val; } x.val }; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 649a5244728ba..ec7cf1a13c596 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -748,6 +748,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), + IntrinsicCast => IntrinsicCast, }) } } @@ -1338,6 +1339,7 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::Sorts)(x), (ty::error::TypeError::ExistentialMismatch)(x), (ty::error::TypeError::ConstMismatch)(x), + (ty::error::TypeError::IntrinsicCast), } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 2b173068b38e4..d2edf6fb1ee80 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -86,6 +86,7 @@ impl BoundRegion { /// AST structure in `libsyntax/ast.rs` as well. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable, Debug)] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "TyKind")] pub enum TyKind<'tcx> { /// The primitive boolean type. Written as `bool`. Bool, @@ -385,7 +386,7 @@ impl<'tcx> ClosureSubsts<'tcx> { let ty = self.closure_sig_ty(def_id, tcx); match ty.sty { ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty), + _ => bug!("closure_sig_ty is not a fn-ptr: {:?}", ty.sty), } } } @@ -2299,23 +2300,33 @@ impl<'tcx> Const<'tcx> { assert_eq!(self.ty, ty); // if `ty` does not depend on generic parameters, use an empty param_env let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size; + self.eval(tcx, param_env).val.try_to_bits(size) + } + + #[inline] + pub fn eval( + &self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> &Const<'tcx> { + // FIXME(const_generics): this doesn't work right now, + // because it tries to relate an `Infer` to a `Param`. match self.val { - // FIXME(const_generics): this doesn't work right now, - // because it tries to relate an `Infer` to a `Param`. ConstValue::Unevaluated(did, substs) => { // if `substs` has no unresolved components, use and empty param_env let (param_env, substs) = param_env.with_reveal_all().and(substs).into_parts(); // try to resolve e.g. associated constants to their definition on an impl - let instance = ty::Instance::resolve(tcx, param_env, did, substs)?; + let instance = match ty::Instance::resolve(tcx, param_env, did, substs) { + Some(instance) => instance, + None => return self, + }; let gid = GlobalId { instance, promoted: None, }; - let evaluated = tcx.const_eval(param_env.and(gid)).ok()?; - evaluated.val.try_to_bits(size) + tcx.const_eval(param_env.and(gid)).unwrap_or(self) }, - // otherwise just extract a `ConstValue`'s bits if possible - _ => self.val.try_to_bits(size), + _ => self, } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 96e16efd1300a..7a77418050cdb 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -998,7 +998,7 @@ impl<'tcx> ty::TyS<'tcx> { fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); + let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem, None); tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( &infcx, @@ -1011,7 +1011,7 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); + let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem, None); tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( &infcx, @@ -1024,7 +1024,7 @@ fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); + let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem, None); tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( &infcx, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index d32c32af29e0d..d6de217f79c29 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), + def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), substs: self.infcx.tcx.mk_substs_trait(subty, &[]), }; self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 9f68d770b9e87..18d968fbddd9b 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1,13 +1,13 @@ use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO}; use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd}; +use core::cmp::{self, Ordering}; +use core::convert::TryFrom; +use core::fmt::{self, Write}; +use core::marker::PhantomData; +use core::mem; +use core::ops::Neg; use smallvec::{SmallVec, smallvec}; -use std::cmp::{self, Ordering}; -use std::convert::TryFrom; -use std::fmt::{self, Write}; -use std::marker::PhantomData; -use std::mem; -use std::ops::Neg; #[must_use] pub struct IeeeFloat { @@ -2287,8 +2287,8 @@ impl Loss { /// Implementation details of IeeeFloat significands, such as big integer arithmetic. /// As a rule of thumb, no functions in this module should dynamically allocate. mod sig { - use std::cmp::Ordering; - use std::mem; + use core::cmp::Ordering; + use core::mem; use super::{ExpInt, Limb, LIMB_BITS, limbs_for_bits, Loss}; pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool { diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 9e6d5a6f62434..1190cea21acc3 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -31,15 +31,19 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![no_std] #![forbid(unsafe_code)] #![feature(nll)] -use std::cmp::Ordering; -use std::fmt; -use std::ops::{Neg, Add, Sub, Mul, Div, Rem}; -use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; -use std::str::FromStr; +#[macro_use] +extern crate alloc; + +use core::cmp::Ordering; +use core::fmt; +use core::ops::{Neg, Add, Sub, Mul, Div, Rem}; +use core::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; +use core::str::FromStr; bitflags::bitflags! { /// IEEE-754R 7: Default exception handling. @@ -587,7 +591,7 @@ macro_rules! float_common_impls { } } - impl<$t> ::std::str::FromStr for $ty<$t> where Self: Float { + impl<$t> ::core::str::FromStr for $ty<$t> where Self: Float { type Err = ParseError; fn from_str(s: &str) -> Result { Self::from_str_r(s, Round::NearestTiesToEven).map(|x| x.value) @@ -596,66 +600,66 @@ macro_rules! float_common_impls { // Rounding ties to the nearest even, by default. - impl<$t> ::std::ops::Add for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Add for $ty<$t> where Self: Float { type Output = StatusAnd; fn add(self, rhs: Self) -> StatusAnd { self.add_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Sub for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Sub for $ty<$t> where Self: Float { type Output = StatusAnd; fn sub(self, rhs: Self) -> StatusAnd { self.sub_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Mul for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Mul for $ty<$t> where Self: Float { type Output = StatusAnd; fn mul(self, rhs: Self) -> StatusAnd { self.mul_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Div for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Div for $ty<$t> where Self: Float { type Output = StatusAnd; fn div(self, rhs: Self) -> StatusAnd { self.div_r(rhs, Round::NearestTiesToEven) } } - impl<$t> ::std::ops::Rem for $ty<$t> where Self: Float { + impl<$t> ::core::ops::Rem for $ty<$t> where Self: Float { type Output = StatusAnd; fn rem(self, rhs: Self) -> StatusAnd { self.c_fmod(rhs) } } - impl<$t> ::std::ops::AddAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::AddAssign for $ty<$t> where Self: Float { fn add_assign(&mut self, rhs: Self) { *self = (*self + rhs).value; } } - impl<$t> ::std::ops::SubAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::SubAssign for $ty<$t> where Self: Float { fn sub_assign(&mut self, rhs: Self) { *self = (*self - rhs).value; } } - impl<$t> ::std::ops::MulAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::MulAssign for $ty<$t> where Self: Float { fn mul_assign(&mut self, rhs: Self) { *self = (*self * rhs).value; } } - impl<$t> ::std::ops::DivAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::DivAssign for $ty<$t> where Self: Float { fn div_assign(&mut self, rhs: Self) { *self = (*self / rhs).value; } } - impl<$t> ::std::ops::RemAssign for $ty<$t> where Self: Float { + impl<$t> ::core::ops::RemAssign for $ty<$t> where Self: Float { fn rem_assign(&mut self, rhs: Self) { *self = (*self % rhs).value; } diff --git a/src/librustc_apfloat/ppc.rs b/src/librustc_apfloat/ppc.rs index ddccfd6ca623b..8e2e390568e48 100644 --- a/src/librustc_apfloat/ppc.rs +++ b/src/librustc_apfloat/ppc.rs @@ -1,9 +1,9 @@ use crate::{Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd}; use crate::ieee; -use std::cmp::Ordering; -use std::fmt; -use std::ops::Neg; +use core::cmp::Ordering; +use core::fmt; +use core::ops::Neg; #[must_use] #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] diff --git a/src/librustc_ast_borrowck/dataflow.rs b/src/librustc_ast_borrowck/dataflow.rs index 94849728a9319..3a4c8c924764e 100644 --- a/src/librustc_ast_borrowck/dataflow.rs +++ b/src/librustc_ast_borrowck/dataflow.rs @@ -186,8 +186,8 @@ fn build_local_id_to_index(body: Option<&hir::Body>, index: &'a mut FxHashMap>, } let mut formals = Formals { entry: entry, index: index }; - for arg in &body.arguments { - formals.visit_pat(&arg.pat); + for param in &body.params { + formals.visit_pat(¶m.pat); } impl<'a, 'v> Visitor<'v> for Formals<'a> { fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> { diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 5ed08943fe6fd..a43fbb68dbaed 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -183,7 +183,7 @@ pub(crate) fn prepare_thin( fn fat_lto(cgcx: &CodegenContext, diag_handler: &Handler, - mut modules: Vec>, + modules: Vec>, cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char]) @@ -191,6 +191,32 @@ fn fat_lto(cgcx: &CodegenContext, { info!("going for a fat lto"); + // Sort out all our lists of incoming modules into two lists. + // + // * `serialized_modules` (also and argument to this function) contains all + // modules that are serialized in-memory. + // * `in_memory` contains modules which are already parsed and in-memory, + // such as from multi-CGU builds. + // + // All of `cached_modules` (cached from previous incremental builds) can + // immediately go onto the `serialized_modules` modules list and then we can + // split the `modules` array into these two lists. + let mut in_memory = Vec::new(); + serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { + info!("pushing cached module {:?}", wp.cgu_name); + (buffer, CString::new(wp.cgu_name).unwrap()) + })); + for module in modules { + match module { + FatLTOInput::InMemory(m) => in_memory.push(m), + FatLTOInput::Serialized { name, buffer } => { + info!("pushing serialized module {:?}", name); + let buffer = SerializedModule::Local(buffer); + serialized_modules.push((buffer, CString::new(name).unwrap())); + } + } + } + // Find the "costliest" module and merge everything into that codegen unit. // All the other modules will be serialized and reparsed into the new // context, so this hopefully avoids serializing and parsing the largest @@ -200,14 +226,8 @@ fn fat_lto(cgcx: &CodegenContext, // file copy operations in the backend work correctly. The only other kind // of module here should be an allocator one, and if your crate is smaller // than the allocator module then the size doesn't really matter anyway. - let costliest_module = modules.iter() + let costliest_module = in_memory.iter() .enumerate() - .filter_map(|(i, module)| { - match module { - FatLTOInput::InMemory(m) => Some((i, m)), - FatLTOInput::Serialized { .. } => None, - } - }) .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, module)| { let cost = unsafe { @@ -223,26 +243,14 @@ fn fat_lto(cgcx: &CodegenContext, // re-executing the LTO passes. If that's the case deserialize the first // module and create a linker with it. let module: ModuleCodegen = match costliest_module { - Some((_cost, i)) => { - match modules.remove(i) { - FatLTOInput::InMemory(m) => m, - FatLTOInput::Serialized { .. } => unreachable!(), - } - } + Some((_cost, i)) => in_memory.remove(i), None => { - let pos = modules.iter().position(|m| { - match m { - FatLTOInput::InMemory(_) => false, - FatLTOInput::Serialized { .. } => true, - } - }).expect("must have at least one serialized module"); - let (name, buffer) = match modules.remove(pos) { - FatLTOInput::Serialized { name, buffer } => (name, buffer), - FatLTOInput::InMemory(_) => unreachable!(), - }; + assert!(serialized_modules.len() > 0, "must have at least one serialized module"); + let (buffer, name) = serialized_modules.remove(0); + info!("no in-memory regular modules to choose from, parsing {:?}", name); ModuleCodegen { - module_llvm: ModuleLlvm::parse(cgcx, &name, &buffer, diag_handler)?, - name, + module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), diag_handler)?, + name: name.into_string().unwrap(), kind: ModuleKind::Regular, } } @@ -265,25 +273,13 @@ fn fat_lto(cgcx: &CodegenContext, // and we want to move everything to the same LLVM context. Currently the // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? - let mut new_modules = modules.into_iter().map(|module| { - match module { - FatLTOInput::InMemory(module) => { - let buffer = ModuleBuffer::new(module.module_llvm.llmod()); - let llmod_id = CString::new(&module.name[..]).unwrap(); - (SerializedModule::Local(buffer), llmod_id) - } - FatLTOInput::Serialized { name, buffer } => { - let llmod_id = CString::new(name).unwrap(); - (SerializedModule::Local(buffer), llmod_id) - } - } - }).collect::>(); + for module in in_memory { + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + let llmod_id = CString::new(&module.name[..]).unwrap(); + serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); + } // Sort the modules to ensure we produce deterministic results. - new_modules.sort_by(|module1, module2| module1.1.partial_cmp(&module2.1).unwrap()); - serialized_modules.extend(new_modules); - serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { - (buffer, CString::new(wp.cgu_name).unwrap()) - })); + serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1)); // For all serialized bitcode files we parse them and link them in as we did // above, this is all mostly handled in C++. Like above, though, we don't @@ -850,7 +846,7 @@ fn module_name_to_str(c_str: &CStr) -> &str { bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e)) } -fn parse_module<'a>( +pub fn parse_module<'a>( cx: &'a llvm::Context, name: &CStr, data: &[u8], diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 0077df3cf5eea..958666cb8858a 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -25,21 +25,31 @@ use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags}; use std::ffi::{CStr, CString}; pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { - let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); + let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); let dl = cx.data_layout(); let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, ((), alloc_id)) in alloc.relocations.iter() { + for &(offset, ((), alloc_id)) in alloc.relocations().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { - llvals.push(cx.const_bytes(&alloc.bytes[next_offset..offset])); + // This `inspect` is okay since we have checked that it is not within a relocation, it + // is within the bounds of the allocation, and it doesn't affect interpreter execution + // (we inspect the result after interpreter execution). Any undef byte is replaced with + // some arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset); + llvals.push(cx.const_bytes(bytes)); } let ptr_offset = read_target_uint( dl.endian, - &alloc.bytes[offset..(offset + pointer_size)], + // This `inspect` is okay since it is within the bounds of the allocation, it doesn't + // affect interpreter execution (we inspect the result after interpreter execution), + // and we properly interpret the relocation as a relocation pointer offset. + alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)), ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(cx.scalar_to_backend( Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), @@ -51,8 +61,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll )); next_offset = offset + pointer_size; } - if alloc.bytes.len() >= next_offset { - llvals.push(cx.const_bytes(&alloc.bytes[next_offset ..])); + if alloc.len() >= next_offset { + let range = next_offset..alloc.len(); + // This `inspect` is okay since we have check that it is after all relocations, it is + // within the bounds of the allocation, and it doesn't affect interpreter execution (we + // inspect the result after interpreter execution). Any undef byte is replaced with some + // arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range); + llvals.push(cx.const_bytes(bytes)); } cx.const_struct(&llvals, true) @@ -437,7 +455,23 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // // We could remove this hack whenever we decide to drop macOS 10.10 support. if self.tcx.sess.target.target.options.is_like_osx { - let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { + assert_eq!(alloc.relocations().len(), 0); + + let is_zeroed = { + // Treats undefined bytes as if they were defined with the byte value that + // happens to be currently assigned in mir. This is valid since reading + // undef bytes may yield arbitrary values. + // + // FIXME: ignore undef bytes even with representation `!= 0`. + // + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state + // (not as part of the interpreter execution). + alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len()) + .iter() + .all(|b| *b == 0) + }; + let sect_name = if is_zeroed { CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") } else { CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") @@ -456,10 +490,17 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { section.as_str().as_ptr() as *const _, section.as_str().len() as c_uint, ); + assert!(alloc.relocations().is_empty()); + + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state (not + // as part of the interpreter execution). + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter( + 0..alloc.len()); let alloc = llvm::LLVMMDStringInContext( self.llcx, - alloc.bytes.as_ptr() as *const _, - alloc.bytes.len() as c_uint, + bytes.as_ptr() as *const _, + bytes.len() as c_uint, ); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 51e789b17880a..928532a1f4760 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -683,11 +683,13 @@ pub fn type_metadata( } ty::Closure(def_id, substs) => { let upvar_tys : Vec<_> = substs.upvar_tys(def_id, cx.tcx).collect(); + let containing_scope = get_namespace_for_item(cx, def_id); prepare_tuple_metadata(cx, t, &upvar_tys, unique_type_id, - usage_site_span).finalize(cx) + usage_site_span, + Some(containing_scope)).finalize(cx) } ty::Generator(def_id, substs, _) => { let upvar_tys : Vec<_> = substs.prefix_tys(def_id, cx.tcx).map(|t| { @@ -728,7 +730,8 @@ pub fn type_metadata( t, &tys, unique_type_id, - usage_site_span).finalize(cx) + usage_site_span, + NO_SCOPE_METADATA).finalize(cx) } _ => { bug!("debuginfo: unexpected type in type_metadata: {:?}", t) @@ -1205,6 +1208,7 @@ fn prepare_tuple_metadata( component_types: &[Ty<'tcx>], unique_type_id: UniqueTypeId, span: Span, + containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); @@ -1212,7 +1216,7 @@ fn prepare_tuple_metadata( tuple_type, &tuple_name[..], unique_type_id, - NO_SCOPE_METADATA); + containing_scope); create_and_register_recursive_type_forward_declaration( cx, diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 653dd8868f479..2fd78885bd01e 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -54,6 +54,7 @@ use syntax_pos::symbol::InternedString; pub use llvm_util::target_features; use std::any::Any; use std::sync::{mpsc, Arc}; +use std::ffi::CStr; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; @@ -386,13 +387,13 @@ impl ModuleLlvm { fn parse( cgcx: &CodegenContext, - name: &str, - buffer: &back::lto::ModuleBuffer, + name: &CStr, + buffer: &[u8], handler: &Handler, ) -> Result { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = buffer.parse(name, llcx, handler)?; + let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; let tm = match (cgcx.tm_factory.0)() { Ok(m) => m, Err(e) => { diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 26091005f25aa..de481d2262478 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -430,10 +430,13 @@ impl<'a> Linker for GccLinker<'a> { // Write an LD version script let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); - writeln!(f, "{{\n global:")?; - for sym in self.info.exports[&crate_type].iter() { - debug!(" {};", sym); - writeln!(f, " {};", sym)?; + writeln!(f, "{{")?; + if !self.info.exports[&crate_type].is_empty() { + writeln!(f, " global:")?; + for sym in self.info.exports[&crate_type].iter() { + debug!(" {};", sym); + writeln!(f, " {};", sym)?; + } } writeln!(f, "\n local:\n *;\n}};")?; }; diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index cdc54bb179ebf..4acbe0356b47c 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -456,7 +456,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &' let arg_argv = param_argv; let (start_fn, args) = if use_start_lang_item { - let start_def_id = cx.tcx().require_lang_item(StartFnLangItem); + let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None); let start_fn = callee::resolve_and_get_fn( cx, start_def_id, diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index ea39913d4b91b..9b5ad94ecd7cb 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -190,11 +190,17 @@ pub fn push_debuginfo_type_name<'tcx>( // processing visited.remove(t); }, - ty::Closure(..) => { - output.push_str("closure"); + ty::Closure(def_id, ..) => { + output.push_str(&format!( + "closure-{}", + tcx.def_key(def_id).disambiguated_data.disambiguator + )); } - ty::Generator(..) => { - output.push_str("generator"); + ty::Generator(def_id, ..) => { + output.push_str(&format!( + "generator-{}", + tcx.def_key(def_id).disambiguated_data.disambiguator + )); } ty::Error | ty::Infer(_) | diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index dbce5ce4896a7..d2a7571fde1e2 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -609,8 +609,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Operand::Copy( Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), + kind: StaticKind::Promoted(promoted, _), ty, + def_id: _, }), projection: None, } @@ -618,8 +619,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Operand::Move( Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), + kind: StaticKind::Promoted(promoted, _), ty, + def_id: _, }), projection: None, } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index a632838ba2442..ac72928a89677 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -1,4 +1,4 @@ -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Instance, Ty}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::mir; use rustc::mir::tcx::PlaceTy; @@ -454,13 +454,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::PlaceRef { base: mir::PlaceBase::Static(box mir::Static { ty, - kind: mir::StaticKind::Promoted(promoted), + kind: mir::StaticKind::Promoted(promoted, substs), + def_id, }), projection: None, } => { let param_env = ty::ParamEnv::reveal_all(); + let instance = Instance::new(*def_id, self.monomorphize(substs)); let cid = mir::interpret::GlobalId { - instance: self.instance, + instance: instance, promoted: Some(*promoted), }; let layout = cx.layout_of(self.monomorphize(&ty)); @@ -487,7 +489,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::PlaceRef { base: mir::PlaceBase::Static(box mir::Static { ty, - kind: mir::StaticKind::Static(def_id), + kind: mir::StaticKind::Static, + def_id, }), projection: None, } => { diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index 1c0d9360f2511..ea771d9f20f8b 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -20,7 +20,6 @@ pub struct TinyList { } impl TinyList { - #[inline] pub fn new() -> TinyList { TinyList { @@ -60,20 +59,24 @@ impl TinyList { #[inline] pub fn contains(&self, data: &T) -> bool { - if let Some(ref head) = self.head { - head.contains(data) - } else { - false + let mut elem = self.head.as_ref(); + while let Some(ref e) = elem { + if &e.data == data { + return true; + } + elem = e.next.as_ref().map(|e| &**e); } + false } #[inline] pub fn len(&self) -> usize { - if let Some(ref head) = self.head { - head.len() - } else { - 0 + let (mut elem, mut count) = (self.head.as_ref(), 0); + while let Some(ref e) = elem { + count += 1; + elem = e.next.as_ref().map(|e| &**e); } + count } } @@ -84,40 +87,13 @@ struct Element { } impl Element { - fn remove_next(&mut self, data: &T) -> bool { - let new_next = if let Some(ref mut next) = self.next { - if next.data != *data { - return next.remove_next(data) - } else { - next.next.take() - } - } else { - return false + let new_next = match self.next { + Some(ref mut next) if next.data == *data => next.next.take(), + Some(ref mut next) => return next.remove_next(data), + None => return false, }; - self.next = new_next; - true } - - fn len(&self) -> usize { - if let Some(ref next) = self.next { - 1 + next.len() - } else { - 1 - } - } - - fn contains(&self, data: &T) -> bool { - if self.data == *data { - return true - } - - if let Some(ref next) = self.next { - next.contains(data) - } else { - false - } - } } diff --git a/src/librustc_data_structures/tiny_list/tests.rs b/src/librustc_data_structures/tiny_list/tests.rs index 8374659e1e67b..0142631590cc9 100644 --- a/src/librustc_data_structures/tiny_list/tests.rs +++ b/src/librustc_data_structures/tiny_list/tests.rs @@ -1,7 +1,7 @@ use super::*; extern crate test; -use test::Bencher; +use test::{Bencher, black_box}; #[test] fn test_contains_and_insert() { @@ -98,36 +98,59 @@ fn test_remove_single() { #[bench] fn bench_insert_empty(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new(); + let mut list = black_box(TinyList::new()); list.insert(1); + list }) } #[bench] fn bench_insert_one(b: &mut Bencher) { b.iter(|| { - let mut list = TinyList::new_single(0); + let mut list = black_box(TinyList::new_single(0)); list.insert(1); + list }) } +#[bench] +fn bench_contains_empty(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new()).contains(&1) + }); +} + +#[bench] +fn bench_contains_unknown(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(0)).contains(&1) + }); +} + +#[bench] +fn bench_contains_one(b: &mut Bencher) { + b.iter(|| { + black_box(TinyList::new_single(1)).contains(&1) + }); +} + #[bench] fn bench_remove_empty(b: &mut Bencher) { b.iter(|| { - TinyList::new().remove(&1) + black_box(TinyList::new()).remove(&1) }); } #[bench] fn bench_remove_unknown(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(0).remove(&1) + black_box(TinyList::new_single(0)).remove(&1) }); } #[bench] fn bench_remove_one(b: &mut Bencher) { b.iter(|| { - TinyList::new_single(1).remove(&1) + black_box(TinyList::new_single(1)).remove(&1) }); } diff --git a/src/librustc_driver/args.rs b/src/librustc_driver/args.rs new file mode 100644 index 0000000000000..0906d358badd4 --- /dev/null +++ b/src/librustc_driver/args.rs @@ -0,0 +1,53 @@ +use std::error; +use std::fmt; +use std::fs; +use std::io; +use std::str; +use std::sync::atomic::{AtomicBool, Ordering}; + +static USED_ARGSFILE_FEATURE: AtomicBool = AtomicBool::new(false); + +pub fn used_unstable_argsfile() -> bool { + USED_ARGSFILE_FEATURE.load(Ordering::Relaxed) +} + +pub fn arg_expand(arg: String) -> Result, Error> { + if arg.starts_with("@") { + let path = &arg[1..]; + let file = match fs::read_to_string(path) { + Ok(file) => { + USED_ARGSFILE_FEATURE.store(true, Ordering::Relaxed); + file + } + Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { + return Err(Error::Utf8Error(Some(path.to_string()))); + } + Err(err) => return Err(Error::IOError(path.to_string(), err)), + }; + Ok(file.lines().map(ToString::to_string).collect()) + } else { + Ok(vec![arg]) + } +} + +#[derive(Debug)] +pub enum Error { + Utf8Error(Option), + IOError(String, io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Utf8Error(None) => write!(fmt, "Utf8 error"), + Error::Utf8Error(Some(path)) => write!(fmt, "Utf8 error in {}", path), + Error::IOError(path, err) => write!(fmt, "IO Error: {}: {}", path, err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &'static str { + "argument error" + } +} diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b19ea513b7575..9a6a12e261c10 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -68,6 +68,7 @@ use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; pub mod pretty; +mod args; /// Exit status code used for successful compilation and help output. pub const EXIT_SUCCESS: i32 = 0; @@ -141,14 +142,22 @@ impl Callbacks for TimePassesCallbacks { // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. pub fn run_compiler( - args: &[String], + at_args: &[String], callbacks: &mut (dyn Callbacks + Send), file_loader: Option>, emitter: Option> ) -> interface::Result<()> { + let mut args = Vec::new(); + for arg in at_args { + match args::arg_expand(arg.clone()) { + Ok(arg) => args.extend(arg), + Err(err) => early_error(ErrorOutputType::default(), + &format!("Failed to load argument file: {}", err)), + } + } let diagnostic_output = emitter.map(|emitter| DiagnosticOutput::Raw(emitter)) .unwrap_or(DiagnosticOutput::Default); - let matches = match handle_options(args) { + let matches = match handle_options(&args) { Some(matches) => matches, None => return Ok(()), }; @@ -430,6 +439,15 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option, Option } else { None }; + if let Ok(path) = env::var("UNSTABLE_RUSTDOC_TEST_PATH") { + let line = env::var("UNSTABLE_RUSTDOC_TEST_LINE"). + expect("when UNSTABLE_RUSTDOC_TEST_PATH is set \ + UNSTABLE_RUSTDOC_TEST_LINE also needs to be set"); + let line = isize::from_str_radix(&line, 10). + expect("UNSTABLE_RUSTDOC_TEST_LINE needs to be an number"); + let file_name = FileName::doc_test_source_code(PathBuf::from(path), line); + return Some((Input::Str { name: file_name, input: src }, None, err)); + } Some((Input::Str { name: FileName::anon_source_code(&src), input: src }, None, err)) } else { @@ -779,13 +797,19 @@ fn usage(verbose: bool, include_unstable_options: bool) { } else { "\n --help -v Print the full set of options rustc accepts" }; - println!("{}\nAdditional help: + let at_path = if verbose && nightly_options::is_nightly_build() { + " @path Read newline separated options from `path`\n" + } else { + "" + }; + println!("{options}{at_path}\nAdditional help: -C help Print codegen options -W help \ - Print 'lint' options and default settings{}{}\n", - options.usage(message), - nightly_help, - verbose_help); + Print 'lint' options and default settings{nightly}{verbose}\n", + options = options.usage(message), + at_path = at_path, + nightly = nightly_help, + verbose = verbose_help); } fn print_wall_help() { @@ -1010,6 +1034,12 @@ pub fn handle_options(args: &[String]) -> Option { // (unstable option being used on stable) nightly_options::check_nightly_options(&matches, &config::rustc_optgroups()); + // Late check to see if @file was used without unstable options enabled + if crate::args::used_unstable_argsfile() && !nightly_options::is_unstable_enabled(&matches) { + early_error(ErrorOutputType::default(), + "@path is unstable - use -Z unstable-options to enable its use"); + } + if matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. usage(matches.opt_present("verbose"), nightly_options::is_unstable_enabled(&matches)); @@ -1135,11 +1165,13 @@ pub fn report_ices_to_stderr_if_any R, R>(f: F) -> Result>(); diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index 32f121f18f689..1541845bb55f6 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -18,3 +18,4 @@ unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" annotate-snippets = "0.6.1" +term_size = "0.3.1" diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index 255af3122e70c..3bed5d81dc514 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -30,10 +30,8 @@ pub struct AnnotateSnippetEmitterWriter { impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { - let primary_span = db.span.clone(); let children = db.children.clone(); - // FIXME(#59346): Collect suggestions (see emitter.rs) - let suggestions: &[_] = &[]; + let (primary_span, suggestions) = self.primary_span_formatted(&db); // FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 361b5cd935712..a298f9958f2d1 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -24,7 +24,7 @@ use rustc_data_structures::sync::Lrc; use std::borrow::Cow; use std::io::prelude::*; use std::io; -use std::cmp::{min, Reverse}; +use std::cmp::{min, max, Reverse}; use std::path::Path; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; @@ -51,9 +51,127 @@ impl HumanReadableErrorType { dst: Box, source_map: Option>, teach: bool, + terminal_width: Option, ) -> EmitterWriter { let (short, color_config) = self.unzip(); - EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + let color = color_config.suggests_using_colors(); + EmitterWriter::new(dst, source_map, short, teach, color, terminal_width) + } +} + +#[derive(Clone, Copy, Debug)] +struct Margin { + /// The available whitespace in the left that can be consumed when centering. + pub whitespace_left: usize, + /// The column of the beginning of left-most span. + pub span_left: usize, + /// The column of the end of right-most span. + pub span_right: usize, + /// The beginning of the line to be displayed. + pub computed_left: usize, + /// The end of the line to be displayed. + pub computed_right: usize, + /// The current width of the terminal. 140 by default and in tests. + pub column_width: usize, + /// The end column of a span label, including the span. Doesn't account for labels not in the + /// same line as the span. + pub label_right: usize, +} + +impl Margin { + fn new( + whitespace_left: usize, + span_left: usize, + span_right: usize, + label_right: usize, + column_width: usize, + max_line_len: usize, + ) -> Self { + // The 6 is padding to give a bit of room for `...` when displaying: + // ``` + // error: message + // --> file.rs:16:58 + // | + // 16 | ... fn foo(self) -> Self::Bar { + // | ^^^^^^^^^ + // ``` + + let mut m = Margin { + whitespace_left: if whitespace_left >= 6 { whitespace_left - 6 } else { 0 }, + span_left: if span_left >= 6 { span_left - 6 } else { 0 }, + span_right: span_right + 6, + computed_left: 0, + computed_right: 0, + column_width, + label_right: label_right + 6, + }; + m.compute(max_line_len); + m + } + + fn was_cut_left(&self) -> bool { + self.computed_left > 0 + } + + fn was_cut_right(&self, line_len: usize) -> bool { + let right = if self.computed_right == self.span_right || + self.computed_right == self.label_right + { + // Account for the "..." padding given above. Otherwise we end up with code lines that + // do fit but end in "..." as if they were trimmed. + self.computed_right - 6 + } else { + self.computed_right + }; + right < line_len && line_len > self.computed_left + self.column_width + } + + fn compute(&mut self, max_line_len: usize) { + // When there's a lot of whitespace (>20), we want to trim it as it is useless. + self.computed_left = if self.whitespace_left > 20 { + self.whitespace_left - 16 // We want some padding. + } else { + 0 + }; + // We want to show as much as possible, max_line_len is the right-most boundary for the + // relevant code. + self.computed_right = max(max_line_len, self.computed_left); + + if self.computed_right - self.computed_left > self.column_width { + // Trimming only whitespace isn't enough, let's get craftier. + if self.label_right - self.whitespace_left <= self.column_width { + // Attempt to fit the code window only trimming whitespace. + self.computed_left = self.whitespace_left; + self.computed_right = self.computed_left + self.column_width; + } else if self.label_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering only the spans and labels. + let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else if self.span_right - self.span_left <= self.column_width { + // Attempt to fit the code window considering the spans and labels plus padding. + let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2; + self.computed_left = self.span_left.saturating_sub(padding_left); + self.computed_right = self.computed_left + self.column_width; + } else { // Mostly give up but still don't show the full line. + self.computed_left = self.span_left; + self.computed_right = self.span_right; + } + } + } + + fn left(&self, line_len: usize) -> usize { + min(self.computed_left, line_len) + } + + fn right(&self, line_len: usize) -> usize { + if max(line_len, self.computed_left) - self.computed_left <= self.column_width { + line_len + } else if self.computed_right > line_len { + line_len + } else { + self.computed_right + } } } @@ -73,16 +191,25 @@ pub trait Emitter { fn should_show_explain(&self) -> bool { true } -} -impl Emitter for EmitterWriter { - fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + /// Formats the substitutions of the primary_span + /// + /// The are a lot of conditions to this method, but in short: + /// + /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, + /// we format the `help` suggestion depending on the content of the + /// substitutions. In that case, we return the modified span only. + /// + /// * If the current `Diagnostic` has multiple suggestions, + /// we return the original `primary_span` and the original suggestions. + fn primary_span_formatted<'a>( + &mut self, + db: &'a DiagnosticBuilder<'_> + ) -> (MultiSpan, &'a [CodeSuggestion]) { let mut primary_span = db.span.clone(); - let mut children = db.children.clone(); - let mut suggestions: &[_] = &[]; - if let Some((sugg, rest)) = db.suggestions.split_first() { if rest.is_empty() && + // ^ if there is only one suggestion // don't display multi-suggestions as labels sugg.substitutions.len() == 1 && // don't display multipart suggestions as labels @@ -98,21 +225,34 @@ impl Emitter for EmitterWriter { { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); let msg = if substitution.len() == 0 || sugg.style.hide_inline() { - // This substitution is only removal or we explicitly don't want to show the - // code inline, don't show it + // This substitution is only removal OR we explicitly don't want to show the + // code inline (`hide_inline`). Therefore, we don't show the substitution. format!("help: {}", sugg.msg) } else { + // Show the default suggestion text with the substitution format!("help: {}: `{}`", sugg.msg, substitution) }; primary_span.push_span_label(sugg.substitutions[0].parts[0].span, msg); + + // We return only the modified primary_span + (primary_span, &[]) } else { // if there are multiple suggestions, print them all in full // to be consistent. We could try to figure out if we can // make one (or the first one) inline, but that would give // undue importance to a semi-random suggestion - suggestions = &db.suggestions; + (primary_span, &db.suggestions) } + } else { + (primary_span, &db.suggestions) } + } +} + +impl Emitter for EmitterWriter { + fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { + let mut children = db.children.clone(); + let (mut primary_span, suggestions) = self.primary_span_formatted(&db); self.fix_multispans_in_std_macros(&mut primary_span, &mut children, @@ -180,6 +320,7 @@ pub struct EmitterWriter { short_message: bool, teach: bool, ui_testing: bool, + terminal_width: Option, } #[derive(Debug)] @@ -190,11 +331,13 @@ pub struct FileWithAnnotatedLines { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, - source_map: Option>, - short_message: bool, - teach: bool) - -> EmitterWriter { + pub fn stderr( + color_config: ColorConfig, + source_map: Option>, + short_message: bool, + teach: bool, + terminal_width: Option, + ) -> EmitterWriter { let dst = Destination::from_stderr(color_config); EmitterWriter { dst, @@ -202,6 +345,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -211,6 +355,7 @@ impl EmitterWriter { short_message: bool, teach: bool, colored: bool, + terminal_width: Option, ) -> EmitterWriter { EmitterWriter { dst: Raw(dst, colored), @@ -218,6 +363,7 @@ impl EmitterWriter { short_message, teach, ui_testing: false, + terminal_width, } } @@ -234,12 +380,70 @@ impl EmitterWriter { } } - fn render_source_line(&self, - buffer: &mut StyledBuffer, - file: Lrc, - line: &Line, - width_offset: usize, - code_offset: usize) -> Vec<(usize, Style)> { + fn draw_line( + &self, + buffer: &mut StyledBuffer, + source_string: &str, + line_index: usize, + line_offset: usize, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) { + let line_len = source_string.len(); + // Create the source line we will highlight. + let left = margin.left(line_len); + let right = margin.right(line_len); + // On long lines, we strip the source line, accounting for unicode. + let mut taken = 0; + let code: String = source_string.chars().skip(left).take_while(|ch| { + // Make sure that the trimming on the right will fall within the terminal width. + // FIXME: `unicode_width` sometimes disagrees with terminals on how wide a `char` is. + // For now, just accept that sometimes the code line will be longer than desired. + let next = unicode_width::UnicodeWidthChar::width(*ch).unwrap_or(1); + if taken + next > right - left { + return false; + } + taken += next; + true + }).collect(); + buffer.puts(line_offset, code_offset, &code, Style::Quotation); + if margin.was_cut_left() { + // We have stripped some code/whitespace from the beginning, make it clear. + buffer.puts(line_offset, code_offset, "...", Style::LineNumber); + } + if margin.was_cut_right(line_len) { + // We have stripped some code after the right-most span end, make it clear we did so. + buffer.puts(line_offset, code_offset + taken - 3, "...", Style::LineNumber); + } + buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); + + draw_col_separator(buffer, line_offset, width_offset - 2); + } + + fn render_source_line( + &self, + buffer: &mut StyledBuffer, + file: Lrc, + line: &Line, + width_offset: usize, + code_offset: usize, + margin: Margin, + ) -> Vec<(usize, Style)> { + // Draw: + // + // LL | ... code ... + // | ^^-^ span label + // | | + // | secondary span label + // + // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it + // | | | | + // | | | actual code found in your source code and the spans we use to mark it + // | | when there's too much wasted space to the left, trim it + // | vertical divider between the column number and the code + // column number + if line.line_index == 0 { return Vec::new(); } @@ -251,14 +455,21 @@ impl EmitterWriter { let line_offset = buffer.num_lines(); - // First create the source line we will highlight. - buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); - buffer.puts(line_offset, - 0, - &self.maybe_anonymized(line.line_index), - Style::LineNumber); + let left = margin.left(source_string.len()); // Left trim + // Account for unicode characters of width !=0 that were removed. + let left = source_string.chars().take(left).fold(0, |acc, ch| { + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) + }); - draw_col_separator(buffer, line_offset, width_offset - 2); + self.draw_line( + buffer, + &source_string, + line.line_index, + line_offset, + width_offset, + code_offset, + margin, + ); // Special case when there's only one annotation involved, it is the start of a multiline // span and there's no text at the beginning of the code line. Instead of doing the whole @@ -279,18 +490,13 @@ impl EmitterWriter { if line.annotations.len() == 1 { if let Some(ref ann) = line.annotations.get(0) { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars() - .take(ann.start_col) - .all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) { let style = if ann.is_primary { Style::UnderlinePrimary } else { Style::UnderlineSecondary }; - buffer.putc(line_offset, - width_offset + depth - 1, - '/', - style); + buffer.putc(line_offset, width_offset + depth - 1, '/', style); return vec![(depth, style)]; } } @@ -511,19 +717,23 @@ impl EmitterWriter { match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { - draw_range(buffer, - '_', - line_offset + pos, - width_offset + depth, - code_offset + annotation.start_col, - style); + draw_range( + buffer, + '_', + line_offset + pos, + width_offset + depth, + code_offset + annotation.start_col - left, + style, + ); } _ if self.teach => { - buffer.set_style_range(line_offset, - code_offset + annotation.start_col, - code_offset + annotation.end_col, - style, - annotation.is_primary); + buffer.set_style_range( + line_offset, + code_offset + annotation.start_col - left, + code_offset + annotation.end_col - left, + style, + annotation.is_primary, + ); } _ => {} } @@ -551,7 +761,7 @@ impl EmitterWriter { if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc(p, - code_offset + annotation.start_col, + code_offset + annotation.start_col - margin.computed_left, '|', style); } @@ -595,15 +805,20 @@ impl EmitterWriter { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - (pos + 1, annotation.end_col + 1) + (pos + 1, if annotation.end_col + 1 > left { + annotation.end_col + 1 - left + } else { + 0 + }) } else { - (pos + 2, annotation.start_col) + (pos + 2, if annotation.start_col > left { + annotation.start_col - left + } else { + 0 + }) }; if let Some(ref label) = annotation.label { - buffer.puts(line_offset + pos, - code_offset + col, - &label, - style); + buffer.puts(line_offset + pos, code_offset + col, &label, style); } } @@ -638,10 +853,16 @@ impl EmitterWriter { ('-', Style::UnderlineSecondary) }; for p in annotation.start_col..annotation.end_col { - buffer.putc(line_offset + 1, - code_offset + p, - underline, - style); + buffer.putc( + line_offset + 1, + if code_offset + p > left { + code_offset + p - left + } else { + 0 + }, + underline, + style, + ); } } annotations_position.iter().filter_map(|&(_, annotation)| { @@ -979,22 +1200,30 @@ impl EmitterWriter { let buffer_msg_line_offset = buffer.num_lines(); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); - buffer.append(buffer_msg_line_offset, - &format!("{}:{}:{}", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.append( + buffer_msg_line_offset, + &format!( + "{}:{}:{}", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } } else { - buffer.prepend(0, - &format!("{}:{}:{}: ", - loc.file.name, - sm.doctest_offset_line(&loc.file.name, loc.line), - loc.col.0 + 1), - Style::LineAndColumn); + buffer.prepend( + 0, + &format!( + "{}:{}:{}: ", + loc.file.name, + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); } } else if !self.short_message { // remember where we are in the output buffer for easy reference @@ -1037,22 +1266,96 @@ impl EmitterWriter { // Contains the vertical lines' positions for active multiline annotations let mut multilines = FxHashMap::default(); + // Get the left-side margin to remove it + let mut whitespace_margin = std::usize::MAX; + for line_idx in 0..annotated_file.lines.len() { + let file = annotated_file.file.clone(); + let line = &annotated_file.lines[line_idx]; + if let Some(source_string) = file.get_line(line.line_index - 1) { + let leading_whitespace = source_string + .chars() + .take_while(|c| c.is_whitespace()) + .count(); + if source_string.chars().any(|c| !c.is_whitespace()) { + whitespace_margin = min( + whitespace_margin, + leading_whitespace, + ); + } + } + } + if whitespace_margin == std::usize::MAX { + whitespace_margin = 0; + } + + // Left-most column any visible span points at. + let mut span_left_margin = std::usize::MAX; + for line in &annotated_file.lines { + for ann in &line.annotations { + span_left_margin = min(span_left_margin, ann.start_col); + span_left_margin = min(span_left_margin, ann.end_col); + } + } + if span_left_margin == std::usize::MAX { + span_left_margin = 0; + } + + // Right-most column any visible span points at. + let mut span_right_margin = 0; + let mut label_right_margin = 0; + let mut max_line_len = 0; + for line in &annotated_file.lines { + max_line_len = max(max_line_len, annotated_file.file + .get_line(line.line_index - 1) + .map(|s| s.len()) + .unwrap_or(0)); + for ann in &line.annotations { + span_right_margin = max(span_right_margin, ann.start_col); + span_right_margin = max(span_right_margin, ann.end_col); + // FIXME: account for labels not in the same line + let label_right = ann.label.as_ref().map(|l| l.len() + 1).unwrap_or(0); + label_right_margin = max(label_right_margin, ann.end_col + label_right); + } + } + + let width_offset = 3 + max_line_num_len; + let code_offset = if annotated_file.multiline_depth == 0 { + width_offset + } else { + width_offset + annotated_file.multiline_depth + 1 + }; + + let column_width = if let Some(width) = self.terminal_width { + width.saturating_sub(code_offset) + } else if self.ui_testing { + 140 + } else { + term_size::dimensions() + .map(|(w, _)| w.saturating_sub(code_offset)) + .unwrap_or(std::usize::MAX) + }; + + let margin = Margin::new( + whitespace_margin, + span_left_margin, + span_right_margin, + label_right_margin, + column_width, + max_line_len, + ); + // Next, output the annotate source for this file for line_idx in 0..annotated_file.lines.len() { let previous_buffer_line = buffer.num_lines(); - let width_offset = 3 + max_line_num_len; - let code_offset = if annotated_file.multiline_depth == 0 { - width_offset - } else { - width_offset + annotated_file.multiline_depth + 1 - }; - - let depths = self.render_source_line(&mut buffer, - annotated_file.file.clone(), - &annotated_file.lines[line_idx], - width_offset, - code_offset); + let depths = self.render_source_line( + &mut buffer, + annotated_file.file.clone(), + &annotated_file.lines[line_idx], + width_offset, + code_offset, + margin, + ); let mut to_add = FxHashMap::default(); @@ -1099,25 +1402,24 @@ impl EmitterWriter { let last_buffer_line_num = buffer.num_lines(); - buffer.puts(last_buffer_line_num, - 0, - &self.maybe_anonymized(annotated_file.lines[line_idx + 1] - .line_index - 1), - Style::LineNumber); - draw_col_separator(&mut buffer, - last_buffer_line_num, - 1 + max_line_num_len); - buffer.puts(last_buffer_line_num, - code_offset, - &unannotated_line, - Style::Quotation); + self.draw_line( + &mut buffer, + &unannotated_line, + annotated_file.lines[line_idx + 1].line_index - 1, + last_buffer_line_num, + width_offset, + code_offset, + margin, + ); for (depth, style) in &multilines { - draw_multiline_line(&mut buffer, - last_buffer_line_num, - width_offset, - *depth, - *style); + draw_multiline_line( + &mut buffer, + last_buffer_line_num, + width_offset, + *depth, + *style, + ); } } } @@ -1207,7 +1509,7 @@ impl EmitterWriter { // ...or trailing spaces. Account for substitutions containing unicode // characters. let sub_len = part.snippet.trim().chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) }); let underline_start = (span_start_pos + start) as isize + offset; @@ -1230,7 +1532,7 @@ impl EmitterWriter { // length of the code after substitution let full_sub_len = part.snippet.chars().fold(0, |acc, ch| { - acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) as isize + acc + unicode_width::UnicodeWidthChar::width(ch).unwrap_or(1) as isize }); // length of the code to be substituted diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4018a667bf264..6585633e00af8 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -383,7 +383,7 @@ impl Handler { cm: Option>, flags: HandlerFlags) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false)); + let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false, None)); Handler::with_emitter_and_flags(emitter, flags) } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index e569a9bc7df40..837aa9360c895 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -24,6 +24,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; use rustc::ich::{ATTR_DIRTY, ATTR_CLEAN}; use rustc::ty::TyCtxt; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashSet; use syntax::ast::{self, Attribute, NestedMetaItem}; use syntax::symbol::{Symbol, sym}; @@ -71,6 +72,7 @@ const BASE_IMPL: &[&str] = &[ /// code, i.e., functions+methods const BASE_MIR: &[&str] = &[ label_strs::optimized_mir, + label_strs::promoted_mir, label_strs::mir_built, ]; @@ -472,11 +474,10 @@ impl DirtyCleanVisitor<'tcx> { fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { debug!("assert_dirty({:?})", dep_node); - let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); + let current_fingerprint = self.get_fingerprint(&dep_node); let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); - if Some(current_fingerprint) == prev_fingerprint { + if current_fingerprint == prev_fingerprint { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, @@ -484,14 +485,28 @@ impl DirtyCleanVisitor<'tcx> { } } + fn get_fingerprint(&self, dep_node: &DepNode) -> Option { + if self.tcx.dep_graph.dep_node_exists(dep_node) { + let dep_node_index = self.tcx.dep_graph.dep_node_index_of(dep_node); + Some(self.tcx.dep_graph.fingerprint_of(dep_node_index)) + } else { + None + } + } + fn assert_clean(&self, item_span: Span, dep_node: DepNode) { debug!("assert_clean({:?})", dep_node); - let dep_node_index = self.tcx.dep_graph.dep_node_index_of(&dep_node); - let current_fingerprint = self.tcx.dep_graph.fingerprint_of(dep_node_index); + let current_fingerprint = self.get_fingerprint(&dep_node); let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); - if Some(current_fingerprint) != prev_fingerprint { + // if the node wasn't previously evaluated and now is (or vice versa), + // then the node isn't actually clean or dirty. + if (current_fingerprint == None) ^ (prev_fingerprint == None) { + return; + } + + if current_fingerprint != prev_fingerprint { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 8b0b5a5b7a2bd..24b44964e4fd2 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -473,14 +473,25 @@ fn configure_and_expand_inner<'a>( ast_validation::check_crate(sess, &krate) }); - // If we're in rustdoc we're always compiling as an rlib, but that'll trip a - // bunch of checks in the `modify` function below. For now just skip this - // step entirely if we're rustdoc as it's not too useful anyway. - if !sess.opts.actually_rustdoc { + + let crate_types = sess.crate_types.borrow(); + let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); + + // For backwards compatibility, we don't try to run proc macro injection + // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being + // specified. This should only affect users who manually invoke 'rustdoc', as + // 'cargo doc' will automatically pass the proper '--crate-type' flags. + // However, we do emit a warning, to let such users know that they should + // start passing '--crate-type proc-macro' + if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { + let mut msg = sess.diagnostic().struct_warn(&"Trying to document proc macro crate \ + without passing '--crate-type proc-macro to rustdoc"); + + msg.warn("The generated documentation may be incorrect"); + msg.emit() + } else { krate = time(sess, "maybe creating a macro crate", || { - let crate_types = sess.crate_types.borrow(); let num_crate_types = crate_types.len(); - let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro); let is_test_crate = sess.opts.test; syntax_ext::proc_macro_harness::inject( &sess.parse_sess, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index ce7681c974a5d..26e7b789f8f90 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { } } - fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant, _: &hir::Generics) { + fn check_variant(&mut self, cx: &LateContext<'_, '_>, v: &hir::Variant) { self.check_missing_docs_attrs(cx, Some(v.id), &v.attrs, @@ -570,7 +570,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { _ => return, } - let debug = match cx.tcx.lang_items().debug_trait() { + let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) { Some(debug) => debug, None => return, }; diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index acd17f7663234..bb6119d0ff2aa 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -146,7 +146,7 @@ impl EarlyLintPass for NonCamelCaseTypes { } } - fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant, _: &ast::Generics) { + fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) { self.check_case(cx, "variant", &v.ident); } @@ -350,9 +350,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { &mut self, cx: &LateContext<'_, '_>, s: &hir::VariantData, - _: ast::Name, - _: &hir::Generics, - _: hir::HirId, ) { for sf in s.fields() { self.check_snake_case(cx, "structure field", &sf.ident); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index efc77699313e0..5bf4067431f24 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -95,11 +95,6 @@ pub struct CrateMetadata { pub raw_proc_macros: Option<&'static [ProcMacro]>, } -pub struct FullProcMacro { - pub name: ast::Name, - pub ext: Lrc -} - pub struct CStore { metas: RwLock>>>, /// Map from NodeId's of local extern crate statements to crate numbers @@ -109,7 +104,7 @@ pub struct CStore { pub enum LoadedMacro { MacroDef(ast::Item), - ProcMacro(Lrc), + ProcMacro(SyntaxExtension), } impl CStore { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a66da32fa4d75..d6450f00c8b6a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -30,11 +30,9 @@ use syntax::ast; use syntax::attr; use syntax::source_map; use syntax::edition::Edition; -use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; -use syntax::ext::proc_macro::BangProcMacro; use syntax::parse::source_file_to_stream; use syntax::parse::parser::emit_unclosed_delims; -use syntax::symbol::{Symbol, sym}; +use syntax::symbol::Symbol; use syntax_pos::{Span, FileName}; use rustc_data_structures::bit_set::BitSet; @@ -127,15 +125,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); }) } - optimized_mir => { - let mir = cdata.maybe_get_optimized_mir(tcx, def_id.index).unwrap_or_else(|| { - bug!("get_optimized_mir: missing MIR for `{:?}`", def_id) - }); - - let mir = tcx.arena.alloc(mir); - - mir - } + optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } + promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } mir_const_qualif => { (cdata.mir_const_qualif(def_id.index), tcx.arena.alloc(BitSet::new_empty(0))) } @@ -157,7 +148,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, // a `fn` when encoding, so the dep-tracking wouldn't work. // This is only used by rustdoc anyway, which shouldn't have // incremental recompilation ever enabled. - fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } + fn_arg_names => { cdata.get_fn_param_names(def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } @@ -235,6 +226,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } defined_lib_features => { cdata.get_lib_features(tcx) } defined_lang_items => { cdata.get_lang_items(tcx) } + diagnostic_items => { cdata.get_diagnostic_items(tcx) } missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_extern_crate_item => { @@ -427,15 +419,7 @@ impl cstore::CStore { pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { let data = self.get_crate_data(id.krate); if data.is_proc_macro_crate() { - return LoadedMacro::ProcMacro(data.get_proc_macro(id.index, sess).ext); - } else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote { - let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); - let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })); - let ext = SyntaxExtension { - allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()), - ..SyntaxExtension::default(kind, data.root.edition) - }; - return LoadedMacro::ProcMacro(Lrc::new(ext)); + return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess)); } let def = data.get_macro(id.index); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index da96728d2dec9..75d7261704722 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1,8 +1,9 @@ // Decoding metadata from a single crate's metadata -use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule, FullProcMacro}; +use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule}; use crate::schema::*; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::sync::{Lrc, ReadGuard}; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc::hir; @@ -11,13 +12,14 @@ use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; use rustc::middle::lang_items; use rustc::mir::{self, interpret}; use rustc::mir::interpret::AllocDecodingSession; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::codec::TyDecoder; -use rustc::mir::Body; +use rustc::mir::{Body, Promoted}; use rustc::util::captures::Captures; use std::io; @@ -449,11 +451,19 @@ impl<'a, 'tcx> CrateMetadata { pub fn is_proc_macro_crate(&self) -> bool { self.root.proc_macro_decls_static.is_some() } + fn is_proc_macro(&self, id: DefIndex) -> bool { self.is_proc_macro_crate() && self.root.proc_macro_data.unwrap().decode(self).find(|x| *x == id).is_some() } + fn entry_unless_proc_macro(&self, id: DefIndex) -> Option> { + match self.is_proc_macro(id) { + true => None, + false => Some(self.entry(id)), + } + } + fn maybe_entry(&self, item_id: DefIndex) -> Option>> { self.root.entries_index.lookup(self.blob.raw_bytes(), item_id) } @@ -511,35 +521,14 @@ impl<'a, 'tcx> CrateMetadata { self.entry(index).span.decode((self, sess)) } - - pub fn get_proc_macro(&self, id: DefIndex, sess: &Session) -> FullProcMacro { - if sess.opts.debugging_opts.dual_proc_macros { - let host_lib = self.host_lib.as_ref().unwrap(); - self.load_proc_macro( - &host_lib.metadata.get_root(), - id, - sess - ) - } else { - self.load_proc_macro(&self.root, id, sess) - } - } - - fn load_proc_macro(&self, root: &CrateRoot<'_>, - id: DefIndex, - sess: &Session) - -> FullProcMacro { - - let raw_macro = self.raw_proc_macro(id); - let (name, kind, helper_attrs) = match *raw_macro { + crate fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { + let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) { ProcMacro::CustomDerive { trait_name, attributes, client } => { let helper_attrs = attributes.iter().cloned().map(Symbol::intern).collect::>(); ( trait_name, - SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { - client, attrs: helper_attrs.clone() - })), + SyntaxExtensionKind::Derive(Box::new(ProcMacroDerive { client })), helper_attrs, ) } @@ -550,17 +539,21 @@ impl<'a, 'tcx> CrateMetadata { name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new() ) }; + let edition = if sess.opts.debugging_opts.dual_proc_macros { + self.host_lib.as_ref().unwrap().metadata.get_root().edition + } else { + self.root.edition + }; - let span = self.get_span(id, sess); - - FullProcMacro { - name: Symbol::intern(name), - ext: Lrc::new(SyntaxExtension { - span, - helper_attrs, - ..SyntaxExtension::default(kind, root.edition) - }) - } + SyntaxExtension::new( + &sess.parse_sess, + kind, + self.get_span(id, sess), + helper_attrs, + edition, + Symbol::intern(name), + &self.get_attributes(&self.entry(id), sess), + ) } pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef { @@ -703,10 +696,8 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_deprecation(&self, id: DefIndex) -> Option { - match self.is_proc_macro(id) { - true => None, - false => self.entry(id).deprecation.map(|depr| depr.decode(self)), - } + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.deprecation.map(|depr| depr.decode(self))) } pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { @@ -767,6 +758,23 @@ impl<'a, 'tcx> CrateMetadata { } } + /// Iterates over the diagnostic items in the given crate. + pub fn get_diagnostic_items( + &self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx FxHashMap { + tcx.arena.alloc(if self.is_proc_macro_crate() { + // Proc macro crates do not export any diagnostic-items to the target. + Default::default() + } else { + self.root + .diagnostic_items + .decode(self) + .map(|(name, def_index)| (name, self.local_def_id(def_index))) + .collect() + }) + } + /// Iterates over each child of the given item. pub fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) where F: FnMut(def::Export) @@ -916,11 +924,24 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } - pub fn maybe_get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Option> { - match self.is_proc_macro(id) { - true => None, - false => self.entry(id).mir.map(|mir| mir.decode((self, tcx))), - } + pub fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.mir.map(|mir| mir.decode((self, tcx)))) + .unwrap_or_else(|| { + bug!("get_optimized_mir: missing MIR for `{:?}", self.local_def_id(id)) + }) + } + + pub fn get_promoted_mir( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> IndexVec> { + self.entry_unless_proc_macro(id) + .and_then(|entry| entry.promoted_mir.map(|promoted| promoted.decode((self, tcx)))) + .unwrap_or_else(|| { + bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id)) + }) } pub fn mir_const_qualif(&self, id: DefIndex) -> u8 { @@ -1138,14 +1159,14 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { - let arg_names = match self.entry(id).kind { + pub fn get_fn_param_names(&self, id: DefIndex) -> Vec { + let param_names = match self.entry(id).kind { EntryKind::Fn(data) | - EntryKind::ForeignFn(data) => data.decode(self).arg_names, - EntryKind::Method(data) => data.decode(self).fn_data.arg_names, + EntryKind::ForeignFn(data) => data.decode(self).param_names, + EntryKind::Method(data) => data.decode(self).fn_data.param_names, _ => Lazy::empty(), }; - arg_names.decode(self).collect() + param_names.decode(self).collect() } pub fn exported_symbols( diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index df3320c64a960..db212408d8ebd 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -8,6 +8,7 @@ use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LocalDefId, use rustc::hir::GenericParamKind; use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::indexed_vec::IndexVec; use rustc::middle::dependency_format::Linkage; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel, metadata_symbol_name}; @@ -32,7 +33,7 @@ use syntax::ast; use syntax::attr; use syntax::ext::proc_macro::is_proc_macro_attr; use syntax::source_map::Spanned; -use syntax::symbol::{kw, sym, Ident}; +use syntax::symbol::{kw, sym, Ident, Symbol}; use syntax_pos::{self, FileName, SourceFile, Span}; use log::{debug, trace}; @@ -403,6 +404,11 @@ impl<'tcx> EncodeContext<'tcx> { let lang_items_missing = self.encode_lang_items_missing(); let lang_item_bytes = self.position() - i; + // Encode the diagnostic items. + i = self.position(); + let diagnostic_items = self.encode_diagnostic_items(); + let diagnostic_item_bytes = self.position() - i; + // Encode the native libraries used i = self.position(); let native_libraries = self.encode_native_libraries(); @@ -519,6 +525,7 @@ impl<'tcx> EncodeContext<'tcx> { dylib_dependency_formats, lib_features, lang_items, + diagnostic_items, lang_items_missing, native_libraries, foreign_modules, @@ -544,6 +551,7 @@ impl<'tcx> EncodeContext<'tcx> { println!(" dep bytes: {}", dep_bytes); println!(" lib feature bytes: {}", lib_feature_bytes); println!(" lang item bytes: {}", lang_item_bytes); + println!(" diagnostic item bytes: {}", diagnostic_item_bytes); println!(" native bytes: {}", native_lib_bytes); println!(" source_map bytes: {}", source_map_bytes); println!(" impl bytes: {}", impl_bytes); @@ -623,6 +631,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -677,6 +686,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -713,7 +723,8 @@ impl EncodeContext<'tcx> { predicates: None, predicates_defined_on: None, - mir: None + mir: None, + promoted_mir: None, } } @@ -748,6 +759,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -808,6 +820,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -863,18 +876,18 @@ impl EncodeContext<'tcx> { } ty::AssocKind::Method => { let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { - let arg_names = match *m { + let param_names = match *m { hir::TraitMethod::Required(ref names) => { - self.encode_fn_arg_names(names) + self.encode_fn_param_names(names) } hir::TraitMethod::Provided(body) => { - self.encode_fn_arg_names_for_body(body) + self.encode_fn_param_names_for_body(body) } }; FnData { constness: hir::Constness::NotConst, - arg_names, - sig: self.lazy(tcx.fn_sig(def_id)), + param_names, + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -923,6 +936,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -969,8 +983,8 @@ impl EncodeContext<'tcx> { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { FnData { constness: sig.header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), - sig: self.lazy(tcx.fn_sig(def_id)), + param_names: self.encode_fn_param_names_for_body(body), + sig: self.lazy(&tcx.fn_sig(def_id)), } } else { bug!() @@ -1022,14 +1036,15 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: if mir { self.encode_optimized_mir(def_id) } else { None }, + promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None }, } } - fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId) + fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[ast::Name]> { self.tcx.dep_graph.with_ignore(|| { let body = self.tcx.hir().body(body_id); - self.lazy(body.arguments.iter().map(|arg| { + self.lazy(body.params.iter().map(|arg| { match arg.pat.node { PatKind::Binding(_, _, ident, _) => ident.name, _ => kw::Invalid, @@ -1038,7 +1053,7 @@ impl EncodeContext<'tcx> { }) } - fn encode_fn_arg_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> { + fn encode_fn_param_names(&mut self, param_names: &[ast::Ident]) -> Lazy<[ast::Name]> { self.lazy(param_names.iter().map(|ident| ident.name)) } @@ -1052,6 +1067,19 @@ impl EncodeContext<'tcx> { } } + fn encode_promoted_mir( + &mut self, + def_id: DefId, + ) -> Option>>> { + debug!("EncodeContext::encode_promoted_mir({:?})", def_id); + if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { + let promoted = self.tcx.promoted_mir(def_id); + Some(self.lazy(promoted)) + } else { + None + } + } + // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(&mut self, def_id: DefId) -> Lazy<[DefIndex]> { debug!("EncodeContext::encode_inherent_implementations({:?})", def_id); @@ -1101,7 +1129,7 @@ impl EncodeContext<'tcx> { hir::ItemKind::Fn(_, header, .., body) => { let data = FnData { constness: header.constness, - arg_names: self.encode_fn_arg_names_for_body(body), + param_names: self.encode_fn_param_names_for_body(body), sig: self.lazy(tcx.fn_sig(def_id)), }; @@ -1202,6 +1230,20 @@ impl EncodeContext<'tcx> { hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item), }; + let mir = match item.node { + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true, + hir::ItemKind::Fn(_, header, ..) => { + let generics = tcx.generics_of(def_id); + let needs_inline = + (generics.requires_monomorphization(tcx) || + tcx.codegen_fn_attrs(def_id).requests_inline()) && + !self.metadata_output_only(); + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + needs_inline || header.constness == hir::Constness::Const || always_encode_mir + } + _ => false, + }; + Entry { kind, visibility: self.lazy(ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)), @@ -1301,29 +1343,8 @@ impl EncodeContext<'tcx> { _ => None, // not *wrong* for other kinds of items, but not needed }, - mir: match item.node { - hir::ItemKind::Static(..) => { - self.encode_optimized_mir(def_id) - } - hir::ItemKind::Const(..) => self.encode_optimized_mir(def_id), - hir::ItemKind::Fn(_, header, ..) => { - let generics = tcx.generics_of(def_id); - let needs_inline = - (generics.requires_monomorphization(tcx) || - tcx.codegen_fn_attrs(def_id).requests_inline()) && - !self.metadata_output_only(); - let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; - if needs_inline - || header.constness == hir::Constness::Const - || always_encode_mir - { - self.encode_optimized_mir(def_id) - } else { - None - } - } - _ => None, - }, + mir: if mir { self.encode_optimized_mir(def_id) } else { None }, + promoted_mir: if mir { self.encode_promoted_mir(def_id) } else { None }, } } @@ -1350,6 +1371,7 @@ impl EncodeContext<'tcx> { predicates: None, predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -1376,6 +1398,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: None, + promoted_mir: None, } } @@ -1436,6 +1459,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -1464,6 +1488,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: self.encode_optimized_mir(def_id), + promoted_mir: self.encode_promoted_mir(def_id), } } @@ -1537,6 +1562,12 @@ impl EncodeContext<'tcx> { self.lazy(lib_features.to_vec()) } + fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { + let tcx = self.tcx; + let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) + } + fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { let tcx = self.tcx; let lang_items = tcx.lang_items(); @@ -1645,7 +1676,7 @@ impl EncodeContext<'tcx> { hir::ForeignItemKind::Fn(_, ref names, _) => { let data = FnData { constness: hir::Constness::NotConst, - arg_names: self.encode_fn_arg_names(names), + param_names: self.encode_fn_param_names(names), sig: self.lazy(tcx.fn_sig(def_id)), }; EntryKind::ForeignFn(self.lazy(data)) @@ -1675,6 +1706,7 @@ impl EncodeContext<'tcx> { predicates_defined_on: None, mir: None, + promoted_mir: None, } } } diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index f37877b437e15..1a5f0e17ba7ce 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -11,6 +11,7 @@ use rustc::session::CrateDisambiguator; use rustc::session::config::SymbolManglingVersion; use rustc::ty::{self, Ty, ReprOptions}; use rustc_target::spec::{PanicStrategy, TargetTriple}; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::svh::Svh; use syntax::{ast, attr}; @@ -175,6 +176,7 @@ pub struct CrateRoot<'tcx> { pub lib_features: Lazy<[(Symbol, Option)]>, pub lang_items: Lazy<[(DefIndex, usize)]>, pub lang_items_missing: Lazy<[lang_items::LangItem]>, + pub diagnostic_items: Lazy<[(Symbol, DefIndex)]>, pub native_libraries: Lazy<[NativeLibrary]>, pub foreign_modules: Lazy<[ForeignModule]>, pub source_map: Lazy<[syntax_pos::SourceFile]>, @@ -231,6 +233,7 @@ pub struct Entry<'tcx> { pub predicates_defined_on: Option>>, pub mir: Option>>, + pub promoted_mir: Option>>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] @@ -293,7 +296,7 @@ pub struct MacroDef { #[derive(RustcEncodable, RustcDecodable)] pub struct FnData<'tcx> { pub constness: hir::Constness, - pub arg_names: Lazy<[ast::Name]>, + pub param_names: Lazy<[ast::Name]>, pub sig: Lazy>, } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 99899aa390c4a..251d4b727c754 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -159,7 +159,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), projection: None, @@ -169,7 +169,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), projection: None, @@ -440,7 +441,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub fn is_place_thread_local(&self, place_ref: PlaceRef<'cx, 'tcx>) -> bool { if let PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), projection: None, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index de27aec2b2990..8ded539e7205a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -13,7 +13,7 @@ use rustc::mir::{ ClearCrossCrate, Local, Location, Body, Mutability, Operand, Place, PlaceBase, PlaceRef, Static, StaticKind }; -use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; +use rustc::mir::{Field, Projection, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; use rustc::ty::{self, TyCtxt}; @@ -22,6 +22,7 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; +use rustc_data_structures::indexed_vec::IndexVec; use smallvec::SmallVec; use std::collections::BTreeMap; @@ -86,12 +87,13 @@ pub fn provide(providers: &mut Providers<'_>) { } fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { - let input_body = tcx.mir_validated(def_id); + let (input_body, promoted) = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); - do_mir_borrowck(&infcx, input_body, def_id) + let promoted: &IndexVec<_, _> = &promoted.borrow(); + do_mir_borrowck(&infcx, input_body, promoted, def_id) }); debug!("mir_borrowck done"); @@ -101,6 +103,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> { fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, + input_promoted: &IndexVec>, def_id: DefId, ) -> BorrowCheckResult<'tcx> { debug!("do_mir_borrowck(def_id = {:?})", def_id); @@ -147,7 +150,9 @@ fn do_mir_borrowck<'a, 'tcx>( // be modified (in place) to contain non-lexical lifetimes. It // will have a lifetime tied to the inference context. let mut body: Body<'tcx> = input_body.clone(); - let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body); + let mut promoted: IndexVec> = input_promoted.clone(); + let free_regions = + nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body, &mut promoted); let body = &body; // no further changes let location_table = &LocationTable::new(body); @@ -184,6 +189,7 @@ fn do_mir_borrowck<'a, 'tcx>( def_id, free_regions, body, + &promoted, &upvars, location_table, param_env, @@ -1462,13 +1468,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { assert!(root_place.projection.is_none()); let (might_be_alive, will_be_dropped) = match root_place.base { PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }) => { (true, false) } PlaceBase::Static(box Static { - kind: StaticKind::Static(_), + kind: StaticKind::Static, .. }) => { // Thread-locals might be dropped after the function exits, but @@ -2150,7 +2156,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // `Place::Promoted` if the promotion weren't 100% legal. So we just forward this PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), projection: None, @@ -2162,7 +2168,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }), PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), projection: None, diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index 738a091b0dd76..f10ff71b15e68 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -415,20 +415,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "{:?}", move_place.ty(self.body, self.infcx.tcx).ty, ); - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); - let is_option = move_ty.starts_with("std::option::Option"); - let is_result = move_ty.starts_with("std::result::Result"); - if is_option || is_result { - err.span_suggestion( - span, - &format!("consider borrowing the `{}`'s content", if is_option { - "Option" - } else { - "Result" - }), - format!("{}.as_ref()", snippet), - Applicability::MaybeIncorrect, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + let is_option = move_ty.starts_with("std::option::Option"); + let is_result = move_ty.starts_with("std::result::Result"); + if is_option || is_result { + err.span_suggestion( + span, + &format!("consider borrowing the `{}`'s content", if is_option { + "Option" + } else { + "Result" + }), + format!("{}.as_ref()", snippet), + Applicability::MaybeIncorrect, + ); + } } err } @@ -439,19 +440,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'a>, span: Span, ) { - let snippet = self.infcx.tcx.sess.source_map().span_to_snippet(span).unwrap(); match error { GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); + if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); + } if binds_to.is_empty() { let place_ty = move_from.ty(self.body, self.infcx.tcx).ty; @@ -517,27 +519,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. })) ) = bind_to.is_user_variable { - let pat_snippet = self.infcx.tcx.sess.source_map() - .span_to_snippet(pat_span) - .unwrap(); - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); - let suggestion; - let to_remove; - if pat_snippet.starts_with("mut") - && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) - { - suggestion = pat_snippet["mut".len()..].trim_start(); - to_remove = "&mut"; - } else { - suggestion = pat_snippet; - to_remove = "&"; + if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) + { + if pat_snippet.starts_with('&') { + let pat_snippet = pat_snippet[1..].trim_start(); + let suggestion; + let to_remove; + if pat_snippet.starts_with("mut") + && pat_snippet["mut".len()..].starts_with(Pattern_White_Space) + { + suggestion = pat_snippet["mut".len()..].trim_start(); + to_remove = "&mut"; + } else { + suggestion = pat_snippet; + to_remove = "&"; + } + suggestions.push(( + pat_span, + to_remove, + suggestion.to_owned(), + )); } - suggestions.push(( - pat_span, - to_remove, - suggestion.to_owned(), - )); } } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 937c6383be341..5a5534922aa8a 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), projection: None, @@ -158,7 +158,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Static(def_id), + kind: StaticKind::Static, + def_id, .. }), projection: None, @@ -711,8 +712,8 @@ fn annotate_struct_field( } /// If possible, suggest replacing `ref` with `ref mut`. -fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<(String)> { - let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).unwrap(); +fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { + let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(Pattern_White_Space) { diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index d65cdde303ca0..11ec154e5b5c1 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -11,8 +11,9 @@ use crate::transform::MirSource; use crate::borrow_check::Upvar; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; -use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body}; +use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body, Promoted}; use rustc::ty::{self, RegionKind, RegionVid}; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_errors::Diagnostic; use std::fmt::Debug; use std::env; @@ -52,6 +53,7 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( def_id: DefId, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, + promoted: &mut IndexVec>, ) -> UniversalRegions<'tcx> { debug!("replace_regions_in_mir(def_id={:?})", def_id); @@ -59,7 +61,7 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>( let universal_regions = UniversalRegions::new(infcx, def_id, param_env); // Replace all remaining regions with fresh inference variables. - renumber::renumber_mir(infcx, body); + renumber::renumber_mir(infcx, body, promoted); let source = MirSource::item(def_id); mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, body, |_, _| Ok(())); @@ -75,6 +77,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( def_id: DefId, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, + promoted: &IndexVec>, upvars: &[Upvar], location_table: &LocationTable, param_env: ty::ParamEnv<'tcx>, @@ -105,6 +108,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>( infcx, param_env, body, + promoted, def_id, &universal_regions, location_table, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index ca68b9e31b6b9..75a31628a54b6 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -413,7 +413,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, *counter); - let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)); + let type_name = infcx.extract_type_name(&argument_ty, Some(highlight)).0; debug!( "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -695,7 +695,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *counter); - let type_name = infcx.extract_type_name(&return_ty, Some(highlight)); + let type_name = infcx.extract_type_name(&return_ty, Some(highlight)).0; let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); @@ -758,7 +758,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *counter); - let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)); + let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)).0; let mir_hir_id = tcx.hir().as_local_hir_id(mir_def_id).expect("non-local mir"); diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index c1d1185cf177a..c479c38f30c7e 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -1,16 +1,26 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{Location, Body}; +use rustc::mir::{Location, Body, Promoted}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc_data_structures::indexed_vec::IndexVec; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. -pub fn renumber_mir<'tcx>(infcx: &InferCtxt<'_, 'tcx>, body: &mut Body<'tcx>) { +pub fn renumber_mir<'tcx>( + infcx: &InferCtxt<'_, 'tcx>, + body: &mut Body<'tcx>, + promoted: &mut IndexVec>, +) { debug!("renumber_mir()"); debug!("renumber_mir: body.arg_count={:?}", body.arg_count); let mut visitor = NLLVisitor { infcx }; + + for body in promoted.iter_mut() { + visitor.visit_body(body); + } + visitor.visit_body(body); } @@ -44,14 +54,6 @@ impl<'a, 'tcx> NLLVisitor<'a, 'tcx> { } impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> { - fn visit_body(&mut self, body: &mut Body<'tcx>) { - for promoted in body.promoted.iter_mut() { - self.visit_body(promoted); - } - - self.super_body(body); - } - fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); 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 9ff0c6ca6a546..da1f64b05151b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -112,6 +112,7 @@ pub(crate) fn type_check<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, + promoted: &IndexVec>, mir_def_id: DefId, universal_regions: &Rc>, location_table: &LocationTable, @@ -157,6 +158,7 @@ pub(crate) fn type_check<'tcx>( mir_def_id, param_env, body, + promoted, ®ion_bound_pairs, implicit_region_bound, &mut borrowck_context, @@ -180,6 +182,7 @@ fn type_check_internal<'a, 'tcx, R>( mir_def_id: DefId, param_env: ty::ParamEnv<'tcx>, body: &'a Body<'tcx>, + promoted: &'a IndexVec>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, @@ -197,7 +200,7 @@ fn type_check_internal<'a, 'tcx, R>( universal_region_relations, ); let errors_reported = { - let mut verifier = TypeVerifier::new(&mut checker, body); + let mut verifier = TypeVerifier::new(&mut checker, body, promoted); verifier.visit_body(body); verifier.errors_reported }; @@ -254,6 +257,7 @@ enum FieldAccessError { struct TypeVerifier<'a, 'b, 'tcx> { cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>, + promoted: &'b IndexVec>, last_span: Span, mir_def_id: DefId, errors_reported: bool, @@ -380,9 +384,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn new(cx: &'a mut TypeChecker<'b, 'tcx>, body: &'b Body<'tcx>) -> Self { + fn new( + cx: &'a mut TypeChecker<'b, 'tcx>, + body: &'b Body<'tcx>, + promoted: &'b IndexVec>, + ) -> Self { TypeVerifier { body, + promoted, mir_def_id: cx.mir_def_id, cx, last_span: body.span, @@ -416,7 +425,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let mut place_ty = match place_base { PlaceBase::Local(index) => PlaceTy::from_ty(self.body.local_decls[*index].ty), - PlaceBase::Static(box Static { kind, ty: sty }) => { + PlaceBase::Static(box Static { kind, ty: sty, def_id }) => { let sty = self.sanitize_type(place, sty); let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, @@ -440,16 +449,16 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { }; }; match kind { - StaticKind::Promoted(promoted) => { + StaticKind::Promoted(promoted, _) => { if !self.errors_reported { - let promoted_body = &self.body.promoted[*promoted]; + let promoted_body = &self.promoted[*promoted]; self.sanitize_promoted(promoted_body, location); let promoted_ty = promoted_body.return_ty(); check_err(self, place, promoted_ty, sty); } } - StaticKind::Static(def_id) => { + StaticKind::Static => { let ty = self.tcx().type_of(*def_id); let ty = self.cx.normalize(ty, location); @@ -466,7 +475,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let is_promoted = match place { Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), projection: None, diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 72d5588c34120..5caba637ccc4a 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -46,9 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { } } } - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => false, - PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { tcx.is_mutable_static(*def_id) } }; diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 4dd2794f11301..4f469174b392d 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -329,11 +329,11 @@ fn place_base_conflict<'tcx>( } (PlaceBase::Static(s1), PlaceBase::Static(s2)) => { match (&s1.kind, &s2.kind) { - (StaticKind::Static(def_id_1), StaticKind::Static(def_id_2)) => { - if def_id_1 != def_id_2 { + (StaticKind::Static, StaticKind::Static) => { + if s1.def_id != s2.def_id { debug!("place_element_conflict: DISJOINT-STATIC"); Overlap::Disjoint - } else if tcx.is_mutable_static(*def_id_1) { + } else if tcx.is_mutable_static(s1.def_id) { // We ignore mutable statics - they can only be unsafe code. debug!("place_element_conflict: IGNORE-STATIC-MUT"); Overlap::Disjoint @@ -342,7 +342,7 @@ fn place_base_conflict<'tcx>( Overlap::EqualOrDisjoint } }, - (StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => { + (StaticKind::Promoted(promoted_1, _), StaticKind::Promoted(promoted_2, _)) => { if promoted_1 == promoted_2 { if let ty::Array(_, len) = s1.ty.sty { if let Some(0) = len.try_eval_usize(tcx, param_env) { diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index ecafd4eb1157e..4c6be23de28be 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -136,7 +136,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { } PrefixSet::All => { // all prefixes: just blindly enqueue the base - // of the projection + // of the projection. self.next = Some(PlaceRef { base: cursor.base, projection: &proj.base, diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 7005f274e0e7d..98cf4bba1c75f 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -126,7 +126,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::StaticRef { id } => block.and(Place { base: PlaceBase::Static(Box::new(Static { ty: expr.ty, - kind: StaticKind::Static(id), + kind: StaticKind::Static, + def_id: id, })), projection: None, }), diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index ec85daccd476e..d5890d00ea80f 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; - let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem); + let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem, None); let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); let bool_ty = self.hir.bool_ty(); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 4e970aee42cf4..7ab0bf7d66a64 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -94,7 +94,7 @@ pub fn mir_build(tcx: TyCtxt<'_>, def_id: DefId) -> Body<'_> { let body = tcx.hir().body(body_id); let explicit_arguments = - body.arguments + body.params .iter() .enumerate() .map(|(index, arg)| { @@ -502,7 +502,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { // This is a special case: some functions have a C abi but are meant to // unwind anyway. Don't stop them. match unwind_attr { - None => true, + None => false, // FIXME(#58794) Some(UnwindAttr::Allowed) => false, Some(UnwindAttr::Aborts) => true, } @@ -511,7 +511,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { /////////////////////////////////////////////////////////////////////////// /// the main entry point for building MIR for a function -struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Arg>, Option); +struct ArgInfo<'tcx>(Ty<'tcx>, Option, Option<&'tcx hir::Param>, Option); fn construct_fn<'a, 'tcx, A>( hir: Cx<'a, 'tcx>, @@ -763,7 +763,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.basic_blocks, self.source_scopes, ClearCrossCrate::Set(self.source_scope_local_data), - IndexVec::new(), yield_ty, self.local_decls, self.canonical_user_type_annotations, diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 76ee76a74562b..5aa487d901663 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -49,17 +49,6 @@ pub(crate) fn mk_eval_cx<'mir, 'tcx>( InterpCx::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), Default::default()) } -pub(crate) fn eval_promoted<'mir, 'tcx>( - tcx: TyCtxt<'tcx>, - cid: GlobalId<'tcx>, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, -) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let span = tcx.def_span(cid.instance.def_id()); - let mut ecx = mk_eval_cx(tcx, span, param_env); - eval_body_using_ecx(&mut ecx, cid, body, param_env) -} - fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, 'tcx>, op: OpTy<'tcx>, @@ -360,7 +349,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } // This is a const fn. Call it. - Ok(Some(match ecx.load_mir(instance.def) { + Ok(Some(match ecx.load_mir(instance.def, None) { Ok(body) => body, Err(err) => { if let err_unsup!(NoMirFor(ref path)) = err.kind { @@ -530,6 +519,9 @@ pub fn const_variant_index<'tcx>( ecx.read_discriminant(op).unwrap().1 } +/// Turn an interpreter error into something to report to the user. +/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace. +/// Should be called only if the error is actually going to to be reported! pub fn error_to_const_error<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, mut error: InterpErrorInfo<'tcx>, @@ -664,14 +656,8 @@ pub fn const_eval_raw_provider<'tcx>( Default::default() ); - let res = ecx.load_mir(cid.instance.def); - res.map(|body| { - if let Some(index) = cid.promoted { - &body.promoted[index] - } else { - body - } - }).and_then( + let res = ecx.load_mir(cid.instance.def, cid.promoted); + res.and_then( |body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env) ).and_then(|place| { Ok(RawConst { diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 018fd2e97b264..2ea6c4ae10fdc 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -269,10 +269,6 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { debug!("Borrows::statement_effect: stmt={:?}", stmt); match stmt.kind { mir::StatementKind::Assign(ref lhs, ref rhs) => { - // Make sure there are no remaining borrows for variables - // that are assigned over. - self.kill_borrows_on_place(trans, lhs); - if let mir::Rvalue::Ref(_, _, ref place) = **rhs { if place.ignore_borrow( self.tcx, @@ -287,6 +283,10 @@ impl<'a, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'tcx> { trans.gen(*index); } + + // Make sure there are no remaining borrows for variables + // that are assigned over. + self.kill_borrows_on_place(trans, lhs); } mir::StatementKind::StorageDead(local) => { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 5c2255882b2c7..e5a19572170a7 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -240,7 +240,7 @@ impl MovePathLookup { // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available // parent. - pub fn find(&self, place_ref: PlaceRef<'cx, 'tcx>) -> LookupResult { + pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult { place_ref.iterate(|place_base, place_projection| { let mut result = match place_base { PlaceBase::Local(local) => self.locals[*local], diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 17fd9377a1629..5352888006c30 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -91,9 +91,9 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { fn visit_body(&mut self, body: &'tcx hir::Body) { intravisit::walk_body(self, body); - for arg in &body.arguments { - self.check_irrefutable(&arg.pat, "function argument"); - self.check_patterns(false, slice::from_ref(&arg.pat)); + for param in &body.params { + self.check_irrefutable(¶m.pat, "function argument"); + self.check_patterns(false, slice::from_ref(¶m.pat)); } } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6f48396cdd7cf..054b65f0e1a9e 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -294,6 +294,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn load_mir( &self, instance: ty::InstanceDef<'tcx>, + promoted: Option, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { // do not continue if typeck errors occurred (can only occur in local crate) let did = instance.def_id(); @@ -303,7 +304,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { throw_inval!(TypeckError) } - trace!("load mir {:?}", instance); + trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); + if let Some(promoted) = promoted { + return Ok(&self.tcx.promoted_mir(did)[promoted]); + } match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { Ok(self.tcx.optimized_mir(did)) @@ -438,27 +442,30 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Issue #27023: must add any necessary padding to `size` // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - Ok(Some((size.align_to(align), align))) + let size = size.align_to(align); + + // Check if this brought us over the size limit. + if size.bytes() >= self.tcx.data_layout().obj_size_bound() { + throw_ub_format!("wide pointer metadata contains invalid information: \ + total size is bigger than largest supported object"); + } + Ok(Some((size, align))) } ty::Dynamic(..) => { let vtable = metadata.expect("dyn trait fat ptr must have vtable"); - // the second entry in the vtable is the dynamic size of the object. + // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { let len = metadata.expect("slice fat ptr must have vtable").to_usize(self)?; let elem = layout.field(self, 0)?; - Ok(Some((elem.size * len, elem.align.abi))) + + // Make sure the slice is not too big. + let size = elem.size.checked_mul(len, &*self.tcx) + .ok_or_else(|| err_ub_format!("invalid slice: \ + total size is bigger than largest supported object"))?; + Ok(Some((size, elem.align.abi))) } ty::Foreign(_) => { diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 32ba70a81c997..4cbbc0ffe17cc 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -94,7 +94,7 @@ impl<'rt, 'mir, 'tcx> InternVisitor<'rt, 'mir, 'tcx> { alloc.mutability = mutability; // link the alloc id to the actual allocation let alloc = tcx.intern_const_alloc(alloc); - self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc)); + self.leftover_relocations.extend(alloc.relocations().iter().map(|&(_, ((), reloc))| reloc)); tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc); Ok(None) } @@ -316,7 +316,7 @@ pub fn intern_const_alloc_recursive( // So we hand-roll the interning logic here again let alloc = tcx.intern_const_alloc(alloc); tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc); - for &(_, ((), reloc)) in alloc.relocations.iter() { + for &(_, ((), reloc)) in alloc.relocations().iter() { if leftover_relocations.insert(reloc) { todo.push(reloc); } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 4c86c53256e9b..0f2305e03ff33 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -81,7 +81,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let alloc = alloc_type_name(self.tcx.tcx, substs.type_at(0)); let name_id = self.tcx.alloc_map.lock().create_memory_alloc(alloc); let id_ptr = self.memory.tag_static_base_pointer(name_id.into()); - let alloc_len = alloc.bytes.len() as u64; + let alloc_len = alloc.size.bytes(); let name_val = Immediate::new_slice(Scalar::Ptr(id_ptr), alloc_len, self); self.write_immediate(name_val, dest)?; } @@ -95,7 +95,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | "bitreverse" => { let ty = substs.type_at(0); let layout_of = self.layout_of(ty)?; - let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let bits = self.force_bits(val, layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => throw_unsup!(TypeNotPrimitive(ty)), @@ -149,7 +150,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // term since the sign of the second term can be inferred from this and // the fact that the operation has overflowed (if either is 0 no // overflow can occur) - let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?; + let first_term: u128 = self.force_bits(l.to_scalar()?, l.layout.size)?; let first_term_positive = first_term & (1 << (num_bits-1)) == 0; if first_term_positive { // Negative overflow not possible since the positive first term @@ -187,7 +188,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?; if overflowed { let layout = self.layout_of(substs.type_at(0))?; - let r_val = r.to_scalar()?.to_bits(layout.size)?; + let r_val = self.force_bits(r.to_scalar()?, layout.size)?; throw_ub_format!("Overflowing shift by {} in `{}`", r_val, intrinsic_name); } self.write_scalar(val, dest)?; @@ -196,8 +197,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) let layout = self.layout_of(substs.type_at(0))?; - let val_bits = self.read_scalar(args[0])?.to_bits(layout.size)?; - let raw_shift_bits = self.read_scalar(args[1])?.to_bits(layout.size)?; + let val = self.read_scalar(args[0])?.not_undef()?; + let val_bits = self.force_bits(val, layout.size)?; + let raw_shift = self.read_scalar(args[1])?.not_undef()?; + let raw_shift_bits = self.force_bits(raw_shift, layout.size)?; let width_bits = layout.size.bits() as u128; let shift_bits = raw_shift_bits % width_bits; let inv_shift_bits = (width_bits - shift_bits) % width_bits; diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index f207cfc6b39cd..032d16a49db4b 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -221,7 +221,7 @@ pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> val: ConstValue::Slice { data: alloc, start: 0, - end: alloc.bytes.len(), + end: alloc.len(), }, ty: tcx.mk_static_str(), }) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 87d36dabb0472..62b1760508b4c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -210,7 +210,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let new_ptr = self.allocate(new_size, new_align, kind); let old_size = match old_size_and_align { Some((size, _align)) => size, - None => Size::from_bytes(self.get(ptr.alloc_id)?.bytes.len() as u64), + None => self.get(ptr.alloc_id)?.size, }; self.copy( ptr, @@ -271,20 +271,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { )) } if let Some((size, align)) = old_size_and_align { - if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align { - let bytes = Size::from_bytes(alloc.bytes.len() as u64); + if size != alloc.size || align != alloc.align { + let bytes = alloc.size; throw_unsup!(IncorrectAllocationInformation(size, bytes, align, alloc.align)) } } // Let the machine take some extra action - let size = Size::from_bytes(alloc.bytes.len() as u64); + let size = alloc.size; AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?; // Don't forget to remember size and align of this now-dead allocation let old = self.dead_alloc_map.insert( ptr.alloc_id, - (Size::from_bytes(alloc.bytes.len() as u64), alloc.align) + (alloc.size, alloc.align) ); if old.is_some() { bug!("Nothing can be deallocated twice"); @@ -555,7 +555,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // a) cause cycles in case `id` refers to a static // b) duplicate a static's allocation in miri if let Some((_, alloc)) = self.alloc_map.get(id) { - return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)); + return Ok((alloc.size, alloc.align)); } // # Function pointers @@ -583,7 +583,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(GlobalAlloc::Memory(alloc)) => // Need to duplicate the logic here, because the global allocations have // different associated types than the interpreter-local ones. - Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)), + Ok((alloc.size, alloc.align)), Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), // The rest must be dead. @@ -645,17 +645,22 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { let prefix_len = msg.len(); let mut relocations = vec![]; - for i in 0..(alloc.bytes.len() as u64) { + for i in 0..alloc.size.bytes() { let i = Size::from_bytes(i); - if let Some(&(_, target_id)) = alloc.relocations.get(&i) { + if let Some(&(_, target_id)) = alloc.relocations().get(&i) { if allocs_seen.insert(target_id) { allocs_to_print.push_back(target_id); } relocations.push((i, target_id)); } - if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() { + if alloc.undef_mask().is_range_defined(i, i + Size::from_bytes(1)).is_ok() { // this `as usize` is fine, since `i` came from a `usize` - write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap(); + let i = i.bytes() as usize; + + // Checked definedness (and thus range) and relocations. This access also doesn't + // influence interpreter execution but is only for debugging. + let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(i..i+1); + write!(msg, "{:02x} ", bytes[0]).unwrap(); } else { msg.push_str("__ "); } @@ -664,7 +669,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { trace!( "{}({} bytes, alignment {}){}", msg, - alloc.bytes.len(), + alloc.size.bytes(), alloc.align.bytes(), extra ); @@ -803,32 +808,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // since we don't want to keep any relocations at the target. // (`get_bytes_with_undef_and_ptr` below checks that there are no // relocations overlapping the edges; those would not be handled correctly). - let relocations = { - let relocations = self.get(src.alloc_id)?.relocations(self, src, size); - if relocations.is_empty() { - // nothing to copy, ignore even the `length` loop - Vec::new() - } else { - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); - for i in 0..length { - new_relocations.extend( - relocations - .iter() - .map(|&(offset, reloc)| { - // compute offset for current repetition - let dest_offset = dest.offset + (i * size); - ( - // shift offsets from source allocation to destination allocation - offset + dest_offset - src.offset, - reloc, - ) - }) - ); - } - - new_relocations - } - }; + let relocations = self.get(src.alloc_id)? + .prepare_relocation_copy(self, src, size, dest, length); let tcx = self.tcx.tcx; @@ -875,7 +856,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // copy definedness to the destination self.copy_undef_mask(src, dest, size, length)?; // copy the relocations to the destination - self.get_mut(dest.alloc_id)?.relocations.insert_presorted(relocations); + self.get_mut(dest.alloc_id)?.mark_relocation_range(relocations); Ok(()) } @@ -894,65 +875,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // The bits have to be saved locally before writing to dest in case src and dest overlap. assert_eq!(size.bytes() as usize as u64, size.bytes()); - let undef_mask = &self.get(src.alloc_id)?.undef_mask; - - // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`), - // a naive undef mask copying algorithm would repeatedly have to read the undef mask from - // the source and write it to the destination. Even if we optimized the memory accesses, - // we'd be doing all of this `repeat` times. - // Therefor we precompute a compressed version of the undef mask of the source value and - // then write it back `repeat` times without computing any more information from the source. - - // a precomputed cache for ranges of defined/undefined bits - // 0000010010001110 will become - // [5, 1, 2, 1, 3, 3, 1] - // where each element toggles the state - let mut ranges = smallvec::SmallVec::<[u64; 1]>::new(); - let first = undef_mask.get(src.offset); - let mut cur_len = 1; - let mut cur = first; - for i in 1..size.bytes() { - // FIXME: optimize to bitshift the current undef block's bits and read the top bit - if undef_mask.get(src.offset + Size::from_bytes(i)) == cur { - cur_len += 1; - } else { - ranges.push(cur_len); - cur_len = 1; - cur = !cur; - } - } + let src_alloc = self.get(src.alloc_id)?; + let compressed = src_alloc.compress_undef_range(src, size); // now fill in all the data let dest_allocation = self.get_mut(dest.alloc_id)?; - // an optimization where we can just overwrite an entire range of definedness bits if - // they are going to be uniformly `1` or `0`. - if ranges.is_empty() { - dest_allocation.undef_mask.set_range_inbounds( - dest.offset, - dest.offset + size * repeat, - first, - ); - return Ok(()) - } + dest_allocation.mark_compressed_undef_range(&compressed, dest, size, repeat); - // remember to fill in the trailing bits - ranges.push(cur_len); - - for mut j in 0..repeat { - j *= size.bytes(); - j += dest.offset.bytes(); - let mut cur = first; - for range in &ranges { - let old_j = j; - j += range; - dest_allocation.undef_mask.set_range_inbounds( - Size::from_bytes(old_j), - Size::from_bytes(j), - cur, - ); - cur = !cur; - } - } Ok(()) } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 7a545e8ad6f79..b5aab992e3adb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -629,11 +629,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // post-process Ok(match *discr_kind { layout::DiscriminantKind::Tag => { - let bits_discr = match raw_discr.to_bits(discr_val.layout.size) { - Ok(raw_discr) => raw_discr, - Err(_) => - throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag())), - }; + let bits_discr = raw_discr + .not_undef() + .and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size)) + .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?; let real_discr = if discr_val.layout.ty.is_signed() { // going from layout tag type to typeck discriminant type // requires first sign extending with the layout discriminant diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 85f9cbd37589a..23c9e7fdf67ce 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -585,7 +585,7 @@ where use rustc::mir::StaticKind; Ok(match place_static.kind { - StaticKind::Promoted(promoted) => { + StaticKind::Promoted(promoted, _) => { let instance = self.frame().instance; self.const_eval_raw(GlobalId { instance, @@ -593,11 +593,11 @@ where })? } - StaticKind::Static(def_id) => { + StaticKind::Static => { let ty = place_static.ty; assert!(!ty.needs_subst()); let layout = self.layout_of(ty)?; - let instance = ty::Instance::mono(*self.tcx, def_id); + let instance = ty::Instance::mono(*self.tcx, place_static.def_id); let cid = GlobalId { instance, promoted: None diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 47289064f4d0d..2cac8bb0c517e 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -15,7 +15,7 @@ use rustc::mir::interpret::{ }; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::Align; +use rustc::ty::layout::{Align, Size}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -276,6 +276,7 @@ struct AllocationSnapshot<'a> { relocations: Relocations<(), AllocIdSnapshot<'a>>, undef_mask: &'a UndefMask, align: &'a Align, + size: &'a Size, mutability: &'a Mutability, } @@ -285,12 +286,28 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation type Item = AllocationSnapshot<'a>; fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let Allocation { bytes, relocations, undef_mask, align, mutability, extra: () } = self; + let Allocation { + size, + align, + mutability, + extra: (), + .. + } = self; + + let all_bytes = 0..self.len(); + // This 'inspect' is okay since following access respects undef and relocations. This does + // influence interpreter exeuction, but only to detect the error of cycles in evalution + // dependencies. + let bytes = self.inspect_with_undef_and_ptr_outside_interpreter(all_bytes); + + let undef_mask = self.undef_mask(); + let relocations = self.relocations(); AllocationSnapshot { bytes, undef_mask, align, + size, mutability, relocations: relocations.snapshot(ctx), } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index a2fc75739ffa0..10b767ebba191 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty, Instance, TypeFoldable}; -use rustc::ty::layout::{Size, Align, LayoutOf}; +use rustc::ty::layout::{Size, Align, LayoutOf, HasDataLayout}; use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic,}; use super::{InterpCx, Machine, MemoryKind, FnVal}; @@ -144,11 +144,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let size = alloc.read_ptr_sized( self, vtable.offset(pointer_size, self)? - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let size = self.force_bits(size, pointer_size)? as u64; let align = alloc.read_ptr_sized( self, vtable.offset(pointer_size * 2, self)?, - )?.to_bits(pointer_size)? as u64; + )?.not_undef()?; + let align = self.force_bits(align, pointer_size)? as u64; + + if size >= self.tcx.data_layout().obj_size_bound() { + throw_ub_format!("invalid vtable: \ + size is bigger than largest supported object"); + } Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap())) } } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 82d6d7db01c8d..3e14ba3efcc58 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -1,3 +1,9 @@ +//! Check the validity invariant of a given value, and tell the user +//! where in the value it got violated. +//! In const context, this goes even further and tries to approximate const safety. +//! That's useful because it means other passes (e.g. promotion) can rely on `const`s +//! to be const-safe. + use std::fmt::Write; use std::ops::RangeInclusive; @@ -11,7 +17,7 @@ use std::hash::Hash; use super::{ GlobalAlloc, InterpResult, - OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, + Scalar, OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, }; macro_rules! throw_validation_failure { @@ -250,6 +256,47 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M self.path.truncate(path_len); Ok(()) } + + fn check_wide_ptr_meta( + &mut self, + meta: Option>, + pointee: TyLayout<'tcx>, + ) -> InterpResult<'tcx> { + let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); + match tail.sty { + ty::Dynamic(..) => { + let vtable = meta.unwrap(); + try_validation!( + self.ecx.memory.check_ptr_access( + vtable, + 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align + self.ecx.tcx.data_layout.pointer_align.abi, + ), + "dangling or unaligned vtable pointer in wide pointer or too small vtable", + self.path + ); + try_validation!(self.ecx.read_drop_type_from_vtable(vtable), + "invalid drop fn in vtable", self.path); + try_validation!(self.ecx.read_size_and_align_from_vtable(vtable), + "invalid size or align in vtable", self.path); + // FIXME: More checks for the vtable. + } + ty::Slice(..) | ty::Str => { + let _len = try_validation!(meta.unwrap().to_usize(self.ecx), + "non-integer slice length in wide pointer", self.path); + // We do not check that `len * elem_size <= isize::MAX`: + // that is only required for references, and there it falls out of the + // "dereferencable" check performed by Stacked Borrows. + } + ty::Foreign(..) => { + // Unsized, but not wide. + } + _ => + bug!("Unexpected unsized type tail: {:?}", tail), + } + + Ok(()) + } } impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> @@ -341,56 +388,34 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } } ty::RawPtr(..) => { + // Check pointer part. if self.ref_tracking_for_consts.is_some() { // Integers/floats in CTFE: For consistency with integers, we do not // accept undef. let _ptr = try_validation!(value.to_scalar_ptr(), "undefined address in raw pointer", self.path); - let _meta = try_validation!(value.to_meta(), - "uninitialized data in raw fat pointer metadata", self.path); } else { // Remain consistent with `usize`: Accept anything. } + + // Check metadata. + let meta = try_validation!(value.to_meta(), + "uninitialized data in wide pointer metadata", self.path); + let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?; + if layout.is_unsized() { + self.check_wide_ptr_meta(meta, layout)?; + } } _ if ty.is_box() || ty.is_region_ptr() => { - // Handle fat pointers. + // Handle wide pointers. // Check metadata early, for better diagnostics let ptr = try_validation!(value.to_scalar_ptr(), "undefined address in pointer", self.path); let meta = try_validation!(value.to_meta(), - "uninitialized data in fat pointer metadata", self.path); + "uninitialized data in wide pointer metadata", self.path); let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?; if layout.is_unsized() { - let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(layout.ty, - self.ecx.param_env); - match tail.sty { - ty::Dynamic(..) => { - let vtable = meta.unwrap(); - try_validation!( - self.ecx.memory.check_ptr_access( - vtable, - 3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, - ), - "dangling or unaligned vtable pointer or too small vtable", - self.path - ); - try_validation!(self.ecx.read_drop_type_from_vtable(vtable), - "invalid drop fn in vtable", self.path); - try_validation!(self.ecx.read_size_and_align_from_vtable(vtable), - "invalid size or align in vtable", self.path); - // FIXME: More checks for the vtable. - } - ty::Slice(..) | ty::Str => { - try_validation!(meta.unwrap().to_usize(self.ecx), - "non-integer slice length in fat pointer", self.path); - } - ty::Foreign(..) => { - // Unsized, but not fat. - } - _ => - bug!("Unexpected unsized type tail: {:?}", tail), - } + self.check_wide_ptr_meta(meta, layout)?; } // Make sure this is dereferencable and all. let (size, align) = self.ecx.size_and_align_of(meta, layout)? diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 12d763bb7910a..1f7efebfda819 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -180,12 +180,12 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::interpret::{AllocId, ConstValue}; use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem}; -use rustc::ty::subst::{InternalSubsts, SubstsRef}; +use rustc::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind, Instance}; use rustc::ty::print::obsolete::DefPathBasedNames; use rustc::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc::session::config::EntryFnType; -use rustc::mir::{self, Location, PlaceBase, Promoted, Static, StaticKind}; +use rustc::mir::{self, Location, PlaceBase, Static, StaticKind}; use rustc::mir::visit::Visitor as MirVisitor; use rustc::mir::mono::{MonoItem, InstantiationMode}; use rustc::mir::interpret::{Scalar, GlobalId, GlobalAlloc, ErrorHandled}; @@ -661,7 +661,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _context: mir::visit::PlaceContext, location: Location) { match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { debug!("visiting static {:?} @ {:?}", def_id, location); let tcx = self.tcx; @@ -670,8 +670,24 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(MonoItem::Static(*def_id)); } } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { - // FIXME: should we handle promoteds here instead of eagerly in collect_neighbours? + PlaceBase::Static(box Static { + kind: StaticKind::Promoted(promoted, substs), + def_id, + .. + }) => { + let param_env = ty::ParamEnv::reveal_all(); + let cid = GlobalId { + instance: Instance::new(*def_id, substs.subst(self.tcx, self.param_substs)), + promoted: Some(*promoted), + }; + match self.tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(self.tcx, val, substs, self.output), + Err(ErrorHandled::Reported) => {}, + Err(ErrorHandled::TooGeneric) => { + let span = self.tcx.promoted_mir(*def_id)[*promoted].span; + span_bug!(span, "collection encountered polymorphic constant") + }, + } } PlaceBase::Local(_) => { // Locals have no relevance for collector @@ -1202,7 +1218,7 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec { trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &((), inner) in alloc.relocations.values() { + for &((), inner) in alloc.relocations().values() { collect_miri(tcx, inner, output); } }, @@ -1222,6 +1238,7 @@ fn collect_neighbours<'tcx>( instance: Instance<'tcx>, output: &mut Vec>, ) { + debug!("collect_neighbours: {:?}", instance.def_id()); let body = tcx.instance_mir(instance.def); MirNeighborCollector { @@ -1230,22 +1247,6 @@ fn collect_neighbours<'tcx>( output, param_substs: instance.substs, }.visit_body(&body); - let param_env = ty::ParamEnv::reveal_all(); - for i in 0..body.promoted.len() { - use rustc_data_structures::indexed_vec::Idx; - let i = Promoted::new(i); - let cid = GlobalId { - instance, - promoted: Some(i), - }; - match tcx.const_eval(param_env.and(cid)) { - Ok(val) => collect_const(tcx, val, instance.substs, output), - Err(ErrorHandled::Reported) => {}, - Err(ErrorHandled::TooGeneric) => span_bug!( - body.promoted[i].span, "collection encountered polymorphic constant", - ), - } - } } fn def_id_to_string(tcx: TyCtxt<'_>, def_id: DefId) -> String { @@ -1268,7 +1269,7 @@ fn collect_const<'tcx>( collect_miri(tcx, ptr.alloc_id, output), ConstValue::Slice { data: alloc, start: _, end: _ } | ConstValue::ByRef { alloc, .. } => { - for &((), id) in alloc.relocations.values() { + for &((), id) in alloc.relocations().values() { collect_miri(tcx, id, output); } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 3e02f6c3725fd..aa83255bf62f4 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -112,7 +112,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx }; debug!("make_shim({:?}) = untransformed {:?}", instance, result); - run_passes(tcx, &mut result, instance, MirPhase::Const, &[ + run_passes(tcx, &mut result, instance, None, MirPhase::Const, &[ &add_moves_for_packed_drops::AddMovesForPackedDrops, &no_landing_pads::NoLandingPads, &remove_noop_landing_pads::RemoveNoopLandingPads, @@ -201,7 +201,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls_for_sig(&sig, span), IndexVec::new(), @@ -369,7 +368,6 @@ impl CloneShimBuilder<'tcx> { SourceScopeData { span: self.span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, self.local_decls, IndexVec::new(), @@ -813,7 +811,6 @@ fn build_call_shim<'tcx>( SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls, IndexVec::new(), @@ -900,7 +897,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &Body<'_> { SourceScopeData { span: span, parent_scope: None }, 1 ), ClearCrossCrate::Clear, - IndexVec::new(), None, local_decls, IndexVec::new(), diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs index c08c33bc6ff8b..15ecc6c37920b 100644 --- a/src/librustc_mir/transform/add_call_guards.rs +++ b/src/librustc_mir/transform/add_call_guards.rs @@ -30,8 +30,8 @@ pub use self::AddCallGuards::*; * */ -impl MirPass for AddCallGuards { - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddCallGuards { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { self.add_call_guards(body); } } diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 426e16698d74d..052631ddff371 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -39,8 +39,8 @@ use crate::util; pub struct AddMovesForPackedDrops; -impl MirPass for AddMovesForPackedDrops { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("add_moves_for_packed_drops({:?} @ {:?})", src, body.span); add_moves_for_packed_drops(tcx, body, src.def_id()); } diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index 524a19e3434f3..0fd75cd57b2ac 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -65,8 +65,8 @@ fn may_be_reference<'tcx>(ty: Ty<'tcx>) -> bool { } } -impl MirPass for AddRetag { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for AddRetag { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { if !tcx.sess.opts.debugging_opts.mir_emit_retag { return; } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index d5c5267a119d3..539922c54d12d 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -205,10 +205,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { PlaceBase::Local(..) => { // Locals are safe. } - PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => { + PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => { bug!("unsafety checking should happen before promotion") } - PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static { kind: StaticKind::Static, def_id, .. }) => { if self.tcx.is_mutable_static(*def_id) { self.require_unsafe("use of mutable static", "mutable statics can be mutated by multiple threads: aliasing \ diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 6ee14160bbd1b..ede1cb62f9451 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -26,8 +26,8 @@ pub struct CleanupNonCodegenStatements; pub struct DeleteNonCodegenStatements; -impl MirPass for CleanupNonCodegenStatements { - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut delete = DeleteNonCodegenStatements; delete.visit_body(body); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 98d8ca58ee164..f261fdc268b5b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -8,7 +8,7 @@ use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, - SourceScope, SourceScopeLocalData, LocalDecl, Promoted, + SourceScope, SourceScopeLocalData, LocalDecl, }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, @@ -27,14 +27,14 @@ use crate::interpret::{ ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState, }; use crate::const_eval::{ - CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, + CompileTimeInterpreter, error_to_const_error, mk_eval_cx, }; use crate::transform::{MirPass, MirSource}; pub struct ConstProp; -impl MirPass for ConstProp { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for ConstProp { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { // will be evaluated by miri and produce its errors there if source.promoted.is_some() { return; @@ -64,17 +64,12 @@ impl MirPass for ConstProp { &mut body.source_scope_local_data, ClearCrossCrate::Clear ); - let promoted = std::mem::replace( - &mut body.promoted, - IndexVec::new() - ); let dummy_body = &Body::new( body.basic_blocks().clone(), Default::default(), ClearCrossCrate::Clear, - Default::default(), None, body.local_decls.clone(), Default::default(), @@ -92,22 +87,17 @@ impl MirPass for ConstProp { body, dummy_body, source_scope_local_data, - promoted, tcx, source ); optimization_finder.visit_body(body); // put back the data we stole from `mir` - let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data(); + let source_scope_local_data = optimization_finder.release_stolen_data(); std::mem::replace( &mut body.source_scope_local_data, source_scope_local_data ); - std::mem::replace( - &mut body.promoted, - promoted - ); trace!("ConstProp done for {:?}", source.def_id()); } @@ -124,7 +114,6 @@ struct ConstPropagator<'mir, 'tcx> { param_env: ParamEnv<'tcx>, source_scope_local_data: ClearCrossCrate>, local_decls: IndexVec>, - promoted: IndexVec>, } impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> { @@ -155,7 +144,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { body: &Body<'tcx>, dummy_body: &'mir Body<'tcx>, source_scope_local_data: ClearCrossCrate>, - promoted: IndexVec>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'mir, 'tcx> { @@ -184,17 +172,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_scope_local_data, //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), - promoted, } } - fn release_stolen_data( - self, - ) -> ( - ClearCrossCrate>, - IndexVec>, - ) { - (self.source_scope_local_data, self.promoted) + fn release_stolen_data(self) -> ClearCrossCrate> { + self.source_scope_local_data } fn get_const(&self, local: Local) -> Option> { @@ -255,9 +237,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r = match f(self) { Ok(val) => Some(val), Err(error) => { - let diagnostic = error_to_const_error(&self.ecx, error); use rustc::mir::interpret::InterpError::*; - match diagnostic.error { + match error.kind { Exit(_) => bug!("the CTFE program cannot exit"), Unsupported(_) | UndefinedBehavior(_) @@ -266,6 +247,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // Ignore these errors. } Panic(_) => { + let diagnostic = error_to_const_error(&self.ecx, error); diagnostic.report_as_lint( self.ecx.tcx, "this expression will panic at runtime", @@ -303,7 +285,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { place.iterate(|place_base, place_projection| { let mut eval = match place_base { PlaceBase::Local(loc) => self.get_const(*loc).clone()?, - PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => { + PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted, _), ..}) => { let generics = self.tcx.generics_of(self.source.def_id()); if generics.requires_monomorphization(self.tcx) { // FIXME: can't handle code with generics @@ -315,11 +297,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { instance, promoted: Some(*promoted), }; - // cannot use `const_eval` here, because that would require having the MIR - // for the current function available, but we're producing said MIR right now let res = self.use_ecx(source_info, |this| { - let body = &this.promoted[*promoted]; - eval_promoted(this.tcx, cid, body, this.param_env) + this.ecx.const_eval_raw(cid) })?; trace!("evaluated promoted {:?} to {:?}", promoted, res); res.into() diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 7c9eeb5a57741..f3a523a813413 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -29,8 +29,8 @@ use crate::util::def_use::DefUseAnalysis; pub struct CopyPropagation; -impl MirPass for CopyPropagation { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for CopyPropagation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs index 1b42a0dffb894..1fc7ce09aa647 100644 --- a/src/librustc_mir/transform/deaggregator.rs +++ b/src/librustc_mir/transform/deaggregator.rs @@ -5,8 +5,8 @@ use crate::util::expand_aggregate; pub struct Deaggregator; -impl MirPass for Deaggregator { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for Deaggregator { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); let local_decls = &*local_decls; for bb in basic_blocks { diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index a6fb555f20bd0..ed0eff943a165 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -13,12 +13,12 @@ use crate::util as mir_util; pub struct Marker(pub &'static str); -impl MirPass for Marker { +impl<'tcx> MirPass<'tcx> for Marker { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(self.0) } - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, _body: &mut Body<'tcx>) { } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 4480d1e0a05b8..7a5c00c859629 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -20,8 +20,8 @@ use syntax_pos::Span; pub struct ElaborateDrops; -impl MirPass for ElaborateDrops { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for ElaborateDrops { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", src, body.span); let def_id = src.def_id(); diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 5a29ea21a7a04..21ca339eb968b 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -49,8 +49,8 @@ impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> { pub struct EraseRegions; -impl MirPass for EraseRegions { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for EraseRegions { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { EraseRegionsVisitor::new(tcx).visit_body(body); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index f694188024031..d87331195dd24 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -1115,8 +1115,8 @@ where }).collect() } -impl MirPass for StateTransform { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for StateTransform { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { let yield_ty = if let Some(yield_ty) = body.yield_ty { yield_ty } else { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index bc7bd39be488e..f31303c642faa 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -37,8 +37,8 @@ struct CallSite<'tcx> { location: SourceInfo, } -impl MirPass for Inline { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for Inline { + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { Inliner { tcx, source }.run_pass(body); } @@ -394,7 +394,6 @@ impl Inliner<'tcx> { let mut local_map = IndexVec::with_capacity(callee_body.local_decls.len()); let mut scope_map = IndexVec::with_capacity(callee_body.source_scopes.len()); - let mut promoted_map = IndexVec::with_capacity(callee_body.promoted.len()); for mut scope in callee_body.source_scopes.iter().cloned() { if scope.parent_scope.is_none() { @@ -420,10 +419,6 @@ impl Inliner<'tcx> { local_map.push(idx); } - promoted_map.extend( - callee_body.promoted.iter().cloned().map(|p| caller_body.promoted.push(p)) - ); - // If the call is something like `a[*i] = f(i)`, where // `i : &mut usize`, then just duplicating the `a[*i]` // Place could result in two different locations if `f` @@ -484,12 +479,10 @@ impl Inliner<'tcx> { args: &args, local_map, scope_map, - promoted_map, - _callsite: callsite, destination: dest, return_block, cleanup_block: cleanup, - in_cleanup_block: false + in_cleanup_block: false, }; @@ -644,8 +637,6 @@ struct Integrator<'a, 'tcx> { args: &'a [Local], local_map: IndexVec, scope_map: IndexVec, - promoted_map: IndexVec, - _callsite: CallSite<'tcx>, destination: Place<'tcx>, return_block: BasicBlock, cleanup_block: Option, @@ -698,17 +689,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { // Return pointer; update the place itself *place = self.destination.clone(); }, - Place { - base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted), - .. - }), - projection: None, - } => { - if let Some(p) = self.promoted_map.get(*promoted).cloned() { - *promoted = p; - } - }, _ => self.super_place(place, _ctxt, _location) } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index b2d063a1f4e10..abe41606e8079 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,8 +11,8 @@ use crate::transform::{MirPass, MirSource}; pub struct InstCombine; -impl MirPass for InstCombine { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { // We only run when optimizing MIR (at any level). if tcx.sess.opts.debugging_opts.mir_opt_level == 0 { return diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 61d0b1f3485b6..ac291c2996d06 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -137,60 +137,50 @@ pub fn default_name() -> Cow<'static, str> { /// A streamlined trait that you can implement to create a pass; the /// pass will be named after the type, and it will consist of a main /// loop that goes over each available MIR and applies `run_pass`. -pub trait MirPass { +pub trait MirPass<'tcx> { fn name(&self) -> Cow<'_, str> { default_name::() } - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); + fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>); } pub fn run_passes( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, instance: InstanceDef<'tcx>, + promoted: Option, mir_phase: MirPhase, - passes: &[&dyn MirPass], + passes: &[&dyn MirPass<'tcx>], ) { let phase_index = mir_phase.phase_index(); - let run_passes = |body: &mut Body<'tcx>, promoted| { - if body.phase >= mir_phase { - return; - } + if body.phase >= mir_phase { + return; + } - let source = MirSource { - instance, - promoted, - }; - let mut index = 0; - let mut run_pass = |pass: &dyn MirPass| { - let run_hooks = |body: &_, index, is_after| { - dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index), - &pass.name(), source, body, is_after); - }; - run_hooks(body, index, false); - pass.run_pass(tcx, source, body); - run_hooks(body, index, true); - - index += 1; + let source = MirSource { + instance, + promoted, + }; + let mut index = 0; + let mut run_pass = |pass: &dyn MirPass<'tcx>| { + let run_hooks = |body: &_, index, is_after| { + dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index), + &pass.name(), source, body, is_after); }; + run_hooks(body, index, false); + pass.run_pass(tcx, source, body); + run_hooks(body, index, true); - for pass in passes { - run_pass(*pass); - } - - body.phase = mir_phase; + index += 1; }; - run_passes(body, None); - - for (index, promoted_body) in body.promoted.iter_enumerated_mut() { - run_passes(promoted_body, Some(index)); - - //Let's make sure we don't miss any nested instances - assert!(promoted_body.promoted.is_empty()) + for pass in passes { + run_pass(*pass); } + + body.phase = mir_phase; } fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { @@ -198,7 +188,7 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { let _ = tcx.unsafety_check_result(def_id); let mut body = tcx.mir_built(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Const, &[ + run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Const, &[ // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, @@ -207,7 +197,10 @@ fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal> { tcx.alloc_steal_mir(body) } -fn mir_validated(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { +fn mir_validated( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (&'tcx Steal>, &'tcx Steal>>) { let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) { // Ensure that we compute the `mir_const_qualif` for constants at @@ -216,33 +209,23 @@ fn mir_validated(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Steal> { } let mut body = tcx.mir_const(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Validated, &[ + let qualify_and_promote_pass = qualify_consts::QualifyAndPromoteConstants::default(); + run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Validated, &[ // What we need to run borrowck etc. - &qualify_consts::QualifyAndPromoteConstants, + &qualify_and_promote_pass, &simplify::SimplifyCfg::new("qualify-consts"), ]); - tcx.alloc_steal_mir(body) + let promoted = qualify_and_promote_pass.promoted.into_inner(); + (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) } -fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { - if tcx.is_constructor(def_id) { - // There's no reason to run all of the MIR passes on constructors when - // we can just output the MIR we want directly. This also saves const - // qualification and borrow checking the trouble of special casing - // constructors. - return shim::build_adt_ctor(tcx, def_id); - } - - // (Mir-)Borrowck uses `mir_validated`, so we have to force it to - // execute before we can steal. - tcx.ensure().mir_borrowck(def_id); - - if tcx.use_ast_borrowck() { - tcx.ensure().borrowck(def_id); - } - - let mut body = tcx.mir_validated(def_id).steal(); - run_passes(tcx, &mut body, InstanceDef::Item(def_id), MirPhase::Optimized, &[ +fn run_optimization_passes<'tcx>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + def_id: DefId, + promoted: Option, +) { + run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[ // Remove all things only needed by analysis &no_landing_pads::NoLandingPads, &simplify_branches::SimplifyBranches::new("initial"), @@ -293,10 +276,43 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { &add_call_guards::CriticalCallEdges, &dump_mir::Marker("PreCodegen"), ]); +} + +fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> { + if tcx.is_constructor(def_id) { + // There's no reason to run all of the MIR passes on constructors when + // we can just output the MIR we want directly. This also saves const + // qualification and borrow checking the trouble of special casing + // constructors. + return shim::build_adt_ctor(tcx, def_id); + } + + // (Mir-)Borrowck uses `mir_validated`, so we have to force it to + // execute before we can steal. + tcx.ensure().mir_borrowck(def_id); + + if tcx.use_ast_borrowck() { + tcx.ensure().borrowck(def_id); + } + + let (body, _) = tcx.mir_validated(def_id); + let mut body = body.steal(); + run_optimization_passes(tcx, &mut body, def_id, None); tcx.arena.alloc(body) } fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec> { - let body = tcx.optimized_mir(def_id); - &body.promoted + if tcx.is_constructor(def_id) { + return tcx.intern_promoted(IndexVec::new()); + } + + tcx.ensure().mir_borrowck(def_id); + let (_, promoted) = tcx.mir_validated(def_id); + let mut promoted = promoted.steal(); + + for (p, mut body) in promoted.iter_enumerated_mut() { + run_optimization_passes(tcx, &mut body, def_id, Some(p)); + } + + tcx.intern_promoted(promoted) } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 841db80fc7dbb..762bb5d44839f 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -8,8 +8,8 @@ use crate::transform::{MirPass, MirSource}; pub struct NoLandingPads; -impl MirPass for NoLandingPads { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for NoLandingPads { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { no_landing_pads(tcx, body) } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 3090b63a7e993..cdccdfea39943 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -12,9 +12,11 @@ //! initialization and can otherwise silence errors, if //! move analysis runs after promotion on broken MIR. +use rustc::hir::def_id::DefId; use rustc::mir::*; use rustc::mir::visit::{PlaceContext, MutatingUseContext, MutVisitor, Visitor}; use rustc::mir::traversal::ReversePostorder; +use rustc::ty::subst::InternalSubsts; use rustc::ty::TyCtxt; use syntax_pos::Span; @@ -293,17 +295,28 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { new_temp } - fn promote_candidate(mut self, candidate: Candidate) { + fn promote_candidate( + mut self, + def_id: DefId, + candidate: Candidate, + next_promoted_id: usize, + ) -> Option> { let mut operand = { let promoted = &mut self.promoted; - let promoted_id = Promoted::new(self.source.promoted.len()); + let promoted_id = Promoted::new(next_promoted_id); + let tcx = self.tcx; let mut promoted_place = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new_return_place(ty, span); Place { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(promoted_id), - ty + kind: + StaticKind::Promoted( + promoted_id, + InternalSubsts::identity_for_item(tcx, def_id), + ), + ty, + def_id, }), projection: None, } @@ -319,7 +332,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = statement.source_info.span; Operand::Move(Place { - base: mem::replace(&mut place.base, promoted_place(ty, span).base), + base: mem::replace( + &mut place.base, + promoted_place(ty, span).base + ), projection: None, }) } @@ -332,7 +348,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => { let ty = operand.ty(local_decls, self.tcx); let span = statement.source_info.span; - mem::replace(operand, Operand::Copy(promoted_place(ty, span))) + mem::replace( + operand, + Operand::Copy(promoted_place(ty, span)) + ) } _ => bug!() } @@ -353,7 +372,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { // a function requiring a constant argument and as that constant value // providing a value whose computation contains another call to a function // requiring a constant argument. - TerminatorKind::Goto { .. } => return, + TerminatorKind::Goto { .. } => return None, _ => bug!() } } @@ -368,7 +387,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let span = self.promoted.span; self.assign(RETURN_PLACE, Rvalue::Use(operand), span); - self.source.promoted.push(self.promoted); + Some(self.promoted) } } @@ -385,14 +404,17 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { } pub fn promote_candidates<'tcx>( + def_id: DefId, body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>, mut temps: IndexVec, candidates: Vec, -) { +) -> IndexVec> { // Visit candidates in reverse, in case they're nested. debug!("promote_candidates({:?})", candidates); + let mut promotions = IndexVec::new(); + for candidate in candidates.into_iter().rev() { match candidate { Candidate::Repeat(Location { block, statement_index }) | @@ -426,7 +448,6 @@ pub fn promote_candidates<'tcx>( // memory usage? body.source_scopes.clone(), body.source_scope_local_data.clone(), - IndexVec::new(), None, initial_locals, IndexVec::new(), @@ -440,7 +461,11 @@ pub fn promote_candidates<'tcx>( temps: &mut temps, keep_original: false }; - promoter.promote_candidate(candidate); + + //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice + if let Some(promoted) = promoter.promote_candidate(def_id, candidate, promotions.len()) { + promotions.push(promoted); + } } // Eliminate assignments to, and drops of promoted temps. @@ -474,4 +499,6 @@ pub fn promote_candidates<'tcx>( _ => {} } } + + promotions } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 649cccc36c346..a77421ce15008 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -25,6 +25,7 @@ use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; +use std::cell::Cell; use std::fmt; use std::ops::{Deref, Index, IndexMut}; use std::usize; @@ -222,7 +223,7 @@ trait Qualif { } => Self::in_local(cx, *local), PlaceRef { base: PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), projection: None, @@ -433,13 +434,13 @@ impl Qualif for IsNotPromotable { fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool { match static_.kind { - StaticKind::Promoted(_) => unreachable!(), - StaticKind::Static(def_id) => { + StaticKind::Promoted(_, _) => unreachable!(), + StaticKind::Static => { // Only allow statics (not consts) to refer to other statics. let allowed = cx.mode == Mode::Static || cx.mode == Mode::StaticMut; !allowed || - cx.tcx.get_attrs(def_id).iter().any( + cx.tcx.get_attrs(static_.def_id).iter().any( |attr| attr.check_name(sym::thread_local) ) } @@ -872,7 +873,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { dest_projection = &proj.base; }, (&PlaceBase::Static(box Static { - kind: StaticKind::Promoted(_), + kind: StaticKind::Promoted(..), .. }), None) => bug!("promoteds don't exist yet during promotion"), (&PlaceBase::Static(box Static{ kind: _, .. }), None) => { @@ -1027,10 +1028,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.super_place_base(place_base, context, location); match place_base { PlaceBase::Local(_) => {} - PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. }) => { + PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) => { unreachable!() } - PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) => { + PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => { if self.tcx .get_attrs(*def_id) .iter() @@ -1570,10 +1571,20 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> (u8, &BitSet) { Checker::new(tcx, def_id, body, Mode::Const).check_const() } -pub struct QualifyAndPromoteConstants; +pub struct QualifyAndPromoteConstants<'tcx> { + pub promoted: Cell>>, +} + +impl<'tcx> Default for QualifyAndPromoteConstants<'tcx> { + fn default() -> Self { + QualifyAndPromoteConstants { + promoted: Cell::new(IndexVec::new()), + } + } +} -impl MirPass for QualifyAndPromoteConstants { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants<'tcx> { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { // There's not really any point in promoting errorful MIR. if body.return_ty().references_error() { tcx.sess.delay_span_bug(body.span, "QualifyAndPromoteConstants: MIR had errors"); @@ -1649,7 +1660,9 @@ impl MirPass for QualifyAndPromoteConstants { }; // Do the actual promotion, now that we know what's viable. - promote_consts::promote_candidates(body, tcx, temps, candidates); + self.promoted.set( + promote_consts::promote_candidates(def_id, body, tcx, temps, candidates) + ); } else { if !body.control_flow_destroyed.is_empty() { let mut locals = body.vars_iter(); @@ -1739,7 +1752,10 @@ impl MirPass for QualifyAndPromoteConstants { fulfillment_cx.register_bound(&infcx, param_env, ty, - tcx.require_lang_item(lang_items::SyncTraitLangItem), + tcx.require_lang_item( + lang_items::SyncTraitLangItem, + Some(body.span) + ), cause); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err, None, false); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 334d0cee9fbe7..56093527aee24 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -264,11 +264,11 @@ fn check_place( } match place_base { - PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => { + PlaceBase::Static(box Static { kind: StaticKind::Static, .. }) => { Err((span, "cannot access `static` items in const fn".into())) } PlaceBase::Local(_) - | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()), + | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_, _), .. }) => Ok(()), } }) } diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs index adba9097d12df..73089a2106f6b 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs @@ -18,8 +18,8 @@ pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) RemoveNoopLandingPads.remove_nop_landing_pads(body) } -impl MirPass for RemoveNoopLandingPads { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { remove_noop_landing_pads(tcx, body); } } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 598de3a77e61c..1d3bf247387a7 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -23,8 +23,8 @@ use crate::dataflow::has_rustc_mir_with; pub struct SanityCheck; -impl MirPass for SanityCheck { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for SanityCheck { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let def_id = src.def_id(); if !tcx.has_attr(def_id, sym::rustc_mir) { debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index 2eed9d453f233..d4599ee08aa46 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -52,12 +52,12 @@ pub fn simplify_cfg(body: &mut Body<'_>) { body.basic_blocks_mut().raw.shrink_to_fit(); } -impl MirPass for SimplifyCfg { +impl<'tcx> MirPass<'tcx> for SimplifyCfg { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body); simplify_cfg(body); } @@ -292,8 +292,8 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { pub struct SimplifyLocals; -impl MirPass for SimplifyLocals { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()) }; marker.visit_body(body); // Return pointer and arguments are always live diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 9ffa3db4c2eb0..0a509666d34ae 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -14,12 +14,12 @@ impl SimplifyBranches { } } -impl MirPass for SimplifyBranches { +impl<'tcx> MirPass<'tcx> for SimplifyBranches { fn name(&self) -> Cow<'_, str> { Cow::Borrowed(&self.label) } - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let param_env = tcx.param_env(src.def_id()); for block in body.basic_blocks_mut() { let terminator = block.terminator_mut(); diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index 60489e7fa3668..8199a252e78b0 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -36,8 +36,8 @@ use crate::util::patch::MirPatch; pub struct UniformArrayMoveOut; -impl MirPass for UniformArrayMoveOut { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { @@ -184,8 +184,8 @@ impl<'a, 'tcx> UniformArrayMoveOutVisitor<'a, 'tcx> { pub struct RestoreSubsliceArrayMoveOut; -impl MirPass for RestoreSubsliceArrayMoveOut { - fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { +impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { let mut patch = MirPatch::new(body); let param_env = tcx.param_env(src.def_id()); { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index c5561a1ae0d15..f3e03e7f81daa 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -897,7 +897,10 @@ where ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::from(self.new_temp(tcx.mk_unit())); - let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); + let free_func = tcx.require_lang_item( + lang_items::BoxFreeFnLangItem, + Some(self.source_info.span) + ); let args = adt.variants[VariantIdx::new(0)].fields.iter().enumerate().map(|(i, f)| { let field = Field::new(i); let field_ty = f.ty(self.tcx(), substs); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bd46ca4779a43..5b78727fdd5ad 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -813,8 +813,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_poly_trait_ref(self, t, m); } - fn visit_variant_data(&mut self, s: &'a VariantData, _: Ident, - _: &'a Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } diff --git a/src/librustc_passes/error_codes.rs b/src/librustc_passes/error_codes.rs index cd33943e77e20..a30cd8a627fe3 100644 --- a/src/librustc_passes/error_codes.rs +++ b/src/librustc_passes/error_codes.rs @@ -131,7 +131,7 @@ be taken. Erroneous code example: ```compile_fail,E0268 fn some_func() { - break; // error: `break` outside of loop + break; // error: `break` outside of a loop } ``` diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 8fba3256ec429..a5924efefc2af 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -94,9 +94,9 @@ impl<'k> StatCollector<'k> { } impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { - fn visit_arg(&mut self, arg: &'v hir::Arg) { - self.record("Arg", Id::Node(arg.hir_id), arg); - hir_visit::walk_arg(self, arg) + fn visit_param(&mut self, param: &'v hir::Param) { + self.record("Param", Id::Node(param.hir_id), param); + hir_visit::walk_param(self, param) } fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> { @@ -334,12 +334,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_struct_field(self, s) } - fn visit_variant(&mut self, - v: &'v ast::Variant, - g: &'v ast::Generics, - item_id: NodeId) { + fn visit_variant(&mut self, v: &'v ast::Variant) { self.record("Variant", Id::None, v); - ast_visit::walk_variant(self, v, g, item_id) + ast_visit::walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 1547e607b9c61..dbfbec32a6fbf 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -16,8 +16,8 @@ use errors::Applicability; enum Context { Normal, Loop(hir::LoopSource), - Closure, - AsyncClosure, + Closure(Span), + AsyncClosure(Span), LabeledBlock, AnonConst, } @@ -58,11 +58,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Loop(ref b, _, source) => { self.with_context(Loop(source), |v| v.visit_block(&b)); } - hir::ExprKind::Closure(_, ref function_decl, b, _, movability) => { + hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => { let cx = if let Some(GeneratorMovability::Static) = movability { - AsyncClosure + AsyncClosure(span) } else { - Closure + Closure(span) }; self.visit_fn_decl(&function_decl); self.with_context(cx, |v| v.visit_nested_body(b)); @@ -170,23 +170,22 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { } fn require_break_cx(&self, name: &str, span: Span) { - match self.cx { - LabeledBlock | Loop(_) => {} - Closure => { - struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name) - .span_label(span, "cannot break inside of a closure") + let err_inside_of = |article, ty, closure_span| { + struct_span_err!(self.sess, span, E0267, "`{}` inside of {} {}", name, article, ty) + .span_label(span, format!("cannot `{}` inside of {} {}", name, article, ty)) + .span_label(closure_span, &format!("enclosing {}", ty)) .emit(); - } - AsyncClosure => { - struct_span_err!(self.sess, span, E0267, "`{}` inside of an async block", name) - .span_label(span, "cannot break inside of an async block") - .emit(); - } + }; + + match self.cx { + LabeledBlock | Loop(_) => {}, + Closure(closure_span) => err_inside_of("a", "closure", closure_span), + AsyncClosure(closure_span) => err_inside_of("an", "`async` block", closure_span), Normal | AnonConst => { - struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name) - .span_label(span, "cannot break outside of a loop") + struct_span_err!(self.sess, span, E0268, "`{}` outside of a loop", name) + .span_label(span, format!("cannot `{}` outside of a loop", name)) .emit(); - } + }, } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index bca77621e553e..146058963b69d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -508,11 +508,7 @@ impl EmbargoVisitor<'tcx> { } } - fn update_macro_reachable_mod( - &mut self, - reachable_mod: hir::HirId, - defining_mod: DefId, - ) { + fn update_macro_reachable_mod(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) { let module_def_id = self.tcx.hir().local_def_id(reachable_mod); let module = self.tcx.hir().get_module(module_def_id).0; for item_id in &module.item_ids { @@ -524,19 +520,13 @@ impl EmbargoVisitor<'tcx> { self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod); } } - if let Some(exports) = self.tcx.module_exports(module_def_id) { for export in exports { if export.vis.is_accessible_from(defining_mod, self.tcx) { if let Res::Def(def_kind, def_id) = export.res { let vis = def_id_visibility(self.tcx, def_id).0; if let Some(hir_id) = self.tcx.hir().as_local_hir_id(def_id) { - self.update_macro_reachable_def( - hir_id, - def_kind, - vis, - defining_mod, - ); + self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod); } } } @@ -892,10 +882,14 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { self.tcx.hir().local_def_id(md.hir_id) ).unwrap(); let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap(); + if !self.tcx.hir().is_hir_id_module(module_id) { + // `module_id` doesn't correspond to a `mod`, return early (#63164). + return; + } let level = if md.vis.node.is_pub() { self.get(module_id) } else { None }; let new_level = self.update(md.hir_id, level); if new_level.is_none() { - return + return; } loop { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 42428456b6eec..165a4c707bb6d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -145,17 +145,17 @@ impl<'a> Resolver<'a> { } } - fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { + crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option> { if let Some(ext) = self.macro_map.get(&def_id) { return Some(ext.clone()); } - let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) { - LoadedMacro::MacroDef(macro_def) => macro_def, - LoadedMacro::ProcMacro(ext) => return Some(ext), - }; + let ext = Lrc::new(match self.cstore.load_macro_untracked(def_id, &self.session) { + LoadedMacro::MacroDef(item) => + self.compile_macro(&item, self.cstore.crate_edition_untracked(def_id.krate)), + LoadedMacro::ProcMacro(ext) => ext, + }); - let ext = self.compile_macro(¯o_def, self.cstore.crate_edition_untracked(def_id.krate)); self.macro_map.insert(def_id, ext.clone()); Some(ext) } @@ -1104,7 +1104,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let expansion = parent_scope.expansion; let (ext, ident, span, is_legacy) = match &item.node { ItemKind::MacroDef(def) => { - let ext = self.r.compile_macro(item, self.r.session.edition()); + let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition())); (ext, item.ident, item.span, def.legacy) } ItemKind::Fn(..) => match Self::proc_macro_stub(item) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2dd0ad13c526d..875ae449d94e0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1647,10 +1647,14 @@ impl<'a> Resolver<'a> { if module.expansion != parent.expansion && module.expansion.is_descendant_of(parent.expansion) { // The macro is a proc macro derive - if module.expansion.looks_like_proc_macro_derive() { - if parent.expansion.outer_expn_is_descendant_of(span.ctxt()) { - *poisoned = Some(node_id); - return module.parent; + if let Some(&def_id) = self.macro_defs.get(&module.expansion) { + if let Some(ext) = self.get_macro_by_def_id(def_id) { + if !ext.is_builtin && ext.macro_kind() == MacroKind::Derive { + if parent.expansion.outer_expn_is_descendant_of(span.ctxt()) { + *poisoned = Some(node_id); + return module.parent; + } + } } } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 01ad67252a387..7224bd74230b3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -13,7 +13,7 @@ use rustc::{ty, lint, span_bug}; use syntax::ast::{self, NodeId, Ident}; use syntax::attr::StabilityLevel; use syntax::edition::Edition; -use syntax::ext::base::{self, Indeterminate, SpecialDerives}; +use syntax::ext::base::{self, InvocationRes, Indeterminate, SpecialDerives}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, ExpnId, ExpnData, ExpnKind}; @@ -140,9 +140,23 @@ impl<'a> base::Resolver for Resolver<'a> { ImportResolver { r: self }.resolve_imports() } - fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) - -> Result>, Indeterminate> { - let parent_scope = self.invocation_parent_scopes[&invoc_id]; + fn resolve_macro_invocation( + &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool + ) -> Result { + let invoc_id = invoc.expansion_data.id; + let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) { + Some(parent_scope) => *parent_scope, + None => { + // If there's no entry in the table, then we are resolving an eagerly expanded + // macro, which should inherit its parent scope from its eager expansion root - + // the macro that requested this eager expansion. + let parent_scope = *self.invocation_parent_scopes.get(&eager_expansion_root) + .expect("non-eager expansion without a parent scope"); + self.invocation_parent_scopes.insert(invoc_id, parent_scope); + parent_scope + } + }; + let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), @@ -151,25 +165,24 @@ impl<'a> base::Resolver for Resolver<'a> { InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, &[][..], false), InvocationKind::DeriveContainer { ref derives, .. } => { - // Block expansion of derives in the container until we know whether one of them - // is a built-in `Copy`. Skip the resolution if there's only one derive - either - // it's not a `Copy` and we don't need to do anything, or it's a `Copy` and it - // will automatically knows about itself. - let mut result = Ok(None); - if derives.len() > 1 { - for path in derives { - match self.resolve_macro_path(path, Some(MacroKind::Derive), - &parent_scope, true, force) { - Ok((Some(ref ext), _)) if ext.is_derive_copy => { - self.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); - return Ok(None); - } - Err(Determinacy::Undetermined) => result = Err(Indeterminate), - _ => {} - } - } + // Block expansion of the container until we resolve all derives in it. + // This is required for two reasons: + // - Derive helper attributes are in scope for the item to which the `#[derive]` + // is applied, so they have to be produced by the container's expansion rather + // than by individual derives. + // - Derives in the container need to know whether one of them is a built-in `Copy`. + // FIXME: Try to avoid repeated resolutions for derives here and in expansion. + let mut exts = Vec::new(); + for path in derives { + exts.push(match self.resolve_macro_path( + path, Some(MacroKind::Derive), &parent_scope, true, force + ) { + Ok((Some(ext), _)) => ext, + Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive), + Err(Determinacy::Undetermined) => return Err(Indeterminate), + }) } - return result; + return Ok(InvocationRes::DeriveContainer(exts)); } }; @@ -178,22 +191,18 @@ impl<'a> base::Resolver for Resolver<'a> { let (ext, res) = self.smart_resolve_macro_path(path, kind, parent_scope, force)?; let span = invoc.span(); - invoc.expansion_data.id.set_expn_data( - ext.expn_data(parent_scope.expansion, span, fast_print_path(path)) - ); + invoc_id.set_expn_data(ext.expn_data(parent_scope.expansion, span, fast_print_path(path))); if let Res::Def(_, def_id) = res { if after_derive { self.session.span_err(span, "macro attributes must be placed before `#[derive]`"); } - self.macro_defs.insert(invoc.expansion_data.id, def_id); - let normal_module_def_id = - self.macro_def_scope(invoc.expansion_data.id).normal_ancestor_id; - self.definitions.add_parent_module_of_macro_def(invoc.expansion_data.id, - normal_module_def_id); + self.macro_defs.insert(invoc_id, def_id); + let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id; + self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); } - Ok(Some(ext)) + Ok(InvocationRes::Single(ext)) } fn check_unused_macros(&self) { @@ -790,7 +799,7 @@ impl<'a> Resolver<'a> { /// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined /// extension partially or entirely for built-in macros and legacy plugin macros. - crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> Lrc { + crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension { let mut result = macro_rules::compile( &self.session.parse_sess, self.session.features_untracked(), item, edition ); @@ -812,6 +821,6 @@ impl<'a> Resolver<'a> { } } - Lrc::new(result) + result } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9068605b0753c..d1fd51a97f683 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -230,7 +230,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { } } - fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) { + fn process_formals(&mut self, formals: &'l [ast::Param], qualname: &str) { for arg in formals { self.visit_pat(&arg.pat); let mut collector = PathCollector::new(); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 0bbbbb8249c20..92ccd4f49f6b9 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -32,7 +32,7 @@ use syntax::source_map::Spanned; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::print::pprust; use syntax::visit::{self, Visitor}; -use syntax::print::pprust::{arg_to_string, ty_to_string}; +use syntax::print::pprust::{param_to_string, ty_to_string}; use syntax_pos::*; use dump_visitor::DumpVisitor; @@ -934,7 +934,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig.push('('); sig.push_str(&decl.inputs .iter() - .map(arg_to_string) + .map(param_to_string) .collect::>() .join(", ")); sig.push(')'); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index fc25eb44cbd88..7427ae9ce8de3 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -1,631 +1,12 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs}; use crate::check::coercion::CoerceMany; -use crate::util::nodemap::FxHashMap; -use errors::{Applicability, DiagnosticBuilder}; -use rustc::hir::{self, PatKind, Pat, ExprKind}; -use rustc::hir::def::{Res, DefKind, CtorKind}; -use rustc::hir::pat_util::EnumerateAndAdjustIterator; -use rustc::hir::ptr::P; -use rustc::infer; +use rustc::hir::{self, ExprKind}; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc::traits::{ObligationCause, ObligationCauseCode}; -use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::subst::Kind; -use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use rustc::ty::Ty; use syntax_pos::Span; -use syntax_pos::hygiene::DesugaringKind; - -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::cmp; - -use super::report_unexpected_variant_res; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match - /// expression arm guard, and it points to the match discriminant to add context in type errors. - /// In the following example, `discrim_span` corresponds to the `a + b` expression: - /// - /// ```text - /// error[E0308]: mismatched types - /// --> src/main.rs:5:9 - /// | - /// 4 | let temp: usize = match a + b { - /// | ----- this expression has type `usize` - /// 5 | Ok(num) => num, - /// | ^^^^^^^ expected usize, found enum `std::result::Result` - /// | - /// = note: expected type `usize` - /// found type `std::result::Result<_, _>` - /// ``` - pub fn check_pat_walk( - &self, - pat: &'tcx hir::Pat, - mut expected: Ty<'tcx>, - mut def_bm: ty::BindingMode, - discrim_span: Option, - ) { - let tcx = self.tcx; - - debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); - - let mut path_resolution = None; - let is_non_ref_pat = match pat.node { - PatKind::Struct(..) | - PatKind::TupleStruct(..) | - PatKind::Or(_) | - PatKind::Tuple(..) | - PatKind::Box(_) | - PatKind::Range(..) | - PatKind::Slice(..) => true, - PatKind::Lit(ref lt) => { - let ty = self.check_expr(lt); - match ty.sty { - ty::Ref(..) => false, - _ => true, - } - } - PatKind::Path(ref qpath) => { - let resolution = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); - path_resolution = Some(resolution); - match resolution.0 { - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false, - _ => true, - } - } - PatKind::Wild | - PatKind::Binding(..) | - PatKind::Ref(..) => false, - }; - if is_non_ref_pat { - debug!("pattern is non reference pattern"); - let mut exp_ty = self.resolve_type_vars_with_obligations(&expected); - - // Peel off as many `&` or `&mut` from the discriminant as possible. For example, - // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches - // the `Some(5)` which is not of type Ref. - // - // For each ampersand peeled off, update the binding mode and push the original - // type into the adjustments vector. - // - // See the examples in `ui/match-defbm*.rs`. - let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = exp_ty.sty { - debug!("inspecting {:?}", exp_ty); - - debug!("current discriminant is Ref, inserting implicit deref"); - // Preserve the reference type. We'll need it later during HAIR lowering. - pat_adjustments.push(exp_ty); - - exp_ty = inner_ty; - def_bm = match def_bm { - // If default binding mode is by value, make it `ref` or `ref mut` - // (depending on whether we observe `&` or `&mut`). - ty::BindByValue(_) => - ty::BindByReference(inner_mutability), - - // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate - // the underlying value. - ty::BindByReference(hir::Mutability::MutImmutable) => - ty::BindByReference(hir::Mutability::MutImmutable), - - // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` - // (on `&`). - ty::BindByReference(hir::Mutability::MutMutable) => - ty::BindByReference(inner_mutability), - }; - } - expected = exp_ty; - - if pat_adjustments.len() > 0 { - debug!("default binding mode is now {:?}", def_bm); - self.inh.tables.borrow_mut() - .pat_adjustments_mut() - .insert(pat.hir_id, pat_adjustments); - } - } else if let PatKind::Ref(..) = pat.node { - // When you encounter a `&pat` pattern, reset to "by - // value". This is so that `x` and `y` here are by value, - // as they appear to be: - // - // ``` - // match &(&22, &44) { - // (&x, &y) => ... - // } - // ``` - // - // See issue #46688. - def_bm = ty::BindByValue(hir::MutImmutable); - } - - // Lose mutability now that we know binding mode and discriminant type. - let def_bm = def_bm; - let expected = expected; - - let ty = match pat.node { - PatKind::Wild => { - expected - } - PatKind::Lit(ref lt) => { - // We've already computed the type above (when checking for a non-ref pat), so - // avoid computing it again. - let ty = self.node_ty(lt.hir_id); - - // Byte string patterns behave the same way as array patterns - // They can denote both statically and dynamically-sized byte arrays. - let mut pat_ty = ty; - if let hir::ExprKind::Lit(ref lt) = lt.node { - if let ast::LitKind::ByteStr(_) = lt.node { - let expected_ty = self.structurally_resolved_type(pat.span, expected); - if let ty::Ref(_, r_ty, _) = expected_ty.sty { - if let ty::Slice(_) = r_ty.sty { - pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, - tcx.mk_slice(tcx.types.u8)) - } - } - } - } - - // Somewhat surprising: in this case, the subtyping - // relation goes the opposite way as the other - // cases. Actually what we really want is not a subtyping - // relation at all but rather that there exists a LUB (so - // that they can be compared). However, in practice, - // constants are always scalars or strings. For scalars - // subtyping is irrelevant, and for strings `ty` is - // type is `&'static str`, so if we say that - // - // &'static str <: expected - // - // then that's equivalent to there existing a LUB. - if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) { - err.emit_unless(discrim_span - .filter(|&s| { - // In the case of `if`- and `while`-expressions we've already checked - // that `scrutinee: bool`. We know that the pattern is `true`, - // so an error here would be a duplicate and from the wrong POV. - s.is_desugaring(DesugaringKind::CondTemporary) - }) - .is_some()); - } - - pat_ty - } - PatKind::Range(ref begin, ref end, _) => { - let lhs_ty = self.check_expr(begin); - let rhs_ty = self.check_expr(end); - - // Check that both end-points are of numeric or char type. - let numeric_or_char = |ty: Ty<'_>| { - ty.is_numeric() - || ty.is_char() - || ty.references_error() - }; - let lhs_compat = numeric_or_char(lhs_ty); - let rhs_compat = numeric_or_char(rhs_ty); - - if !lhs_compat || !rhs_compat { - let span = if !lhs_compat && !rhs_compat { - pat.span - } else if !lhs_compat { - begin.span - } else { - end.span - }; - - let mut err = struct_span_err!( - tcx.sess, - span, - E0029, - "only char and numeric types are allowed in range patterns" - ); - err.span_label(span, "ranges require char or numeric types"); - err.note(&format!("start type: {}", self.ty_to_string(lhs_ty))); - err.note(&format!("end type: {}", self.ty_to_string(rhs_ty))); - if tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "In a match expression, only numbers and characters can be matched \ - against a range. This is because the compiler checks that the range \ - is non-empty at compile-time, and is unable to evaluate arbitrary \ - comparison functions. If you want to capture values of an orderable \ - type between two end-points, you can use a guard." - ); - } - err.emit(); - return; - } - - // Now that we know the types can be unified we find the unified type and use - // it to type the entire expression. - let common_type = self.resolve_vars_if_possible(&lhs_ty); - - // Subtyping doesn't matter here, as the value is some kind of scalar. - self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span); - self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span); - common_type - } - PatKind::Binding(ba, var_id, _, ref sub) => { - let bm = if ba == hir::BindingAnnotation::Unannotated { - def_bm - } else { - ty::BindingMode::convert(ba) - }; - self.inh - .tables - .borrow_mut() - .pat_binding_modes_mut() - .insert(pat.hir_id, bm); - debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); - let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; - match bm { - ty::BindByReference(mutbl) => { - // If the binding is like - // ref x | ref const x | ref mut x - // then `x` is assigned a value of type `&M T` where M is the mutability - // and T is the expected type. - let region_var = self.next_region_var(infer::PatternRegion(pat.span)); - let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; - let region_ty = tcx.mk_ref(region_var, mt); - - // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is - // required. However, we use equality, which is stronger. See (*) for - // an explanation. - self.demand_eqtype_pat(pat.span, region_ty, local_ty, discrim_span); - } - // Otherwise, the type of x is the expected type `T`. - ty::BindByValue(_) => { - // As above, `T <: typeof(x)` is required, but we - // use equality, see (*) below. - self.demand_eqtype_pat(pat.span, expected, local_ty, discrim_span); - } - } - - // If there are multiple arms, make sure they all agree on - // what the type of the binding `x` ought to be. - if var_id != pat.hir_id { - let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); - } - - if let Some(ref p) = *sub { - self.check_pat_walk(&p, expected, def_bm, discrim_span); - } - - local_ty - } - PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { - self.check_pat_tuple_struct( - pat, - qpath, - &subpats, - ddpos, - expected, - def_bm, - discrim_span, - ) - } - PatKind::Path(ref qpath) => { - self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) - } - PatKind::Struct(ref qpath, ref fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) - } - PatKind::Or(ref pats) => { - let expected_ty = self.structurally_resolved_type(pat.span, expected); - for pat in pats { - self.check_pat_walk(pat, expected, def_bm, discrim_span); - } - expected_ty - } - PatKind::Tuple(ref elements, ddpos) => { - let mut expected_len = elements.len(); - if ddpos.is_some() { - // Require known type only when `..` is present. - if let ty::Tuple(ref tys) = - self.structurally_resolved_type(pat.span, expected).sty { - expected_len = tys.len(); - } - } - let max_len = cmp::max(expected_len, elements.len()); - - let element_tys_iter = (0..max_len).map(|_| { - Kind::from(self.next_ty_var( - // FIXME: `MiscVariable` for now -- obtaining the span and name information - // from all tuple elements isn't trivial. - TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: pat.span, - }, - )) - }); - let element_tys = tcx.mk_substs(element_tys_iter); - let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); - if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) { - err.emit(); - // Walk subpatterns with an expected type of `err` in this case to silence - // further errors being emitted when using the bindings. #50333 - let element_tys_iter = (0..max_len).map(|_| tcx.types.err); - for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &tcx.types.err, def_bm, discrim_span); - } - tcx.mk_tup(element_tys_iter) - } else { - for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk( - elem, - &element_tys[i].expect_ty(), - def_bm, - discrim_span, - ); - } - pat_ty - } - } - PatKind::Box(ref inner) => { - let inner_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: inner.span, - }); - let uniq_ty = tcx.mk_box(inner_ty); - - if self.check_dereferencable(pat.span, expected, &inner) { - // Here, `demand::subtype` is good enough, but I don't - // think any errors can be introduced by using - // `demand::eqtype`. - self.demand_eqtype_pat(pat.span, expected, uniq_ty, discrim_span); - self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); - uniq_ty - } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); - tcx.types.err - } - } - PatKind::Ref(ref inner, mutbl) => { - let expected = self.shallow_resolve(expected); - if self.check_dereferencable(pat.span, expected, &inner) { - // `demand::subtype` would be good enough, but using - // `eqtype` turns out to be equally general. See (*) - // below for details. - - // Take region, inner-type from expected type if we - // can, to avoid creating needless variables. This - // also helps with the bad interactions of the given - // hack detailed in (*) below. - debug!("check_pat_walk: expected={:?}", expected); - let (rptr_ty, inner_ty) = match expected.sty { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => { - (expected, r_ty) - } - _ => { - let inner_ty = self.next_ty_var( - TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span: inner.span, - } - ); - let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; - let region = self.next_region_var(infer::PatternRegion(pat.span)); - let rptr_ty = tcx.mk_ref(region, mt); - debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty); - let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); - - // Look for a case like `fn foo(&foo: u32)` and suggest - // `fn foo(foo: &u32)` - if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); - err.emit(); - } - (rptr_ty, inner_ty) - } - }; - - self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); - rptr_ty - } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); - tcx.types.err - } - } - PatKind::Slice(ref before, ref slice, ref after) => { - let expected_ty = self.structurally_resolved_type(pat.span, expected); - let (inner_ty, slice_ty) = match expected_ty.sty { - ty::Array(inner_ty, size) => { - if let Some(size) = size.try_eval_usize(tcx, self.param_env) { - let min_len = before.len() as u64 + after.len() as u64; - if slice.is_none() { - if min_len != size { - struct_span_err!( - tcx.sess, pat.span, E0527, - "pattern requires {} elements but array has {}", - min_len, size) - .span_label(pat.span, format!("expected {} elements", size)) - .emit(); - } - (inner_ty, tcx.types.err) - } else if let Some(rest) = size.checked_sub(min_len) { - (inner_ty, tcx.mk_array(inner_ty, rest)) - } else { - struct_span_err!(tcx.sess, pat.span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size) - .span_label(pat.span, - format!("pattern cannot match array of {} elements", size)) - .emit(); - (inner_ty, tcx.types.err) - } - } else { - struct_span_err!( - tcx.sess, - pat.span, - E0730, - "cannot pattern-match on an array without a fixed length", - ).emit(); - (inner_ty, tcx.types.err) - } - } - ty::Slice(inner_ty) => (inner_ty, expected_ty), - _ => { - if !expected_ty.references_error() { - let mut err = struct_span_err!( - tcx.sess, pat.span, E0529, - "expected an array or slice, found `{}`", - expected_ty); - if let ty::Ref(_, ty, _) = expected_ty.sty { - match ty.sty { - ty::Array(..) | ty::Slice(..) => { - err.help("the semantics of slice patterns changed \ - recently; see issue #62254"); - } - _ => {} - } - } - - err.span_label( pat.span, - format!("pattern cannot match with input type `{}`", expected_ty) - ).emit(); - } - (tcx.types.err, tcx.types.err) - } - }; - - for elt in before { - self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); - } - if let Some(ref slice) = *slice { - self.check_pat_walk(&slice, slice_ty, def_bm, discrim_span); - } - for elt in after { - self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); - } - expected_ty - } - }; - - self.write_ty(pat.hir_id, ty); - - // (*) In most of the cases above (literals and constants being - // the exception), we relate types using strict equality, even - // though subtyping would be sufficient. There are a few reasons - // for this, some of which are fairly subtle and which cost me - // (nmatsakis) an hour or two debugging to remember, so I thought - // I'd write them down this time. - // - // 1. There is no loss of expressiveness here, though it does - // cause some inconvenience. What we are saying is that the type - // of `x` becomes *exactly* what is expected. This can cause unnecessary - // errors in some cases, such as this one: - // - // ``` - // fn foo<'x>(x: &'x int) { - // let a = 1; - // let mut z = x; - // z = &a; - // } - // ``` - // - // The reason we might get an error is that `z` might be - // assigned a type like `&'x int`, and then we would have - // a problem when we try to assign `&a` to `z`, because - // the lifetime of `&a` (i.e., the enclosing block) is - // shorter than `'x`. - // - // HOWEVER, this code works fine. The reason is that the - // expected type here is whatever type the user wrote, not - // the initializer's type. In this case the user wrote - // nothing, so we are going to create a type variable `Z`. - // Then we will assign the type of the initializer (`&'x - // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we - // will instantiate `Z` as a type `&'0 int` where `'0` is - // a fresh region variable, with the constraint that `'x : - // '0`. So basically we're all set. - // - // Note that there are two tests to check that this remains true - // (`regions-reassign-{match,let}-bound-pointer.rs`). - // - // 2. Things go horribly wrong if we use subtype. The reason for - // THIS is a fairly subtle case involving bound regions. See the - // `givens` field in `region_constraints`, as well as the test - // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, - // for details. Short version is that we must sometimes detect - // relationships between specific region variables and regions - // bound in a closure signature, and that detection gets thrown - // off when we substitute fresh region variables here to enable - // subtyping. - } - - fn borrow_pat_suggestion( - &self, - err: &mut DiagnosticBuilder<'_>, - pat: &Pat, - inner: &Pat, - expected: Ty<'tcx>, - ) { - let tcx = self.tcx; - if let PatKind::Binding(..) = inner.node { - let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id); - let binding_parent = tcx.hir().get(binding_parent_id); - debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent); - match binding_parent { - hir::Node::Arg(hir::Arg { span, .. }) => { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { - err.span_suggestion( - *span, - &format!("did you mean `{}`", snippet), - format!(" &{}", expected), - Applicability::MachineApplicable, - ); - } - } - hir::Node::Arm(_) | - hir::Node::Pat(_) => { - // rely on match ergonomics or it might be nested `&&pat` - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { - err.span_suggestion( - pat.span, - "you can probably remove the explicit borrow", - snippet, - Applicability::MaybeIncorrect, - ); - } - } - _ => {} // don't provide suggestions in other cases #55175 - } - } - } - - pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &hir::Pat) -> bool { - if let PatKind::Binding(..) = inner.node { - if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { - if let ty::Dynamic(..) = mt.ty.sty { - // This is "x = SomeTrait" being reduced from - // "let &x = &SomeTrait" or "let box x = Box", an error. - let type_str = self.ty_to_string(expected); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0033, - "type `{}` cannot be dereferenced", - type_str - ); - err.span_label(span, format!("type `{}` cannot be dereferenced", type_str)); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note("\ -This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ -pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \ -this type has no compile-time size. Therefore, all accesses to trait types must be through \ -pointers. If you encounter this error you should try to avoid dereferencing the pointer. - -You can read more about trait objects in the Trait Objects section of the Reference: \ -https://doc.rust-lang.org/reference/types.html#trait-objects"); - } - err.emit(); - return false - } - } - } - true - } - pub fn check_match( &self, expr: &'tcx hir::Expr, @@ -678,8 +59,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { self.diverges.set(Diverges::Maybe); - let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); - self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span)); + self.check_pat_top(&p, discrim_ty, Some(discrim.span)); all_pats_diverge &= self.diverges.get(); } @@ -732,19 +112,26 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } self.diverges.set(pats_diverge); - let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + let arm_ty = if source_if && if_no_else && i != 0 && self.if_fallback_coercion( + expr.span, + &arms[0].body, + &mut coercion, + ) { + tcx.types.err + } else { + // Only call this if this is not an `if` expr with an expected type and no `else` + // clause to avoid duplicated type errors. (#60254) + self.check_expr_with_expectation(&arm.body, expected) + }; all_arms_diverge &= self.diverges.get(); - - let span = expr.span; - if source_if { let then_expr = &arms[0].body; match (i, if_no_else) { - (0, _) => coercion.coerce(self, &self.misc(span), &arm.body, arm_ty), - (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion), + (0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty), + (_, true) => {} // Handled above to avoid duplicated type errors (#60254). (_, _) => { let then_ty = prior_arm_ty.unwrap(); - let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty); + let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty); coercion.coerce(self, &cause, &arm.body, arm_ty); } } @@ -759,7 +146,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), - _ => (span, ObligationCauseCode::MatchExpressionArm { + _ => (expr.span, ObligationCauseCode::MatchExpressionArm { arm_span, source: match_src, prior_arms: other_arms.clone(), @@ -800,16 +187,19 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } /// Handle the fallback arm of a desugared if(-let) like a missing else. + /// + /// Returns `true` if there was an error forcing the coercion to the `()` type. fn if_fallback_coercion( &self, span: Span, then_expr: &'tcx hir::Expr, coercion: &mut CoerceMany<'tcx, '_, rustc::hir::Arm>, - ) { + ) -> bool { // If this `if` expr is the parent's function return expr, // the cause of the type coercion is the return type, point at it. (#25228) let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); + let mut error = false; coercion.coerce_forced_unit(self, &cause, &mut |err| { if let Some((span, msg)) = &ret_reason { err.span_label(*span, msg.as_str()); @@ -820,7 +210,9 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } err.note("`if` expressions without `else` evaluate to `()`"); err.help("consider adding an `else` block that evaluates to the expected type"); + error = true; }, ret_reason.is_none()); + error } fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { @@ -1038,346 +430,4 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); discrim_ty } } - - fn check_pat_struct( - &self, - pat: &'tcx hir::Pat, - qpath: &hir::QPath, - fields: &'tcx [hir::FieldPat], - etc: bool, - expected: Ty<'tcx>, - def_bm: ty::BindingMode, - discrim_span: Option, - ) -> Ty<'tcx> { - // Resolve the path and check the definition for errors. - let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) - { - variant_ty - } else { - for field in fields { - self.check_pat_walk(&field.pat, self.tcx.types.err, def_bm, discrim_span); - } - return self.tcx.types.err; - }; - - // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); - - // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) - { - pat_ty - } else { - self.tcx.types.err - } - } - - fn check_pat_path( - &self, - pat: &hir::Pat, - path_resolution: (Res, Option>, &'b [hir::PathSegment]), - qpath: &hir::QPath, - expected: Ty<'tcx>, - ) -> Ty<'tcx> { - let tcx = self.tcx; - - // We have already resolved the path. - let (res, opt_ty, segments) = path_resolution; - match res { - Res::Err => { - self.set_tainted_by_errors(); - return tcx.types.err; - } - Res::Def(DefKind::Method, _) | - Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) | - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { - report_unexpected_variant_res(tcx, res, pat.span, qpath); - return tcx.types.err; - } - Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | - Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {} // OK - _ => bug!("unexpected pattern resolution: {:?}", res) - } - - // Type-check the path. - let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0; - self.demand_suptype(pat.span, expected, pat_ty); - pat_ty - } - - fn check_pat_tuple_struct( - &self, - pat: &hir::Pat, - qpath: &hir::QPath, - subpats: &'tcx [P], - ddpos: Option, - expected: Ty<'tcx>, - def_bm: ty::BindingMode, - match_arm_pat_span: Option, - ) -> Ty<'tcx> { - let tcx = self.tcx; - let on_error = || { - for pat in subpats { - self.check_pat_walk(&pat, tcx.types.err, def_bm, match_arm_pat_span); - } - }; - let report_unexpected_res = |res: Res| { - let msg = format!("expected tuple struct/variant, found {} `{}`", - res.descr(), - hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); - let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); - match (res, &pat.node) { - (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => { - err.span_label(pat.span, "`fn` calls are not allowed in patterns"); - err.help("for more information, visit \ - https://doc.rust-lang.org/book/ch18-00-patterns.html"); - } - _ => { - err.span_label(pat.span, "not a tuple variant or struct"); - } - } - err.emit(); - on_error(); - }; - - // Resolve the path and check the definition for errors. - let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); - if res == Res::Err { - self.set_tainted_by_errors(); - on_error(); - return self.tcx.types.err; - } - - // Type-check the path. - let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, - pat.hir_id); - if !pat_ty.is_fn() { - report_unexpected_res(res); - return self.tcx.types.err; - } - - let variant = match res { - Res::Err => { - self.set_tainted_by_errors(); - on_error(); - return tcx.types.err; - } - Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Method, _) => { - report_unexpected_res(res); - return tcx.types.err; - } - Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { - tcx.expect_variant_res(res) - } - _ => bug!("unexpected pattern resolution: {:?}", res) - }; - - // Replace constructor type with constructed type for tuple struct patterns. - let pat_ty = pat_ty.fn_sig(tcx).output(); - let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); - - self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span); - - // Type-check subpatterns. - if subpats.len() == variant.fields.len() || - subpats.len() < variant.fields.len() && ddpos.is_some() { - let substs = match pat_ty.sty { - ty::Adt(_, substs) => substs, - _ => bug!("unexpected pattern type {:?}", pat_ty), - }; - for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { - let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat_walk(&subpat, field_ty, def_bm, match_arm_pat_span); - - self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); - } - } else { - let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; - let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; - struct_span_err!(tcx.sess, pat.span, E0023, - "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), subpats_ending, res.descr(), - variant.fields.len(), fields_ending) - .span_label(pat.span, format!("expected {} field{}, found {}", - variant.fields.len(), fields_ending, subpats.len())) - .emit(); - on_error(); - return tcx.types.err; - } - pat_ty - } - - fn check_struct_pat_fields( - &self, - adt_ty: Ty<'tcx>, - pat_id: hir::HirId, - span: Span, - variant: &'tcx ty::VariantDef, - fields: &'tcx [hir::FieldPat], - etc: bool, - def_bm: ty::BindingMode, - ) -> bool { - let tcx = self.tcx; - - let (substs, adt) = match adt_ty.sty { - ty::Adt(adt, substs) => (substs, adt), - _ => span_bug!(span, "struct pattern is not an ADT") - }; - let kind_name = adt.variant_descr(); - - // Index the struct fields' types. - let field_map = variant.fields - .iter() - .enumerate() - .map(|(i, field)| (field.ident.modern(), (i, field))) - .collect::>(); - - // Keep track of which fields have already appeared in the pattern. - let mut used_fields = FxHashMap::default(); - let mut no_field_errors = true; - - let mut inexistent_fields = vec![]; - // Typecheck each field. - for field in fields { - let span = field.span; - let ident = tcx.adjust_ident(field.ident, variant.def_id); - let field_ty = match used_fields.entry(ident) { - Occupied(occupied) => { - struct_span_err!(tcx.sess, span, E0025, - "field `{}` bound multiple times \ - in the pattern", - field.ident) - .span_label(span, - format!("multiple uses of `{}` in pattern", field.ident)) - .span_label(*occupied.get(), format!("first use of `{}`", field.ident)) - .emit(); - no_field_errors = false; - tcx.types.err - } - Vacant(vacant) => { - vacant.insert(span); - field_map.get(&ident) - .map(|(i, f)| { - self.write_field_index(field.hir_id, *i); - self.tcx.check_stability(f.did, Some(pat_id), span); - self.field_ty(span, f, substs) - }) - .unwrap_or_else(|| { - inexistent_fields.push(field.ident); - no_field_errors = false; - tcx.types.err - }) - } - }; - - self.check_pat_walk(&field.pat, field_ty, def_bm, None); - } - let mut unmentioned_fields = variant.fields - .iter() - .map(|field| field.ident.modern()) - .filter(|ident| !used_fields.contains_key(&ident)) - .collect::>(); - if inexistent_fields.len() > 0 && !variant.recovered { - let (field_names, t, plural) = if inexistent_fields.len() == 1 { - (format!("a field named `{}`", inexistent_fields[0]), "this", "") - } else { - (format!("fields named {}", - inexistent_fields.iter() - .map(|ident| format!("`{}`", ident)) - .collect::>() - .join(", ")), "these", "s") - }; - let spans = inexistent_fields.iter().map(|ident| ident.span).collect::>(); - let mut err = struct_span_err!(tcx.sess, - spans, - E0026, - "{} `{}` does not have {}", - kind_name, - tcx.def_path_str(variant.def_id), - field_names); - if let Some(ident) = inexistent_fields.last() { - err.span_label(ident.span, - format!("{} `{}` does not have {} field{}", - kind_name, - tcx.def_path_str(variant.def_id), - t, - plural)); - if plural == "" { - let input = unmentioned_fields.iter().map(|field| &field.name); - let suggested_name = - find_best_match_for_name(input, &ident.as_str(), None); - if let Some(suggested_name) = suggested_name { - err.span_suggestion( - ident.span, - "a field with a similar name exists", - suggested_name.to_string(), - Applicability::MaybeIncorrect, - ); - - // we don't want to throw `E0027` in case we have thrown `E0026` for them - unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); - } - } - } - if tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "This error indicates that a struct pattern attempted to \ - extract a non-existent field from a struct. Struct fields \ - are identified by the name used before the colon : so struct \ - patterns should resemble the declaration of the struct type \ - being matched.\n\n\ - If you are using shorthand field patterns but want to refer \ - to the struct field by a different name, you should rename \ - it explicitly." - ); - } - err.emit(); - } - - // Require `..` if struct has non_exhaustive attribute. - if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { - span_err!(tcx.sess, span, E0638, - "`..` required with {} marked as non-exhaustive", - kind_name); - } - - // Report an error if incorrect number of the fields were specified. - if kind_name == "union" { - if fields.len() != 1 { - tcx.sess.span_err(span, "union patterns should have exactly one field"); - } - if etc { - tcx.sess.span_err(span, "`..` cannot be used in union patterns"); - } - } else if !etc { - if unmentioned_fields.len() > 0 { - let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`", unmentioned_fields[0]) - } else { - format!("fields {}", - unmentioned_fields.iter() - .map(|name| format!("`{}`", name)) - .collect::>() - .join(", ")) - }; - let mut diag = struct_span_err!(tcx.sess, span, E0027, - "pattern does not mention {}", - field_names); - diag.span_label(span, format!("missing {}", field_names)); - if variant.ctor_kind == CtorKind::Fn { - diag.note("trying to match a tuple variant with a struct variant pattern"); - } - if tcx.sess.teach(&diag.get_code().unwrap()) { - diag.note( - "This error indicates that a pattern for a struct fails to specify a \ - sub-pattern for every one of the struct's fields. Ensure that each field \ - from the struct's definition is mentioned in the pattern, or use `..` to \ - ignore unwanted fields." - ); - } - diag.emit(); - } - } - no_field_errors - } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 53101499af1dc..c216cc92b1e58 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -40,6 +40,7 @@ use rustc::ty::{self, Ty, TypeFoldable, TypeAndMut}; use rustc::ty::subst::SubstsRef; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; +use rustc::ty::error::TypeError; use rustc::middle::lang_items; use syntax::ast; use syntax_pos::Span; @@ -461,6 +462,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, fcx.tcx.mk_fn_ptr(f), AllowTwoPhase::No); + if let Err(TypeError::IntrinsicCast) = res { + return Err(CastError::IllegalCast); + } if res.is_err() { return Err(CastError::NonScalar); } @@ -649,7 +653,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem); + let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) } } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d2f2f89cf0b1c..e9370429f3f55 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -3,7 +3,7 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes}; use crate::astconv::AstConv; -use crate::middle::region; +use crate::middle::{lang_items, region}; use rustc::hir::def_id::DefId; use rustc::infer::{InferOk, InferResult}; use rustc::infer::LateBoundRegionConversionTime; @@ -266,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_ref = projection.to_poly_trait_ref(tcx); let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some(); - let gen_trait = tcx.lang_items().gen_trait().unwrap(); + let gen_trait = tcx.require_lang_item(lang_items::GeneratorTraitLangItem, cause_span); let is_gen = gen_trait == trait_ref.def_id(); if !is_fn && !is_gen { debug!("deduce_sig_from_projection: not fn or generator"); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4edb6ad893113..f2e1a6e29d6fc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -70,6 +70,7 @@ use std::ops::Deref; use syntax::feature_gate; use syntax::symbol::sym; use syntax_pos; +use rustc_target::spec::abi::Abi; struct Coerce<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -689,6 +690,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match b.sty { ty::FnPtr(_) => { let a_sig = a.fn_sig(self.tcx); + // Intrinsics are not coercible to function pointers + if a_sig.abi() == Abi::RustIntrinsic || + a_sig.abi() == Abi::PlatformIntrinsic { + return Err(TypeError::IntrinsicCast); + } let InferOk { value: a_sig, mut obligations } = self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig); @@ -799,12 +805,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// adjusted type of the expression, if successful. /// Adjustments are only recorded if the coercion succeeded. /// The expressions *must not* have any pre-existing adjustments. - pub fn try_coerce(&self, - expr: &hir::Expr, - expr_ty: Ty<'tcx>, - target: Ty<'tcx>, - allow_two_phase: AllowTwoPhase) - -> RelateResult<'tcx, Ty<'tcx>> { + pub fn try_coerce( + &self, + expr: &hir::Expr, + expr_ty: Ty<'tcx>, + target: Ty<'tcx>, + allow_two_phase: AllowTwoPhase, + ) -> RelateResult<'tcx, Ty<'tcx>> { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index de5ba8bc8eb42..63137bad52ff8 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -224,13 +224,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// fn takes_ref(_: &Foo) {} /// let ref opt = Some(Foo); /// - /// opt.map(|arg| takes_ref(arg)); + /// opt.map(|param| takes_ref(param)); /// ``` - /// Suggest using `opt.as_ref().map(|arg| takes_ref(arg));` instead. + /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead. /// /// It only checks for `Option` and `Result` and won't work with /// ``` - /// opt.map(|arg| { takes_ref(arg) }); + /// opt.map(|param| { takes_ref(param) }); /// ``` fn can_use_as_ref( &self, @@ -247,13 +247,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let local_parent = self.tcx.hir().get_parent_node(local_id); - let arg_hir_id = match self.tcx.hir().find(local_parent) { - Some(Node::Arg(hir::Arg { hir_id, .. })) => hir_id, + let param_hir_id = match self.tcx.hir().find(local_parent) { + Some(Node::Param(hir::Param { hir_id, .. })) => hir_id, _ => return None }; - let arg_parent = self.tcx.hir().get_parent_node(*arg_hir_id); - let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(arg_parent) { + let param_parent = self.tcx.hir().get_parent_node(*param_hir_id); + let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(param_parent) { Some(Node::Expr( hir::Expr { hir_id, node: hir::ExprKind::Closure(_, decl, ..), .. } )) => (hir_id, decl), @@ -587,6 +587,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } } + if let hir::ExprKind::Call(path, args) = &expr.node { + if let ( + hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), + 1, + ) = (&path.node, args.len()) { + // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697). + if let ( + hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), + sym::from, + ) = (&base_ty.node, path_segment.ident.name) { + if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() { + match ident.name { + sym::i128 | sym::i64 | sym::i32 | sym::i16 | sym::i8 | + sym::u128 | sym::u64 | sym::u32 | sym::u16 | sym::u8 | + sym::isize | sym::usize + if base_ty_path.segments.len() == 1 => { + return false; + } + _ => {} + } + } + } + } + } let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index d139cd4264c86..fbaa9904d8303 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -12,7 +12,7 @@ use crate::check::fatally_break_rust; use crate::check::report_unexpected_variant_res; use crate::check::Needs; use crate::check::TupleArgumentsFlag::DontTupleArguments; -use crate::check::method::SelfSource; +use crate::check::method::{probe, SelfSource, MethodError}; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; use crate::astconv::AstConv as _; @@ -29,6 +29,7 @@ use rustc::hir::def::{CtorKind, Res, DefKind}; use rustc::hir::ptr::P; use rustc::infer; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::middle::lang_items; use rustc::mir::interpret::GlobalId; use rustc::ty; use rustc::ty::adjustment::{ @@ -775,35 +776,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); - let method = match self.lookup_method(rcvr_t, - segment, - span, - expr, - rcvr) { + let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr) { Ok(method) => { self.write_method_call(expr.hir_id, method); Ok(method) } Err(error) => { if segment.ident.name != kw::Invalid { - self.report_method_error(span, - rcvr_t, - segment.ident, - SelfSource::MethodCall(rcvr), - error, - Some(args)); + self.report_extended_method_error(segment, span, args, rcvr_t, error); } Err(()) } }; // Call the generic checker. - self.check_method_argument_types(span, - expr.span, - method, - &args[1..], - DontTupleArguments, - expected) + self.check_method_argument_types( + span, + expr.span, + method, + &args[1..], + DontTupleArguments, + expected, + ) + } + + fn report_extended_method_error( + &self, + segment: &hir::PathSegment, + span: Span, + args: &'tcx [hir::Expr], + rcvr_t: Ty<'tcx>, + error: MethodError<'tcx> + ) { + let rcvr = &args[0]; + let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| { + if let Ok(pick) = self.lookup_probe( + span, + segment.ident, + new_rcvr_t, + rcvr, + probe::ProbeScope::AllTraits, + ) { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + } + }; + + if let Some(mut err) = self.report_method_error( + span, + rcvr_t, + segment.ident, + SelfSource::MethodCall(rcvr), + error, + Some(args), + ) { + if let ty::Adt(..) = rcvr_t.sty { + // Try alternative arbitrary self types that could fulfill this call. + // FIXME: probe for all types that *could* be arbitrary self-types, not + // just this whitelist. + let box_rcvr_t = self.tcx.mk_box(rcvr_t); + try_alt_rcvr(&mut err, box_rcvr_t); + let pin_rcvr_t = self.tcx.mk_lang_item( + rcvr_t, + lang_items::PinTypeLangItem, + ); + try_alt_rcvr(&mut err, pin_rcvr_t); + let arc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Arc); + try_alt_rcvr(&mut err, arc_rcvr_t); + let rc_rcvr_t = self.tcx.mk_lang_item(rcvr_t, lang_items::Rc); + try_alt_rcvr(&mut err, rc_rcvr_t); + } + err.emit(); + } } fn check_expr_cast( @@ -1392,12 +1438,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_did: DefId, ) { let struct_path = self.tcx().def_path_str(base_did); + let kind_name = match self.tcx().def_kind(base_did) { + Some(def_kind) => def_kind.descr(base_did), + _ => " ", + }; let mut err = struct_span_err!( self.tcx().sess, expr.span, E0616, - "field `{}` of struct `{}` is private", + "field `{}` of {} `{}` is private", field, + kind_name, struct_path ); // Also check if an accessible method exists, which is often what is meant. @@ -1461,8 +1512,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let struct_variant_def = def.non_enum_variant(); let field_names = self.available_field_names(struct_variant_def); if !field_names.is_empty() { - err.note(&format!("available fields are: {}", - self.name_series_display(field_names))); + err.note(&format!( + "available fields are: {}", + self.name_series_display(field_names), + )); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index a7e4f8e5c6289..1509c0f8a2196 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(result.callee) } - fn lookup_probe( + pub fn lookup_probe( &self, span: Span, method_name: ast::Ident, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 53024d97c3b13..72e6f59715960 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -69,12 +69,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'b>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr]>, - ) { + ) -> Option> { let orig_span = span; let mut span = span; // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { - return; + return None; } let print_disambiguation_help = | @@ -314,7 +314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } err.emit(); - return; + return None; } else { span = item_name.span; let mut err = struct_span_err!( @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - err.emit(); + return Some(err); } MethodError::Ambiguity(sources) => { @@ -573,6 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bug!("no return type expectations but got BadReturnType") } } + None } fn suggest_use_candidates(&self, @@ -743,8 +744,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. let mut has_bounds = false; + let mut impl_trait = false; if let Node::GenericParam(ref param) = hir.get(id) { - has_bounds = !param.bounds.is_empty(); + match param.kind { + hir::GenericParamKind::Type { synthetic: Some(_), .. } => { + // We've found `fn foo(x: impl Trait)` instead of + // `fn foo(x: T)`. We want to suggest the correct + // `fn foo(x: impl Trait + TraitBound)` instead of + // `fn foo(x: T)`. (#63706) + impl_trait = true; + has_bounds = param.bounds.len() > 1; + } + _ => { + has_bounds = !param.bounds.is_empty(); + } + } } let sp = hir.span(id); // `sp` only covers `T`, change it so that it covers @@ -765,8 +779,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, &msg[..], candidates.iter().map(|t| format!( - "{}: {}{}", + "{}{} {}{}", param, + if impl_trait { " +" } else { ":" }, self.tcx.def_path_str(t.def_id), if has_bounds { " +"} else { "" }, )), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c7ac83e82e97..16903304a1427 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -70,6 +70,7 @@ type parameter). mod autoderef; pub mod dropck; pub mod _match; +mod pat; pub mod writeback; mod regionck; pub mod coercion; @@ -1101,20 +1102,19 @@ fn check_fn<'a, 'tcx>( GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id, }.visit_body(body); // Add formal parameters. - for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { + for (param_ty, param) in fn_sig.inputs().iter().zip(&body.params) { // Check the pattern. - let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); - fcx.check_pat_walk(&arg.pat, arg_ty, binding_mode, None); + fcx.check_pat_top(¶m.pat, param_ty, None); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if arg.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { - fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::SizedArgumentType); + if param.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { + fcx.require_type_is_sized(param_ty, decl.output.span(), traits::SizedArgumentType); } - fcx.write_ty(arg.hir_id, arg_ty); + fcx.write_ty(param.hir_id, param_ty); } inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); @@ -1570,7 +1570,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: DefId, span: Span) } else { bug!("Matching on non-ByRef static") }; - if alloc.relocations.len() != 0 { + if alloc.relocations().len() != 0 { let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; @@ -1859,14 +1859,18 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) { for attr in tcx.get_attrs(def_id).iter() { for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) { if let attr::ReprPacked(pack) = r { - if pack != repr.pack { - struct_span_err!(tcx.sess, sp, E0634, - "type has conflicting packed representation hints").emit(); + if let Some(repr_pack) = repr.pack { + if pack as u64 != repr_pack.bytes() { + struct_span_err!( + tcx.sess, sp, E0634, + "type has conflicting packed representation hints" + ).emit(); + } } } } } - if repr.align > 0 { + if repr.align.is_some() { struct_span_err!(tcx.sess, sp, E0587, "type has conflicting packed and align representation hints").emit(); } @@ -1885,7 +1889,7 @@ fn check_packed_inner(tcx: TyCtxt<'_>, def_id: DefId, stack: &mut Vec) -> } if let ty::Adt(def, substs) = t.sty { if def.is_struct() || def.is_union() { - if tcx.adt_def(def.did).repr.align > 0 { + if tcx.adt_def(def.did).repr.align.is_some() { return true; } // push struct def_id before checking fields @@ -2622,7 +2626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, code: traits::ObligationCauseCode<'tcx>) { - let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem); + let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); self.require_type_meets(ty, span, code, lang_item); } @@ -3576,7 +3580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { SelfSource::QPath(qself), error, None, - ); + ).map(|mut e| e.emit()); } result }); @@ -3630,12 +3634,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.check_pat_walk( - &local.pat, - t, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - None, - ); + self.check_pat_top(&local.pat, t, None); let pat_ty = self.node_ty(local.pat.hir_id); if pat_ty.references_error() { self.write_ty(local.hir_id, pat_ty); @@ -3917,75 +3916,99 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) -> bool { - match found.sty { - ty::FnDef(..) | ty::FnPtr(_) => {} - _ => return false, - } let hir = self.tcx.hir(); + let (def_id, sig) = match found.sty { + ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), + ty::Closure(def_id, substs) => { + // We don't use `closure_sig` to account for malformed closures like + // `|_: [_; continue]| {}` and instead we don't suggest anything. + let closure_sig_ty = substs.closure_sig_ty(def_id, self.tcx); + (def_id, match closure_sig_ty.sty { + ty::FnPtr(sig) => sig, + _ => return false, + }) + } + _ => return false, + }; - let sig = found.fn_sig(self.tcx); let sig = self .replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig) .0; let sig = self.normalize_associated_types_in(expr.span, &sig); - if let Ok(_) = self.try_coerce(expr, sig.output(), expected, AllowTwoPhase::No) { + if self.can_coerce(sig.output(), expected) { let (mut sugg_call, applicability) = if sig.inputs().is_empty() { (String::new(), Applicability::MachineApplicable) } else { ("...".to_string(), Applicability::HasPlaceholders) }; let mut msg = "call this function"; - if let ty::FnDef(def_id, ..) = found.sty { - match hir.get_if_local(def_id) { - Some(Node::Item(hir::Item { - node: ItemKind::Fn(.., body_id), - .. - })) | - Some(Node::ImplItem(hir::ImplItem { - node: hir::ImplItemKind::Method(_, body_id), - .. - })) | - Some(Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), - .. - })) => { - let body = hir.body(*body_id); - sugg_call = body.arguments.iter() - .map(|arg| match &arg.pat.node { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }).collect::>().join(", "); + match hir.get_if_local(def_id) { + Some(Node::Item(hir::Item { + node: ItemKind::Fn(.., body_id), + .. + })) | + Some(Node::ImplItem(hir::ImplItem { + node: hir::ImplItemKind::Method(_, body_id), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Provided(body_id)), + .. + })) => { + let body = hir.body(*body_id); + sugg_call = body.params.iter() + .map(|param| match ¶m.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + } + Some(Node::Expr(hir::Expr { + node: ExprKind::Closure(_, _, body_id, closure_span, _), + span: full_closure_span, + .. + })) => { + if *full_closure_span == expr.span { + return false; } - Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { - sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); - match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) { - Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { - msg = "instantiate this tuple variant"; - } - Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => { - msg = "instantiate this tuple struct"; - } - _ => {} + err.span_label(*closure_span, "closure defined here"); + msg = "call this closure"; + let body = hir.body(*body_id); + sugg_call = body.params.iter() + .map(|param| match ¶m.pat.node { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => ident.to_string(), + _ => "_".to_string(), + }).collect::>().join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::>().join(", "); + match hir.as_local_hir_id(def_id).and_then(|hir_id| hir.def_kind(hir_id)) { + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; } + Some(hir::def::DefKind::Ctor(hir::def::CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} } - Some(Node::ForeignItem(hir::ForeignItem { - node: hir::ForeignItemKind::Fn(_, idents, _), - .. - })) | - Some(Node::TraitItem(hir::TraitItem { - node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), - .. - })) => sugg_call = idents.iter() - .map(|ident| if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - }).collect::>() - .join(", "), - _ => {} } - }; + Some(Node::ForeignItem(hir::ForeignItem { + node: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) | + Some(Node::TraitItem(hir::TraitItem { + node: hir::TraitItemKind::Method(.., hir::TraitMethod::Required(idents)), + .. + })) => sugg_call = idents.iter() + .map(|ident| if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + }).collect::>() + .join(", "), + _ => {} + } if let Ok(code) = self.sess().source_map().span_to_snippet(expr.span) { err.span_suggestion( expr.span, diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs new file mode 100644 index 0000000000000..4cf0df308fb4c --- /dev/null +++ b/src/librustc_typeck/check/pat.rs @@ -0,0 +1,1123 @@ +use crate::check::FnCtxt; +use crate::util::nodemap::FxHashMap; +use errors::{Applicability, DiagnosticBuilder}; +use rustc::hir::{self, PatKind, Pat, HirId}; +use rustc::hir::def::{Res, DefKind, CtorKind}; +use rustc::hir::pat_util::EnumerateAndAdjustIterator; +use rustc::hir::ptr::P; +use rustc::infer; +use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc::ty::{self, Ty, BindingMode, TypeFoldable}; +use rustc::ty::subst::Kind; +use syntax::ast; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax_pos::Span; +use syntax_pos::hygiene::DesugaringKind; + +use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::cmp; + +use super::report_unexpected_variant_res; + +const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\ +This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \ +pattern. Every trait defines a type, but because the size of trait implementors isn't fixed, \ +this type has no compile-time size. Therefore, all accesses to trait types must be through \ +pointers. If you encounter this error you should try to avoid dereferencing the pointer. + +You can read more about trait objects in the Trait Objects section of the Reference: \ +https://doc.rust-lang.org/reference/types.html#trait-objects"; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn check_pat_top(&self, pat: &'tcx Pat, expected: Ty<'tcx>, discrim_span: Option) { + let def_bm = BindingMode::BindByValue(hir::Mutability::MutImmutable); + self.check_pat(pat, expected, def_bm, discrim_span); + } + + /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match + /// expression arm guard, and it points to the match discriminant to add context in type errors. + /// In the following example, `discrim_span` corresponds to the `a + b` expression: + /// + /// ```text + /// error[E0308]: mismatched types + /// --> src/main.rs:5:9 + /// | + /// 4 | let temp: usize = match a + b { + /// | ----- this expression has type `usize` + /// 5 | Ok(num) => num, + /// | ^^^^^^^ expected usize, found enum `std::result::Result` + /// | + /// = note: expected type `usize` + /// found type `std::result::Result<_, _>` + /// ``` + fn check_pat( + &self, + pat: &'tcx Pat, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) { + debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); + + let path_resolution = match &pat.node { + PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), + _ => None, + }; + let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res)); + let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp); + + let ty = match &pat.node { + PatKind::Wild => expected, + PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, discrim_span), + PatKind::Range(begin, end, _) => { + match self.check_pat_range(pat.span, begin, end, expected, discrim_span) { + None => return, + Some(ty) => ty, + } + } + PatKind::Binding(ba, var_id, _, sub) => { + let sub = sub.as_deref(); + self.check_pat_ident(pat, *ba, *var_id, sub, expected, def_bm, discrim_span) + } + PatKind::TupleStruct(qpath, subpats, ddpos) => { + self.check_pat_tuple_struct( + pat, + qpath, + subpats, + *ddpos, + expected, + def_bm, + discrim_span, + ) + } + PatKind::Path(qpath) => { + self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected) + } + PatKind::Struct(qpath, fields, etc) => { + self.check_pat_struct(pat, qpath, fields, *etc, expected, def_bm, discrim_span) + } + PatKind::Or(pats) => { + let expected_ty = self.structurally_resolved_type(pat.span, expected); + for pat in pats { + self.check_pat(pat, expected, def_bm, discrim_span); + } + expected_ty + } + PatKind::Tuple(elements, ddpos) => { + self.check_pat_tuple(pat.span, elements, *ddpos, expected, def_bm, discrim_span) + } + PatKind::Box(inner) => { + self.check_pat_box(pat.span, inner, expected, def_bm, discrim_span) + } + PatKind::Ref(inner, mutbl) => { + self.check_pat_ref(pat, inner, *mutbl, expected, def_bm, discrim_span) + } + PatKind::Slice(before, slice, after) => { + let slice = slice.as_deref(); + self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, discrim_span) + } + }; + + self.write_ty(pat.hir_id, ty); + + // (note_1): In most of the cases where (note_1) is referenced + // (literals and constants being the exception), we relate types + // using strict equality, even though subtyping would be sufficient. + // There are a few reasons for this, some of which are fairly subtle + // and which cost me (nmatsakis) an hour or two debugging to remember, + // so I thought I'd write them down this time. + // + // 1. There is no loss of expressiveness here, though it does + // cause some inconvenience. What we are saying is that the type + // of `x` becomes *exactly* what is expected. This can cause unnecessary + // errors in some cases, such as this one: + // + // ``` + // fn foo<'x>(x: &'x int) { + // let a = 1; + // let mut z = x; + // z = &a; + // } + // ``` + // + // The reason we might get an error is that `z` might be + // assigned a type like `&'x int`, and then we would have + // a problem when we try to assign `&a` to `z`, because + // the lifetime of `&a` (i.e., the enclosing block) is + // shorter than `'x`. + // + // HOWEVER, this code works fine. The reason is that the + // expected type here is whatever type the user wrote, not + // the initializer's type. In this case the user wrote + // nothing, so we are going to create a type variable `Z`. + // Then we will assign the type of the initializer (`&'x + // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we + // will instantiate `Z` as a type `&'0 int` where `'0` is + // a fresh region variable, with the constraint that `'x : + // '0`. So basically we're all set. + // + // Note that there are two tests to check that this remains true + // (`regions-reassign-{match,let}-bound-pointer.rs`). + // + // 2. Things go horribly wrong if we use subtype. The reason for + // THIS is a fairly subtle case involving bound regions. See the + // `givens` field in `region_constraints`, as well as the test + // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`, + // for details. Short version is that we must sometimes detect + // relationships between specific region variables and regions + // bound in a closure signature, and that detection gets thrown + // off when we substitute fresh region variables here to enable + // subtyping. + } + + /// Compute the new expected type and default binding mode from the old ones + /// as well as the pattern form we are currently checking. + fn calc_default_binding_mode( + &self, + pat: &'tcx Pat, + expected: Ty<'tcx>, + def_bm: BindingMode, + is_non_ref_pat: bool, + ) -> (Ty<'tcx>, BindingMode) { + if is_non_ref_pat { + debug!("pattern is non reference pattern"); + self.peel_off_references(pat, expected, def_bm) + } else { + // When you encounter a `&pat` pattern, reset to "by + // value". This is so that `x` and `y` here are by value, + // as they appear to be: + // + // ``` + // match &(&22, &44) { + // (&x, &y) => ... + // } + // ``` + // + // See issue #46688. + let def_bm = match pat.node { + PatKind::Ref(..) => ty::BindByValue(hir::MutImmutable), + _ => def_bm, + }; + (expected, def_bm) + } + } + + /// Is the pattern a "non reference pattern"? + /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`. + fn is_non_ref_pat(&self, pat: &'tcx Pat, opt_path_res: Option) -> bool { + match pat.node { + PatKind::Struct(..) | + PatKind::TupleStruct(..) | + PatKind::Or(_) | + PatKind::Tuple(..) | + PatKind::Box(_) | + PatKind::Range(..) | + PatKind::Slice(..) => true, + PatKind::Lit(ref lt) => { + let ty = self.check_expr(lt); + match ty.sty { + ty::Ref(..) => false, + _ => true, + } + } + PatKind::Path(_) => { + match opt_path_res.unwrap() { + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false, + _ => true, + } + } + PatKind::Wild | + PatKind::Binding(..) | + PatKind::Ref(..) => false, + } + } + + /// Peel off as many immediately nested `& mut?` from the expected type as possible + /// and return the new expected type and binding default binding mode. + /// The adjustments vector, if non-empty is stored in a table. + fn peel_off_references( + &self, + pat: &'tcx Pat, + expected: Ty<'tcx>, + mut def_bm: BindingMode, + ) -> (Ty<'tcx>, BindingMode) { + let mut expected = self.resolve_type_vars_with_obligations(&expected); + + // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, + // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches + // the `Some(5)` which is not of type Ref. + // + // For each ampersand peeled off, update the binding mode and push the original + // type into the adjustments vector. + // + // See the examples in `ui/match-defbm*.rs`. + let mut pat_adjustments = vec![]; + while let ty::Ref(_, inner_ty, inner_mutability) = expected.sty { + debug!("inspecting {:?}", expected); + + debug!("current discriminant is Ref, inserting implicit deref"); + // Preserve the reference type. We'll need it later during HAIR lowering. + pat_adjustments.push(expected); + + expected = inner_ty; + def_bm = ty::BindByReference(match def_bm { + // If default binding mode is by value, make it `ref` or `ref mut` + // (depending on whether we observe `&` or `&mut`). + ty::BindByValue(_) | + // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`). + ty::BindByReference(hir::Mutability::MutMutable) => inner_mutability, + // Once a `ref`, always a `ref`. + // This is because a `& &mut` cannot mutate the underlying value. + ty::BindByReference(m @ hir::Mutability::MutImmutable) => m, + }); + } + + if pat_adjustments.len() > 0 { + debug!("default binding mode is now {:?}", def_bm); + self.inh.tables.borrow_mut() + .pat_adjustments_mut() + .insert(pat.hir_id, pat_adjustments); + } + + (expected, def_bm) + } + + fn check_pat_lit( + &self, + span: Span, + lt: &hir::Expr, + expected: Ty<'tcx>, + discrim_span: Option, + ) -> Ty<'tcx> { + // We've already computed the type above (when checking for a non-ref pat), + // so avoid computing it again. + let ty = self.node_ty(lt.hir_id); + + // Byte string patterns behave the same way as array patterns + // They can denote both statically and dynamically-sized byte arrays. + let mut pat_ty = ty; + if let hir::ExprKind::Lit(ref lt) = lt.node { + if let ast::LitKind::ByteStr(_) = lt.node { + let expected_ty = self.structurally_resolved_type(span, expected); + if let ty::Ref(_, r_ty, _) = expected_ty.sty { + if let ty::Slice(_) = r_ty.sty { + let tcx = self.tcx; + pat_ty = tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_slice(tcx.types.u8), + ); + } + } + } + } + + // Somewhat surprising: in this case, the subtyping relation goes the + // opposite way as the other cases. Actually what we really want is not + // a subtyping relation at all but rather that there exists a LUB + // (so that they can be compared). However, in practice, constants are + // always scalars or strings. For scalars subtyping is irrelevant, + // and for strings `ty` is type is `&'static str`, so if we say that + // + // &'static str <: expected + // + // then that's equivalent to there existing a LUB. + if let Some(mut err) = self.demand_suptype_diag(span, expected, pat_ty) { + err.emit_unless(discrim_span + .filter(|&s| { + // In the case of `if`- and `while`-expressions we've already checked + // that `scrutinee: bool`. We know that the pattern is `true`, + // so an error here would be a duplicate and from the wrong POV. + s.is_desugaring(DesugaringKind::CondTemporary) + }) + .is_some()); + } + + pat_ty + } + + fn check_pat_range( + &self, + span: Span, + begin: &'tcx hir::Expr, + end: &'tcx hir::Expr, + expected: Ty<'tcx>, + discrim_span: Option, + ) -> Option> { + let lhs_ty = self.check_expr(begin); + let rhs_ty = self.check_expr(end); + + // Check that both end-points are of numeric or char type. + let numeric_or_char = |ty: Ty<'_>| { + ty.is_numeric() + || ty.is_char() + || ty.references_error() + }; + let lhs_compat = numeric_or_char(lhs_ty); + let rhs_compat = numeric_or_char(rhs_ty); + + if !lhs_compat || !rhs_compat { + let span = if !lhs_compat && !rhs_compat { + span + } else if !lhs_compat { + begin.span + } else { + end.span + }; + + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0029, + "only char and numeric types are allowed in range patterns" + ); + err.span_label(span, "ranges require char or numeric types"); + err.note(&format!("start type: {}", self.ty_to_string(lhs_ty))); + err.note(&format!("end type: {}", self.ty_to_string(rhs_ty))); + if self.tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "In a match expression, only numbers and characters can be matched \ + against a range. This is because the compiler checks that the range \ + is non-empty at compile-time, and is unable to evaluate arbitrary \ + comparison functions. If you want to capture values of an orderable \ + type between two end-points, you can use a guard." + ); + } + err.emit(); + return None; + } + + // Now that we know the types can be unified we find the unified type and use + // it to type the entire expression. + let common_type = self.resolve_vars_if_possible(&lhs_ty); + + // Subtyping doesn't matter here, as the value is some kind of scalar. + self.demand_eqtype_pat(span, expected, lhs_ty, discrim_span); + self.demand_eqtype_pat(span, expected, rhs_ty, discrim_span); + Some(common_type) + } + + fn check_pat_ident( + &self, + pat: &Pat, + ba: hir::BindingAnnotation, + var_id: HirId, + sub: Option<&'tcx Pat>, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + // Determine the binding mode... + let bm = match ba { + hir::BindingAnnotation::Unannotated => def_bm, + _ => BindingMode::convert(ba), + }; + // ...and store it in a side table: + self.inh + .tables + .borrow_mut() + .pat_binding_modes_mut() + .insert(pat.hir_id, bm); + + debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); + + let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty; + let eq_ty = match bm { + ty::BindByReference(mutbl) => { + // If the binding is like `ref x | ref const x | ref mut x` + // then `x` is assigned a value of type `&M T` where M is the + // mutability and T is the expected type. + let region_ty = self.new_ref_ty(pat.span, mutbl, expected); + + // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` + // is required. However, we use equality, which is stronger. + // See (note_1) for an explanation. + region_ty + } + // Otherwise, the type of x is the expected type `T`. + ty::BindByValue(_) => { + // As above, `T <: typeof(x)` is required, but we use equality, see (note_1). + expected + } + }; + self.demand_eqtype_pat(pat.span, eq_ty, local_ty, discrim_span); + + // If there are multiple arms, make sure they all agree on + // what the type of the binding `x` ought to be. + if var_id != pat.hir_id { + let vt = self.local_ty(pat.span, var_id).decl_ty; + self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); + } + + if let Some(p) = sub { + self.check_pat(&p, expected, def_bm, discrim_span); + } + + local_ty + } + + fn borrow_pat_suggestion( + &self, + err: &mut DiagnosticBuilder<'_>, + pat: &Pat, + inner: &Pat, + expected: Ty<'tcx>, + ) { + let tcx = self.tcx; + if let PatKind::Binding(..) = inner.node { + let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id); + let binding_parent = tcx.hir().get(binding_parent_id); + debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent); + match binding_parent { + hir::Node::Param(hir::Param { span, .. }) => { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + *span, + &format!("did you mean `{}`", snippet), + format!(" &{}", expected), + Applicability::MachineApplicable, + ); + } + } + hir::Node::Arm(_) | + hir::Node::Pat(_) => { + // rely on match ergonomics or it might be nested `&&pat` + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) { + err.span_suggestion( + pat.span, + "you can probably remove the explicit borrow", + snippet, + Applicability::MaybeIncorrect, + ); + } + } + _ => {} // don't provide suggestions in other cases #55175 + } + } + } + + pub fn check_dereferencable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat) -> bool { + if let PatKind::Binding(..) = inner.node { + if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { + if let ty::Dynamic(..) = mt.ty.sty { + // This is "x = SomeTrait" being reduced from + // "let &x = &SomeTrait" or "let box x = Box", an error. + let type_str = self.ty_to_string(expected); + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0033, + "type `{}` cannot be dereferenced", + type_str + ); + err.span_label(span, format!("type `{}` cannot be dereferenced", type_str)); + if self.tcx.sess.teach(&err.get_code().unwrap()) { + err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ); + } + err.emit(); + return false + } + } + } + true + } + + fn check_pat_struct( + &self, + pat: &'tcx Pat, + qpath: &hir::QPath, + fields: &'tcx [hir::FieldPat], + etc: bool, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + // Resolve the path and check the definition for errors. + let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.hir_id) + { + variant_ty + } else { + for field in fields { + self.check_pat(&field.pat, self.tcx.types.err, def_bm, discrim_span); + } + return self.tcx.types.err; + }; + + // Type-check the path. + self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); + + // Type-check subpatterns. + if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) + { + pat_ty + } else { + self.tcx.types.err + } + } + + fn check_pat_path( + &self, + pat: &Pat, + path_resolution: (Res, Option>, &'b [hir::PathSegment]), + qpath: &hir::QPath, + expected: Ty<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx; + + // We have already resolved the path. + let (res, opt_ty, segments) = path_resolution; + match res { + Res::Err => { + self.set_tainted_by_errors(); + return tcx.types.err; + } + Res::Def(DefKind::Method, _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) | + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { + report_unexpected_variant_res(tcx, res, pat.span, qpath); + return tcx.types.err; + } + Res::Def(DefKind::Ctor(_, CtorKind::Const), _) | Res::SelfCtor(..) | + Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {} // OK + _ => bug!("unexpected pattern resolution: {:?}", res) + } + + // Type-check the path. + let pat_ty = self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.hir_id).0; + self.demand_suptype(pat.span, expected, pat_ty); + pat_ty + } + + fn check_pat_tuple_struct( + &self, + pat: &Pat, + qpath: &hir::QPath, + subpats: &'tcx [P], + ddpos: Option, + expected: Ty<'tcx>, + def_bm: BindingMode, + match_arm_pat_span: Option, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let on_error = || { + for pat in subpats { + self.check_pat(&pat, tcx.types.err, def_bm, match_arm_pat_span); + } + }; + let report_unexpected_res = |res: Res| { + let msg = format!("expected tuple struct/variant, found {} `{}`", + res.descr(), + hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); + let mut err = struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg); + match (res, &pat.node) { + (Res::Def(DefKind::Fn, _), _) | (Res::Def(DefKind::Method, _), _) => { + err.span_label(pat.span, "`fn` calls are not allowed in patterns"); + err.help("for more information, visit \ + https://doc.rust-lang.org/book/ch18-00-patterns.html"); + } + _ => { + err.span_label(pat.span, "not a tuple variant or struct"); + } + } + err.emit(); + on_error(); + }; + + // Resolve the path and check the definition for errors. + let (res, opt_ty, segments) = self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span); + if res == Res::Err { + self.set_tainted_by_errors(); + on_error(); + return self.tcx.types.err; + } + + // Type-check the path. + let (pat_ty, res) = self.instantiate_value_path(segments, opt_ty, res, pat.span, + pat.hir_id); + if !pat_ty.is_fn() { + report_unexpected_res(res); + return tcx.types.err; + } + + let variant = match res { + Res::Err => { + self.set_tainted_by_errors(); + on_error(); + return tcx.types.err; + } + Res::Def(DefKind::AssocConst, _) | Res::Def(DefKind::Method, _) => { + report_unexpected_res(res); + return tcx.types.err; + } + Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => { + tcx.expect_variant_res(res) + } + _ => bug!("unexpected pattern resolution: {:?}", res) + }; + + // Replace constructor type with constructed type for tuple struct patterns. + let pat_ty = pat_ty.fn_sig(tcx).output(); + let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); + + self.demand_eqtype_pat(pat.span, expected, pat_ty, match_arm_pat_span); + + // Type-check subpatterns. + if subpats.len() == variant.fields.len() + || subpats.len() < variant.fields.len() && ddpos.is_some() + { + let substs = match pat_ty.sty { + ty::Adt(_, substs) => substs, + _ => bug!("unexpected pattern type {:?}", pat_ty), + }; + for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { + let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); + self.check_pat(&subpat, field_ty, def_bm, match_arm_pat_span); + + self.tcx.check_stability(variant.fields[i].did, Some(pat.hir_id), subpat.span); + } + } else { + let subpats_ending = if subpats.len() == 1 { "" } else { "s" }; + let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; + struct_span_err!(tcx.sess, pat.span, E0023, + "this pattern has {} field{}, but the corresponding {} has {} field{}", + subpats.len(), subpats_ending, res.descr(), + variant.fields.len(), fields_ending) + .span_label(pat.span, format!("expected {} field{}, found {}", + variant.fields.len(), fields_ending, subpats.len())) + .emit(); + on_error(); + return tcx.types.err; + } + pat_ty + } + + fn check_pat_tuple( + &self, + span: Span, + elements: &'tcx [P], + ddpos: Option, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let mut expected_len = elements.len(); + if ddpos.is_some() { + // Require known type only when `..` is present. + if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).sty { + expected_len = tys.len(); + } + } + let max_len = cmp::max(expected_len, elements.len()); + + let element_tys_iter = (0..max_len).map(|_| { + Kind::from(self.next_ty_var( + // FIXME: `MiscVariable` for now -- obtaining the span and name information + // from all tuple elements isn't trivial. + TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }, + )) + }); + let element_tys = tcx.mk_substs(element_tys_iter); + let pat_ty = tcx.mk_ty(ty::Tuple(element_tys)); + if let Some(mut err) = self.demand_eqtype_diag(span, expected, pat_ty) { + err.emit(); + // Walk subpatterns with an expected type of `err` in this case to silence + // further errors being emitted when using the bindings. #50333 + let element_tys_iter = (0..max_len).map(|_| tcx.types.err); + for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { + self.check_pat(elem, &tcx.types.err, def_bm, discrim_span); + } + tcx.mk_tup(element_tys_iter) + } else { + for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { + self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, discrim_span); + } + pat_ty + } + } + + fn check_struct_pat_fields( + &self, + adt_ty: Ty<'tcx>, + pat_id: HirId, + span: Span, + variant: &'tcx ty::VariantDef, + fields: &'tcx [hir::FieldPat], + etc: bool, + def_bm: BindingMode, + ) -> bool { + let tcx = self.tcx; + + let (substs, adt) = match adt_ty.sty { + ty::Adt(adt, substs) => (substs, adt), + _ => span_bug!(span, "struct pattern is not an ADT") + }; + let kind_name = adt.variant_descr(); + + // Index the struct fields' types. + let field_map = variant.fields + .iter() + .enumerate() + .map(|(i, field)| (field.ident.modern(), (i, field))) + .collect::>(); + + // Keep track of which fields have already appeared in the pattern. + let mut used_fields = FxHashMap::default(); + let mut no_field_errors = true; + + let mut inexistent_fields = vec![]; + // Typecheck each field. + for field in fields { + let span = field.span; + let ident = tcx.adjust_ident(field.ident, variant.def_id); + let field_ty = match used_fields.entry(ident) { + Occupied(occupied) => { + self.error_field_already_bound(span, field.ident, *occupied.get()); + no_field_errors = false; + tcx.types.err + } + Vacant(vacant) => { + vacant.insert(span); + field_map.get(&ident) + .map(|(i, f)| { + self.write_field_index(field.hir_id, *i); + self.tcx.check_stability(f.did, Some(pat_id), span); + self.field_ty(span, f, substs) + }) + .unwrap_or_else(|| { + inexistent_fields.push(field.ident); + no_field_errors = false; + tcx.types.err + }) + } + }; + + self.check_pat(&field.pat, field_ty, def_bm, None); + } + + let mut unmentioned_fields = variant.fields + .iter() + .map(|field| field.ident.modern()) + .filter(|ident| !used_fields.contains_key(&ident)) + .collect::>(); + + if inexistent_fields.len() > 0 && !variant.recovered { + self.error_inexistent_fields( + kind_name, + &inexistent_fields, + &mut unmentioned_fields, + variant + ); + } + + // Require `..` if struct has non_exhaustive attribute. + if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { + span_err!(tcx.sess, span, E0638, + "`..` required with {} marked as non-exhaustive", + kind_name); + } + + // Report an error if incorrect number of the fields were specified. + if kind_name == "union" { + if fields.len() != 1 { + tcx.sess.span_err(span, "union patterns should have exactly one field"); + } + if etc { + tcx.sess.span_err(span, "`..` cannot be used in union patterns"); + } + } else if !etc && unmentioned_fields.len() > 0 { + self.error_unmentioned_fields(span, &unmentioned_fields, variant); + } + no_field_errors + } + + fn error_field_already_bound(&self, span: Span, ident: ast::Ident, other_field: Span) { + struct_span_err!( + self.tcx.sess, span, E0025, + "field `{}` bound multiple times in the pattern", + ident + ) + .span_label(span, format!("multiple uses of `{}` in pattern", ident)) + .span_label(other_field, format!("first use of `{}`", ident)) + .emit(); + } + + fn error_inexistent_fields( + &self, + kind_name: &str, + inexistent_fields: &[ast::Ident], + unmentioned_fields: &mut Vec, + variant: &ty::VariantDef, + ) { + let tcx = self.tcx; + let (field_names, t, plural) = if inexistent_fields.len() == 1 { + (format!("a field named `{}`", inexistent_fields[0]), "this", "") + } else { + (format!("fields named {}", + inexistent_fields.iter() + .map(|ident| format!("`{}`", ident)) + .collect::>() + .join(", ")), "these", "s") + }; + let spans = inexistent_fields.iter().map(|ident| ident.span).collect::>(); + let mut err = struct_span_err!(tcx.sess, + spans, + E0026, + "{} `{}` does not have {}", + kind_name, + tcx.def_path_str(variant.def_id), + field_names); + if let Some(ident) = inexistent_fields.last() { + err.span_label(ident.span, + format!("{} `{}` does not have {} field{}", + kind_name, + tcx.def_path_str(variant.def_id), + t, + plural)); + if plural == "" { + let input = unmentioned_fields.iter().map(|field| &field.name); + let suggested_name = + find_best_match_for_name(input, &ident.as_str(), None); + if let Some(suggested_name) = suggested_name { + err.span_suggestion( + ident.span, + "a field with a similar name exists", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + + // we don't want to throw `E0027` in case we have thrown `E0026` for them + unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); + } + } + } + if tcx.sess.teach(&err.get_code().unwrap()) { + err.note( + "This error indicates that a struct pattern attempted to \ + extract a non-existent field from a struct. Struct fields \ + are identified by the name used before the colon : so struct \ + patterns should resemble the declaration of the struct type \ + being matched.\n\n\ + If you are using shorthand field patterns but want to refer \ + to the struct field by a different name, you should rename \ + it explicitly." + ); + } + err.emit(); + } + + fn error_unmentioned_fields( + &self, + span: Span, + unmentioned_fields: &[ast::Ident], + variant: &ty::VariantDef, + ) { + let field_names = if unmentioned_fields.len() == 1 { + format!("field `{}`", unmentioned_fields[0]) + } else { + let fields = unmentioned_fields.iter() + .map(|name| format!("`{}`", name)) + .collect::>() + .join(", "); + format!("fields {}", fields) + }; + let mut diag = struct_span_err!( + self.tcx.sess, span, E0027, + "pattern does not mention {}", + field_names + ); + diag.span_label(span, format!("missing {}", field_names)); + if variant.ctor_kind == CtorKind::Fn { + diag.note("trying to match a tuple variant with a struct variant pattern"); + } + if self.tcx.sess.teach(&diag.get_code().unwrap()) { + diag.note( + "This error indicates that a pattern for a struct fails to specify a \ + sub-pattern for every one of the struct's fields. Ensure that each field \ + from the struct's definition is mentioned in the pattern, or use `..` to \ + ignore unwanted fields." + ); + } + diag.emit(); + } + + fn check_pat_box( + &self, + span: Span, + inner: &'tcx Pat, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let (box_ty, inner_ty) = if self.check_dereferencable(span, expected, &inner) { + // Here, `demand::subtype` is good enough, but I don't + // think any errors can be introduced by using `demand::eqtype`. + let inner_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + }); + let box_ty = tcx.mk_box(inner_ty); + self.demand_eqtype_pat(span, expected, box_ty, discrim_span); + (box_ty, inner_ty) + } else { + (tcx.types.err, tcx.types.err) + }; + self.check_pat(&inner, inner_ty, def_bm, discrim_span); + box_ty + } + + fn check_pat_ref( + &self, + pat: &Pat, + inner: &'tcx Pat, + mutbl: hir::Mutability, + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let expected = self.shallow_resolve(expected); + let (rptr_ty, inner_ty) = if self.check_dereferencable(pat.span, expected, &inner) { + // `demand::subtype` would be good enough, but using `eqtype` turns + // out to be equally general. See (note_1) for details. + + // Take region, inner-type from expected type if we can, + // to avoid creating needless variables. This also helps with + // the bad interactions of the given hack detailed in (note_1). + debug!("check_pat_ref: expected={:?}", expected); + match expected.sty { + ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), + _ => { + let inner_ty = self.next_ty_var( + TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: inner.span, + } + ); + let rptr_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); + debug!("check_pat_ref: demanding {:?} = {:?}", expected, rptr_ty); + let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); + + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); + err.emit(); + } + (rptr_ty, inner_ty) + } + } + } else { + (tcx.types.err, tcx.types.err) + }; + self.check_pat(&inner, inner_ty, def_bm, discrim_span); + rptr_ty + } + + /// Create a reference type with a fresh region variable. + fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> { + let region = self.next_region_var(infer::PatternRegion(span)); + let mt = ty::TypeAndMut { ty, mutbl }; + self.tcx.mk_ref(region, mt) + } + + fn check_pat_slice( + &self, + span: Span, + before: &'tcx [P], + slice: Option<&'tcx Pat>, + after: &'tcx [P], + expected: Ty<'tcx>, + def_bm: BindingMode, + discrim_span: Option, + ) -> Ty<'tcx> { + let tcx = self.tcx; + let expected_ty = self.structurally_resolved_type(span, expected); + let (inner_ty, slice_ty) = match expected_ty.sty { + ty::Array(inner_ty, size) => { + let slice_ty = if let Some(size) = size.try_eval_usize(tcx, self.param_env) { + let min_len = before.len() as u64 + after.len() as u64; + if slice.is_none() { + if min_len != size { + self.error_scrutinee_inconsistent_length(span, min_len, size) + } + tcx.types.err + } else if let Some(rest) = size.checked_sub(min_len) { + tcx.mk_array(inner_ty, rest) + } else { + self.error_scrutinee_with_rest_inconsistent_length(span, min_len, size); + tcx.types.err + } + } else { + self.error_scrutinee_unfixed_length(span); + tcx.types.err + }; + (inner_ty, slice_ty) + } + ty::Slice(inner_ty) => (inner_ty, expected_ty), + _ => { + if !expected_ty.references_error() { + self.error_expected_array_or_slice(span, expected_ty); + } + (tcx.types.err, tcx.types.err) + } + }; + + for elt in before { + self.check_pat(&elt, inner_ty, def_bm, discrim_span); + } + if let Some(slice) = slice { + self.check_pat(&slice, slice_ty, def_bm, discrim_span); + } + for elt in after { + self.check_pat(&elt, inner_ty, def_bm, discrim_span); + } + expected_ty + } + + fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { + struct_span_err!( + self.tcx.sess, span, E0527, + "pattern requires {} elements but array has {}", + min_len, size + ) + .span_label(span, format!("expected {} elements", size)) + .emit(); + } + + fn error_scrutinee_with_rest_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { + struct_span_err!( + self.tcx.sess, span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size + ) + .span_label(span, format!("pattern cannot match array of {} elements", size)) + .emit(); + } + + fn error_scrutinee_unfixed_length(&self, span: Span) { + struct_span_err!( + self.tcx.sess, span, E0730, + "cannot pattern-match on an array without a fixed length", + ) + .emit(); + } + + fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>) { + let mut err = struct_span_err!( + self.tcx.sess, span, E0529, + "expected an array or slice, found `{}`", + expected_ty + ); + if let ty::Ref(_, ty, _) = expected_ty.sty { + if let ty::Array(..) | ty::Slice(..) = ty.sty { + err.help("the semantics of slice patterns changed recently; see issue #62254"); + } + } + err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty)); + err.emit(); + } +} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3f9e662c6f412..fc01a820e2359 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -347,12 +347,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { ); self.outlives_environment .save_implied_bounds(body_id.hir_id); - self.link_fn_args( + self.link_fn_params( region::Scope { id: body.value.hir_id.local_id, data: region::ScopeData::Node, }, - &body.arguments, + &body.params, ); self.visit_body(body); self.visit_region_obligations(body_id.hir_id); @@ -1078,16 +1078,16 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Computes the guarantors for any ref bindings in a match and /// then ensures that the lifetime of the resulting pointer is /// linked to the lifetime of its guarantor (if any). - fn link_fn_args(&self, body_scope: region::Scope, args: &[hir::Arg]) { - debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - for arg in args { - let arg_ty = self.node_ty(arg.hir_id); + fn link_fn_params(&self, body_scope: region::Scope, params: &[hir::Param]) { + debug!("regionck::link_fn_params(body_scope={:?})", body_scope); + for param in params { + let param_ty = self.node_ty(param.hir_id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); - let arg_cmt = self.with_mc(|mc| { - Rc::new(mc.cat_rvalue(arg.hir_id, arg.pat.span, re_scope, arg_ty)) + let param_cmt = self.with_mc(|mc| { + Rc::new(mc.cat_rvalue(param.hir_id, param.pat.span, re_scope, param_ty)) }); - debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, arg_cmt, arg); - self.link_pattern(arg_cmt, &arg.pat); + debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); + self.link_pattern(param_cmt, ¶m.pat); } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9c6ea7d30ccf9..f95b3e44bf0f7 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -287,7 +287,7 @@ fn check_type_defn<'tcx, F>( let last = idx == variant.fields.len() - 1; fcx.register_bound( field.ty, - fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), + fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), traits::ObligationCause::new( field.span, fcx.body_id, @@ -375,7 +375,7 @@ fn check_item_type( if forbid_unsized { fcx.register_bound( item_ty, - fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), + fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation), ); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index a88e32eb34dcd..487dc8ec2ae0c 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -39,8 +39,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); - for arg in &body.arguments { - wbcx.visit_node_id(arg.pat.span, arg.hir_id); + for param in &body.params { + wbcx.visit_node_id(param.pat.span, param.hir_id); } // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_id) { @@ -245,8 +245,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { match e.node { hir::ExprKind::Closure(_, _, body, _, _) => { let body = self.fcx.tcx.hir().body(body); - for arg in &body.arguments { - self.visit_node_id(e.span, arg.hir_id); + for param in &body.params { + self.visit_node_id(e.span, param.hir_id); } self.visit_body(body); diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 5a4dc7be326d2..516be99ed6aad 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -464,7 +464,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { // it is *not* required (i.e., '?Sized') let sized_trait = self.cx .tcx - .require_lang_item(lang_items::SizedTraitLangItem); + .require_lang_item(lang_items::SizedTraitLangItem, None); let mut replacer = RegionReplacer { vid_to_region: &vid_to_region, @@ -777,9 +777,9 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { fn is_fn_ty(&self, tcx: TyCtxt<'_>, ty: &Type) -> bool { match &ty { &&Type::ResolvedPath { ref did, .. } => { - *did == tcx.require_lang_item(lang_items::FnTraitLangItem) - || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem) - || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem) + *did == tcx.require_lang_item(lang_items::FnTraitLangItem, None) + || *did == tcx.require_lang_item(lang_items::FnMutTraitLangItem, None) + || *did == tcx.require_lang_item(lang_items::FnOnceTraitLangItem, None) } _ => false, } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6f93c95edef08..cb42ff1c8052f 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -20,6 +20,7 @@ use crate::clean::{ self, GetDefId, ToSource, + TypeKind }; use super::Clean; @@ -107,15 +108,16 @@ pub fn try_inline( record_extern_fqn(cx, did, clean::TypeKind::Const); clean::ConstantItem(build_const(cx, did)) } - // FIXME: proc-macros don't propagate attributes or spans across crates, so they look empty - Res::Def(DefKind::Macro(MacroKind::Bang), did) => { + Res::Def(DefKind::Macro(kind), did) => { let mac = build_macro(cx, did, name); - if let clean::MacroItem(..) = mac { - record_extern_fqn(cx, did, clean::TypeKind::Macro); - mac - } else { - return None; - } + + let type_kind = match kind { + MacroKind::Bang => TypeKind::Macro, + MacroKind::Attr => TypeKind::Attr, + MacroKind::Derive => TypeKind::Derive + }; + record_extern_fqn(cx, did, type_kind); + mac } _ => return None, }; @@ -217,8 +219,9 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { }; let predicates = cx.tcx.predicates_of(did); - let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); - let decl = (did, sig).clean(cx); + let (generics, decl) = clean::enter_impl_trait(cx, || { + ((cx.tcx.generics_of(did), &predicates).clean(cx), (did, sig).clean(cx)) + }); let (all_types, ret_types) = clean::get_all_types(&generics, &decl, cx); clean::Function { decl, @@ -372,7 +375,9 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, attrs: Option>, None } }).collect::>(), - (tcx.generics_of(did), &predicates).clean(cx), + clean::enter_impl_trait(cx, || { + (tcx.generics_of(did), &predicates).clean(cx) + }), ) }; let polarity = tcx.impl_polarity(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9b4803ce41e29..4971155113263 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -45,7 +45,7 @@ use std::cell::RefCell; use std::sync::Arc; use std::u32; -use crate::core::{self, DocContext}; +use crate::core::{self, DocContext, ImplTraitParam}; use crate::doctree; use crate::html::render::{cache, ExternalLocation}; use crate::html::item_type::ItemType; @@ -136,94 +136,88 @@ pub struct Crate { pub collapsed: bool, } -impl Clean for hir::Crate { - // note that self here is ignored in favor of `cx.tcx.hir().krate()` since - // that gets around tying self's lifetime to the '_ in cx. - fn clean(&self, cx: &DocContext<'_>) -> Crate { - use crate::visit_lib::LibEmbargoVisitor; - - let v = crate::visit_ast::RustdocVisitor::new(&cx); - let module = v.visit(cx.tcx.hir().krate()); - - { - let mut r = cx.renderinfo.borrow_mut(); - r.deref_trait_did = cx.tcx.lang_items().deref_trait(); - r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - r.owned_box_did = cx.tcx.lang_items().owned_box(); - } - - let mut externs = Vec::new(); - for &cnum in cx.tcx.crates().iter() { - externs.push((cnum, cnum.clean(cx))); - // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(cx).visit_lib(cnum); - } - externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); - - // Clean the crate, translating the entire libsyntax AST to one that is - // understood by rustdoc. - let mut module = module.clean(cx); - let mut masked_crates = FxHashSet::default(); - - match module.inner { - ModuleItem(ref module) => { - for it in &module.items { - // `compiler_builtins` should be masked too, but we can't apply - // `#[doc(masked)]` to the injected `extern crate` because it's unstable. - if it.is_extern_crate() - && (it.attrs.has_doc_flag(sym::masked) - || cx.tcx.is_compiler_builtins(it.def_id.krate)) - { - masked_crates.insert(it.def_id.krate); - } +pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { + use crate::visit_lib::LibEmbargoVisitor; + + let krate = cx.tcx.hir().krate(); + let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); + + let mut r = cx.renderinfo.get_mut(); + r.deref_trait_did = cx.tcx.lang_items().deref_trait(); + r.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); + r.owned_box_did = cx.tcx.lang_items().owned_box(); + + let mut externs = Vec::new(); + for &cnum in cx.tcx.crates().iter() { + externs.push((cnum, cnum.clean(cx))); + // Analyze doc-reachability for extern items + LibEmbargoVisitor::new(&mut cx).visit_lib(cnum); + } + externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + + // Clean the crate, translating the entire libsyntax AST to one that is + // understood by rustdoc. + let mut module = module.clean(cx); + let mut masked_crates = FxHashSet::default(); + + match module.inner { + ModuleItem(ref module) => { + for it in &module.items { + // `compiler_builtins` should be masked too, but we can't apply + // `#[doc(masked)]` to the injected `extern crate` because it's unstable. + if it.is_extern_crate() + && (it.attrs.has_doc_flag(sym::masked) + || cx.tcx.is_compiler_builtins(it.def_id.krate)) + { + masked_crates.insert(it.def_id.krate); } } - _ => unreachable!(), } + _ => unreachable!(), + } - let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); - { - let m = match module.inner { - ModuleItem(ref mut m) => m, - _ => unreachable!(), - }; - m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { - Item { - source: Span::empty(), - name: Some(prim.to_url_str().to_string()), - attrs: attrs.clone(), - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: PrimitiveItem(prim), - } - })); - m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { - Item { - source: Span::empty(), - name: Some(kw.clone()), - attrs: attrs, - visibility: Some(Public), - stability: get_stability(cx, def_id), - deprecation: get_deprecation(cx, def_id), - def_id, - inner: KeywordItem(kw), - } - })); - } + let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); + { + let m = match module.inner { + ModuleItem(ref mut m) => m, + _ => unreachable!(), + }; + m.items.extend(primitives.iter().map(|&(def_id, prim, ref attrs)| { + Item { + source: Span::empty(), + name: Some(prim.to_url_str().to_string()), + attrs: attrs.clone(), + visibility: Some(Public), + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: PrimitiveItem(prim), + } + })); + m.items.extend(keywords.into_iter().map(|(def_id, kw, attrs)| { + Item { + source: Span::empty(), + name: Some(kw.clone()), + attrs: attrs, + visibility: Some(Public), + stability: get_stability(cx, def_id), + deprecation: get_deprecation(cx, def_id), + def_id, + inner: KeywordItem(kw), + } + })); + } - Crate { - name, - version: None, - src, - module: Some(module), - externs, - primitives, - external_traits: cx.external_traits.clone(), - masked_crates, - collapsed: false, - } + Crate { + name, + version: None, + src, + module: Some(module), + externs, + primitives, + external_traits: cx.external_traits.clone(), + masked_crates, + collapsed: false, } } @@ -572,23 +566,6 @@ pub enum ItemEnum { } impl ItemEnum { - pub fn generics(&self) -> Option<&Generics> { - Some(match *self { - ItemEnum::StructItem(ref s) => &s.generics, - ItemEnum::EnumItem(ref e) => &e.generics, - ItemEnum::FunctionItem(ref f) => &f.generics, - ItemEnum::TypedefItem(ref t, _) => &t.generics, - ItemEnum::OpaqueTyItem(ref t, _) => &t.generics, - ItemEnum::TraitItem(ref t) => &t.generics, - ItemEnum::ImplItem(ref i) => &i.generics, - ItemEnum::TyMethodItem(ref i) => &i.generics, - ItemEnum::MethodItem(ref i) => &i.generics, - ItemEnum::ForeignFunctionItem(ref f) => &f.generics, - ItemEnum::TraitAliasItem(ref ta) => &ta.generics, - _ => return None, - }) - } - pub fn is_associated(&self) -> bool { match *self { ItemEnum::TypedefItem(_, _) | @@ -1060,7 +1037,7 @@ pub enum GenericBound { impl GenericBound { fn maybe_sized(cx: &DocContext<'_>) -> GenericBound { - let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); + let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None); let empty = cx.tcx.intern_substs(&[]); let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); @@ -1540,9 +1517,7 @@ impl Clean for ty::GenericParamDef { ty::GenericParamDefKind::Lifetime => { (self.name.to_string(), GenericParamDefKind::Lifetime) } - ty::GenericParamDefKind::Type { has_default, .. } => { - cx.renderinfo.borrow_mut().external_param_names - .insert(self.def_id, self.name.clean(cx)); + ty::GenericParamDefKind::Type { has_default, synthetic, .. } => { let default = if has_default { Some(cx.tcx.type_of(self.def_id).clean(cx)) } else { @@ -1552,7 +1527,7 @@ impl Clean for ty::GenericParamDef { did: self.def_id, bounds: vec![], // These are filled in from the where-clauses. default, - synthetic: None, + synthetic, }) } ty::GenericParamDefKind::Const { .. } => { @@ -1641,7 +1616,7 @@ impl Clean for hir::Generics { match param.kind { GenericParamDefKind::Lifetime => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone()); + cx.impl_trait_bounds.borrow_mut().insert(did.into(), bounds.clone()); } GenericParamDefKind::Const { .. } => unreachable!(), } @@ -1693,26 +1668,123 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, &'a &'tcx ty::GenericPredicates<'tcx>) { fn clean(&self, cx: &DocContext<'_>) -> Generics { use self::WherePredicate as WP; + use std::collections::BTreeMap; let (gens, preds) = *self; + // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses, + // since `Clean for ty::Predicate` would consume them. + let mut impl_trait = BTreeMap::>::default(); + // Bounds in the type_params and lifetimes fields are repeated in the // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. - let stripped_typarams = gens.params.iter().filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { .. } => { - if param.name.as_symbol() == kw::SelfUpper { - assert_eq!(param.index, 0); - return None; + let stripped_typarams = gens.params.iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { synthetic, .. } => { + if param.name.as_symbol() == kw::SelfUpper { + assert_eq!(param.index, 0); + return None; + } + if synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) { + impl_trait.insert(param.index.into(), vec![]); + return None; + } + Some(param.clean(cx)) + } + ty::GenericParamDefKind::Const { .. } => None, + }).collect::>(); + + // param index -> [(DefId of trait, associated type name, type)] + let mut impl_trait_proj = + FxHashMap::)>>::default(); + + let where_predicates = preds.predicates.iter() + .flat_map(|(p, _)| { + let mut projection = None; + let param_idx = (|| { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if let ty::Param(param) = trait_ref.self_ty().sty { + return Some(param.index); + } + } else if let Some(outlives) = p.to_opt_type_outlives() { + if let ty::Param(param) = outlives.skip_binder().0.sty { + return Some(param.index); + } + } else if let ty::Predicate::Projection(p) = p { + if let ty::Param(param) = p.skip_binder().projection_ty.self_ty().sty { + projection = Some(p); + return Some(param.index); + } + } + + None + })(); + + if let Some(param_idx) = param_idx { + if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { + let p = p.clean(cx)?; + + b.extend( + p.get_bounds() + .into_iter() + .flatten() + .cloned() + .filter(|b| !b.is_sized_bound(cx)) + ); + + let proj = projection + .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty)); + if let Some(((_, trait_did, name), rhs)) = + proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs))) + { + impl_trait_proj + .entry(param_idx) + .or_default() + .push((trait_did, name.to_string(), rhs)); + } + + return None; + } + } + + Some(p) + }) + .collect::>(); + + for (param, mut bounds) in impl_trait { + // Move trait bounds to the front. + bounds.sort_by_key(|b| if let GenericBound::TraitBound(..) = b { + false + } else { + true + }); + + if let crate::core::ImplTraitParam::ParamIndex(idx) = param { + if let Some(proj) = impl_trait_proj.remove(&idx) { + for (trait_did, name, rhs) in proj { + simplify::merge_bounds( + cx, + &mut bounds, + trait_did, + &name, + &rhs.clean(cx), + ); + } } - Some(param.clean(cx)) + } else { + unreachable!(); } - ty::GenericParamDefKind::Const { .. } => None, - }).collect::>(); - let mut where_predicates = preds.predicates.iter() - .flat_map(|(p, _)| p.clean(cx)) + cx.impl_trait_bounds.borrow_mut().insert(param, bounds); + } + + // Now that `cx.impl_trait_bounds` is populated, we can process + // remaining predicates which could contain `impl Trait`. + let mut where_predicates = where_predicates + .into_iter() + .flat_map(|p| p.clean(cx)) .collect::>(); // Type parameters and have a Sized bound by default unless removed with @@ -2023,7 +2095,7 @@ impl<'a> Clean for (&'a [hir::Ty], hir::BodyId) { Arguments { values: self.0.iter().enumerate().map(|(i, ty)| { Argument { - name: name_from_pat(&body.arguments[i].pat), + name: name_from_pat(&body.params[i].pat), type_: ty.clean(cx), } }).collect() @@ -2613,6 +2685,21 @@ impl Type { _ => false, } } + + pub fn projection(&self) -> Option<(&Type, DefId, &str)> { + let (self_, trait_, name) = match self { + QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return None, + }; + let trait_did = match **trait_ { + ResolvedPath { did, .. } => did, + _ => return None, + }; + Some((&self_, trait_did, name)) + } + } impl GetDefId for Type { @@ -2791,7 +2878,7 @@ impl Clean for hir::Ty { if let Some(new_ty) = cx.ty_substs.borrow().get(&did).cloned() { return new_ty; } - if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did) { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&did.into()) { return ImplTrait(bounds); } } @@ -3082,7 +3169,13 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Projection(ref data) => data.clean(cx), - ty::Param(ref p) => Generic(p.name.to_string()), + ty::Param(ref p) => { + if let Some(bounds) = cx.impl_trait_bounds.borrow_mut().remove(&p.index.into()) { + ImplTrait(bounds) + } else { + Generic(p.name.to_string()) + } + } ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, @@ -3686,7 +3779,7 @@ pub struct BareFunctionDecl { impl Clean for hir::BareFnTy { fn clean(&self, cx: &DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, || { - (self.generic_params.clean(cx), (&*self.decl, &self.arg_names[..]).clean(cx)) + (self.generic_params.clean(cx), (&*self.decl, &self.param_names[..]).clean(cx)) }); BareFunctionDecl { unsafety: self.unsafety, diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 3801c42307fc6..8758ab1969116 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -53,58 +53,21 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { // Look for equality predicates on associated types that can be merged into // general bound predicates equalities.retain(|&(ref lhs, ref rhs)| { - let (self_, trait_, name) = match *lhs { - clean::QPath { ref self_type, ref trait_, ref name } => { - (self_type, trait_, name) - } - _ => return true, - }; - let generic = match **self_ { - clean::Generic(ref s) => s, - _ => return true, + let (self_, trait_did, name) = if let Some(p) = lhs.projection() { + p + } else { + return true; }; - let trait_did = match **trait_ { - clean::ResolvedPath { did, .. } => did, + let generic = match self_ { + clean::Generic(s) => s, _ => return true, }; let bounds = match params.get_mut(generic) { Some(bound) => bound, None => return true, }; - !bounds.iter_mut().any(|b| { - let trait_ref = match *b { - clean::GenericBound::TraitBound(ref mut tr, _) => tr, - clean::GenericBound::Outlives(..) => return false, - }; - let (did, path) = match trait_ref.trait_ { - clean::ResolvedPath { did, ref mut path, ..} => (did, path), - _ => return false, - }; - // If this QPath's trait `trait_did` is the same as, or a supertrait - // of, the bound's trait `did` then we can keep going, otherwise - // this is just a plain old equality bound. - if !trait_is_same_or_supertrait(cx, did, trait_did) { - return false - } - let last = path.segments.last_mut().expect("segments were empty"); - match last.args { - PP::AngleBracketed { ref mut bindings, .. } => { - bindings.push(clean::TypeBinding { - name: name.clone(), - kind: clean::TypeBindingKind::Equality { - ty: rhs.clone(), - }, - }); - } - PP::Parenthesized { ref mut output, .. } => { - assert!(output.is_none()); - if *rhs != clean::Type::Tuple(Vec::new()) { - *output = Some(rhs.clone()); - } - } - }; - true - }) + + merge_bounds(cx, bounds, trait_did, name, rhs) }); // And finally, let's reassemble everything @@ -127,6 +90,49 @@ pub fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { clauses } +pub fn merge_bounds( + cx: &clean::DocContext<'_>, + bounds: &mut Vec, + trait_did: DefId, + name: &str, + rhs: &clean::Type, +) -> bool { + !bounds.iter_mut().any(|b| { + let trait_ref = match *b { + clean::GenericBound::TraitBound(ref mut tr, _) => tr, + clean::GenericBound::Outlives(..) => return false, + }; + let (did, path) = match trait_ref.trait_ { + clean::ResolvedPath { did, ref mut path, ..} => (did, path), + _ => return false, + }; + // If this QPath's trait `trait_did` is the same as, or a supertrait + // of, the bound's trait `did` then we can keep going, otherwise + // this is just a plain old equality bound. + if !trait_is_same_or_supertrait(cx, did, trait_did) { + return false + } + let last = path.segments.last_mut().expect("segments were empty"); + match last.args { + PP::AngleBracketed { ref mut bindings, .. } => { + bindings.push(clean::TypeBinding { + name: name.to_string(), + kind: clean::TypeBindingKind::Equality { + ty: rhs.clone(), + }, + }); + } + PP::Parenthesized { ref mut output, .. } => { + assert!(output.is_none()); + if *rhs != clean::Type::Tuple(Vec::new()) { + *output = Some(rhs.clone()); + } + } + }; + true + }) +} + pub fn ty_params(mut params: Vec) -> Vec { for param in &mut params { match param.kind { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 98ab957ecbb38..d261408fc148a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,6 +6,7 @@ use errors; use getopts; use rustc::lint::Level; use rustc::session; +use rustc::session::config::{CrateType, parse_crate_types_from_list}; use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options, get_cmd_lint_options, ExternEntry}; @@ -32,16 +33,24 @@ pub struct Options { pub input: PathBuf, /// The name of the crate being documented. pub crate_name: Option, + /// Whether or not this is a proc-macro crate + pub proc_macro_crate: bool, /// How to format errors and warnings. pub error_format: ErrorOutputType, /// Library search paths to hand to the compiler. pub libs: Vec, + /// Library search paths strings to hand to the compiler. + pub lib_strs: Vec, /// The list of external crates to link against. pub externs: Externs, + /// The list of external crates strings to link against. + pub extern_strs: Vec, /// List of `cfg` flags to hand to the compiler. Always includes `rustdoc`. pub cfgs: Vec, /// Codegen options to hand to the compiler. pub codegen_options: CodegenOptions, + /// Codegen options strings to hand to the compiler. + pub codegen_options_strs: Vec, /// Debugging (`-Z`) options to pass to the compiler. pub debugging_options: DebuggingOptions, /// The target used to compile the crate against. @@ -51,8 +60,6 @@ pub struct Options { pub edition: Edition, /// The path to the sysroot. Used during the compilation process. pub maybe_sysroot: Option, - /// Linker to use when building doctests. - pub linker: Option, /// Lint information passed over the command-line. pub lint_opts: Vec<(String, Level)>, /// Whether to ask rustc to describe the lints it knows. Practically speaking, this will not be @@ -111,6 +118,7 @@ impl fmt::Debug for Options { f.debug_struct("Options") .field("input", &self.input) .field("crate_name", &self.crate_name) + .field("proc_macro_crate", &self.proc_macro_crate) .field("error_format", &self.error_format) .field("libs", &self.libs) .field("externs", &FmtExterns(&self.externs)) @@ -120,7 +128,6 @@ impl fmt::Debug for Options { .field("target", &self.target) .field("edition", &self.edition) .field("maybe_sysroot", &self.maybe_sysroot) - .field("linker", &self.linker) .field("lint_opts", &self.lint_opts) .field("describe_lints", &self.describe_lints) .field("lint_cap", &self.lint_cap) @@ -431,11 +438,19 @@ impl Options { }; let manual_passes = matches.opt_strs("passes"); + let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { + Ok(types) => types, + Err(e) =>{ + diag.struct_err(&format!("unknown crate type: {}", e)).emit(); + return Err(1); + } + }; + let crate_name = matches.opt_str("crate-name"); + let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let display_warnings = matches.opt_present("display-warnings"); - let linker = matches.opt_str("linker").map(PathBuf::from); let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance"); let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default(); let enable_minification = !matches.opt_present("disable-minification"); @@ -448,22 +463,28 @@ impl Options { let generate_search_filter = !matches.opt_present("disable-per-crate-search"); let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let generate_redirect_pages = matches.opt_present("generate-redirect-pages"); + let codegen_options_strs = matches.opt_strs("C"); + let lib_strs = matches.opt_strs("L"); + let extern_strs = matches.opt_strs("extern"); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); Ok(Options { input, crate_name, + proc_macro_crate, error_format, libs, + lib_strs, externs, + extern_strs, cfgs, codegen_options, + codegen_options_strs, debugging_options, target, edition, maybe_sysroot, - linker, lint_opts, describe_lints, lint_cap, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 87381f224d0bb..9cfcad4271966 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -30,7 +30,7 @@ use std::rc::Rc; use crate::config::{Options as RustdocOptions, RenderOptions}; use crate::clean; -use crate::clean::{Clean, MAX_DEF_ID, AttributesExt}; +use crate::clean::{MAX_DEF_ID, AttributesExt}; use crate::html::render::RenderInfo; use crate::passes; @@ -61,8 +61,8 @@ pub struct DocContext<'tcx> { pub lt_substs: RefCell>, /// Table `DefId` of const parameter -> substituted const pub ct_substs: RefCell>, - /// Table DefId of `impl Trait` in argument position -> bounds - pub impl_trait_bounds: RefCell>>, + /// Table synthetic type parameter for `impl Trait` in argument position -> bounds + pub impl_trait_bounds: RefCell>>, pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`. @@ -193,6 +193,7 @@ pub fn new_handler(error_format: ErrorOutputType, source_map.map(|cm| cm as _), short, sessopts.debugging_opts.teach, + sessopts.debugging_opts.terminal_width, ).ui_testing(ui_testing) ) }, @@ -228,6 +229,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let RustdocOptions { input, crate_name, + proc_macro_crate, error_format, libs, externs, @@ -293,11 +295,16 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }).collect(); let host_triple = TargetTriple::from_triple(config::host_triple()); + let crate_types = if proc_macro_crate { + vec![config::CrateType::ProcMacro] + } else { + vec![config::CrateType::Rlib] + }; // plays with error output here! let sessopts = config::Options { maybe_sysroot, search_paths: libs, - crate_types: vec![config::CrateType::Rlib], + crate_types, lint_opts: if !display_warnings { lint_opts } else { @@ -363,7 +370,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut renderinfo = RenderInfo::default(); renderinfo.access_levels = access_levels; - let ctxt = DocContext { + let mut ctxt = DocContext { tcx, resolver, cstore: compiler.cstore().clone(), @@ -383,7 +390,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; debug!("crate: {:?}", tcx.hir().krate()); - let mut krate = tcx.hir().krate().clean(&ctxt); + let mut krate = clean::krate(&mut ctxt); fn report_deprecated_attr(name: &str, diag: &errors::Handler) { let mut msg = diag.struct_warn(&format!("the `#![doc({})]` attribute is \ @@ -459,3 +466,23 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) }) } + +/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter +/// for `impl Trait` in argument position. +#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ImplTraitParam { + DefId(DefId), + ParamIndex(u32), +} + +impl From for ImplTraitParam { + fn from(did: DefId) -> Self { + ImplTraitParam::DefId(did) + } +} + +impl From for ImplTraitParam { + fn from(idx: u32) -> Self { + ImplTraitParam::ParamIndex(idx) + } +} diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9c22837bdae87..313734e3fdd6b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -6,6 +6,7 @@ //! them in the future to instead emit any format desired. use std::borrow::Cow; +use std::cell::Cell; use std::fmt; use rustc::hir::def_id::DefId; @@ -15,7 +16,7 @@ use rustc::hir; use crate::clean::{self, PrimitiveType}; use crate::html::item_type::ItemType; -use crate::html::render::{self, cache, CURRENT_LOCATION_KEY}; +use crate::html::render::{self, cache, CURRENT_DEPTH}; /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) @@ -36,13 +37,8 @@ pub struct AsyncSpace(pub hir::IsAsync); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); -/// Similar to VisSpace, but used for mutability -#[derive(Copy, Clone)] -pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting type parameter bounds. pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]); -/// Wrapper struct for emitting a comma-separated list of items -pub struct CommaSep<'a, T>(pub &'a [T]); pub struct AbiSpace(pub Abi); pub struct DefaultSpace(pub bool); @@ -71,11 +67,6 @@ pub struct WhereClause<'a>{ pub end_newline: bool, } -pub struct HRef<'a> { - pub did: DefId, - pub text: &'a str, -} - impl<'a> VisSpace<'a> { pub fn get(self) -> &'a Option { let VisSpace(v) = self; v @@ -94,14 +85,14 @@ impl ConstnessSpace { } } -impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, item) in self.0.iter().enumerate() { +fn comma_sep(items: &[T]) -> impl fmt::Display + '_ { + display_fn(move |f| { + for (i, item) in items.iter().enumerate() { if i != 0 { write!(f, ", ")?; } fmt::Display::fmt(item, f)?; } Ok(()) - } + }) } impl<'a> fmt::Display for GenericBounds<'a> { @@ -168,9 +159,9 @@ impl fmt::Display for clean::Generics { return Ok(()); } if f.alternate() { - write!(f, "<{:#}>", CommaSep(&real_params)) + write!(f, "<{:#}>", comma_sep(&real_params)) } else { - write!(f, "<{}>", CommaSep(&real_params)) + write!(f, "<{}>", comma_sep(&real_params)) } } } @@ -268,9 +259,9 @@ impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if !self.generic_params.is_empty() { if f.alternate() { - write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?; + write!(f, "for<{:#}> ", comma_sep(&self.generic_params))?; } else { - write!(f, "for<{}> ", CommaSep(&self.generic_params))?; + write!(f, "for<{}> ", comma_sep(&self.generic_params))?; } } if f.alternate() { @@ -407,16 +398,16 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { return None } - let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); + let depth = CURRENT_DEPTH.with(|l| l.get()); let (fqp, shortty, mut url) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => { - (fqp, shortty, "../".repeat(loc.len())) + (fqp, shortty, "../".repeat(depth)) } None => { let &(ref fqp, shortty) = cache.external_paths.get(&did)?; (fqp, shortty, match cache.extern_locations[&did.krate] { (.., render::Remote(ref s)) => s.to_string(), - (.., render::Local) => "../".repeat(loc.len()), + (.., render::Local) => "../".repeat(depth), (.., render::Unknown) => return None, }) } @@ -452,19 +443,18 @@ fn resolved_path(w: &mut fmt::Formatter<'_>, did: DefId, path: &clean::Path, } } if w.alternate() { - write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?; + write!(w, "{}{:#}", &last.name, last.args)?; } else { let path = if use_absolute { - match href(did) { - Some((_, _, fqp)) => { - format!("{}::{}", - fqp[..fqp.len() - 1].join("::"), - HRef::new(did, fqp.last().unwrap())) - } - None => HRef::new(did, &last.name).to_string(), + if let Some((_, _, fqp)) = href(did) { + format!("{}::{}", + fqp[..fqp.len() - 1].join("::"), + anchor(did, fqp.last().unwrap())) + } else { + last.name.to_string() } } else { - HRef::new(did, &last.name).to_string() + anchor(did, &last.name).to_string() }; write!(w, "{}{}", path, last.args)?; } @@ -479,7 +469,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, if !f.alternate() { match m.primitive_locations.get(&prim) { Some(&def_id) if def_id.is_local() => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); let len = if len == 0 {0} else {len - 1}; write!(f, "", "../".repeat(len), @@ -492,7 +482,7 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, Some((cname, s.to_string())) } (ref cname, _, render::Local) => { - let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len()); + let len = CURRENT_DEPTH.with(|s| s.get()); Some((cname, "../".repeat(len))) } (.., render::Unknown) => None, @@ -516,38 +506,30 @@ fn primitive_link(f: &mut fmt::Formatter<'_>, } /// Helper to render type parameters -fn tybounds(w: &mut fmt::Formatter<'_>, - param_names: &Option>) -> fmt::Result { - match *param_names { - Some(ref params) => { - for param in params { - write!(w, " + ")?; - fmt::Display::fmt(param, w)?; +fn tybounds(param_names: &Option>) -> impl fmt::Display + '_ { + display_fn(move |f| { + match *param_names { + Some(ref params) => { + for param in params { + write!(f, " + ")?; + fmt::Display::fmt(param, f)?; + } + Ok(()) } - Ok(()) + None => Ok(()) } - None => Ok(()) - } -} - -impl<'a> HRef<'a> { - pub fn new(did: DefId, text: &'a str) -> HRef<'a> { - HRef { did: did, text: text } - } + }) } -impl<'a> fmt::Display for HRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match href(self.did) { - Some((url, shortty, fqp)) => if !f.alternate() { - write!(f, "{}", - shortty, url, shortty, fqp.join("::"), self.text) - } else { - write!(f, "{}", self.text) - }, - _ => write!(f, "{}", self.text), +pub fn anchor(did: DefId, text: &str) -> impl fmt::Display + '_ { + display_fn(move |f| { + if let Some((url, short_ty, fqp)) = href(did) { + write!(f, r#"{}"#, + short_ty, url, short_ty, fqp.join("::"), text) + } else { + write!(f, "{}", text) } - } + }) } fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> fmt::Result { @@ -561,7 +543,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } // Paths like `T::Output` and `Self::Output` should be rendered with all segments. resolved_path(f, did, path, is_generic, use_absolute)?; - tybounds(f, param_names) + fmt::Display::fmt(&tybounds(param_names), f) } clean::Infer => write!(f, "_"), clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()), @@ -570,12 +552,12 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> write!(f, "{}{:#}fn{:#}{:#}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi), - CommaSep(&decl.generic_params), + comma_sep(&decl.generic_params), decl.decl) } else { write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?; primitive_link(f, PrimitiveType::Fn, "fn")?; - write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl) + write!(f, "{}{}", comma_sep(&decl.generic_params), decl.decl) } } clean::Tuple(ref typs) => { @@ -589,7 +571,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> } many => { primitive_link(f, PrimitiveType::Tuple, "(")?; - fmt::Display::fmt(&CommaSep(many), f)?; + fmt::Display::fmt(&comma_sep(many), f)?; primitive_link(f, PrimitiveType::Tuple, ")") } } @@ -607,19 +589,22 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> clean::Never => primitive_link(f, PrimitiveType::Never, "!"), clean::CVarArgs => primitive_link(f, PrimitiveType::CVarArgs, "..."), clean::RawPointer(m, ref t) => { + let m = match m { + clean::Immutable => "const", + clean::Mutable => "mut", + }; match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { if f.alternate() { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{:#}", RawMutableSpace(m), t)) + &format!("*{} {:#}", m, t)) } else { primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}{}", RawMutableSpace(m), t)) + &format!("*{} {}", m, t)) } } _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, - &format!("*{}", RawMutableSpace(m)))?; + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m))?; fmt::Display::fmt(t, f) } } @@ -1047,15 +1032,6 @@ impl fmt::Display for MutableSpace { } } -impl fmt::Display for RawMutableSpace { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - RawMutableSpace(clean::Immutable) => write!(f, "const "), - RawMutableSpace(clean::Mutable) => write!(f, "mut "), - } - } -} - impl fmt::Display for AbiSpace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let quot = if f.alternate() { "\"" } else { """ }; @@ -1075,3 +1051,19 @@ impl fmt::Display for DefaultSpace { } } } + +crate fn display_fn( + f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +) -> impl fmt::Display { + WithFormatter(Cell::new(Some(f))) +} + +struct WithFormatter(Cell>); + +impl fmt::Display for WithFormatter + where F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0.take()).unwrap()(f) + } +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 5a7deb651b00d..74413a7f905d4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -785,10 +785,6 @@ impl MarkdownSummaryLine<'_> { } pub fn plain_summary_line(md: &str) -> String { - plain_summary_line_full(md, false) -} - -pub fn plain_summary_line_full(md: &str, limit_length: bool) -> String { struct ParserWrapper<'a> { inner: Parser<'a>, is_in: isize, @@ -834,21 +830,7 @@ pub fn plain_summary_line_full(md: &str, limit_length: bool) -> String { s.push_str(&t); } } - if limit_length && s.chars().count() > 60 { - let mut len = 0; - let mut ret = s.split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::>() - .join(" "); - ret.push('…'); - ret - } else { - s - } + s } pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ea97cea942820..d5c47a15948fb 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -28,7 +28,7 @@ pub use self::ExternalLocation::*; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::cmp::Ordering; use std::collections::{BTreeMap, VecDeque}; use std::default::Default; @@ -72,6 +72,7 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::item_type::ItemType; use crate::html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, ErrorCodes, IdMap}; use crate::html::{highlight, layout, static_files}; +use crate::html::sources; use minifier; @@ -173,7 +174,7 @@ struct Context { playground: Option, } -struct SharedContext { +crate struct SharedContext { /// The path to the crate root source minus the file name. /// Used for simplifying paths to the highlighted source code files. pub src_root: PathBuf, @@ -218,7 +219,7 @@ struct SharedContext { } impl SharedContext { - fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { + crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> { let mut dirs = self.created_dirs.borrow_mut(); if !dirs.contains(dst) { try_err!(self.fs.create_dir_all(dst), dst); @@ -281,11 +282,6 @@ impl Impl { /// rendering threads. #[derive(Default)] pub struct Cache { - /// Mapping of typaram ids to the name of the type parameter. This is used - /// when pretty-printing a type (so pretty-printing doesn't have to - /// painfully maintain a context like this) - pub param_names: FxHashMap, - /// Maps a type ID to all known implementations for that type. This is only /// recognized for intra-crate `ResolvedPath` types, and is used to print /// out extra documentation on the page of an enum/struct. @@ -381,7 +377,6 @@ pub struct Cache { pub struct RenderInfo { pub inlined: FxHashSet, pub external_paths: crate::core::ExternalPaths, - pub external_param_names: FxHashMap, pub exact_paths: FxHashMap>, pub access_levels: AccessLevels, pub deref_trait_did: Option, @@ -389,18 +384,6 @@ pub struct RenderInfo { pub owned_box_did: Option, } -/// Helper struct to render all source code to HTML pages -struct SourceCollector<'a> { - scx: &'a mut SharedContext, - - /// Root destination to place all HTML output into - dst: PathBuf, -} - -/// Wrapper struct to render the source code of a file. This will do things like -/// adding line numbers to the left-hand side. -struct Source<'a>(&'a str); - // Helper structs for rendering items/sidebars and carrying along contextual // information @@ -496,7 +479,7 @@ impl ToJson for IndexItemFunctionType { } thread_local!(static CACHE_KEY: RefCell> = Default::default()); -thread_local!(pub static CURRENT_LOCATION_KEY: RefCell> = RefCell::new(Vec::new())); +thread_local!(pub static CURRENT_DEPTH: Cell = Cell::new(0)); pub fn initial_ids() -> Vec { [ @@ -612,7 +595,7 @@ pub fn run(mut krate: clean::Crate, } let dst = output; scx.ensure_dir(&dst)?; - krate = render_sources(&dst, &mut scx, krate)?; + krate = sources::render(&dst, &mut scx, krate)?; let mut cx = Context { current: Vec::new(), dst, @@ -628,7 +611,6 @@ pub fn run(mut krate: clean::Crate, let RenderInfo { inlined: _, external_paths, - external_param_names, exact_paths, access_levels, deref_trait_did, @@ -662,7 +644,6 @@ pub fn run(mut krate: clean::Crate, deref_mut_trait_did, owned_box_did, masked_crates: mem::take(&mut krate.masked_crates), - param_names: external_param_names, aliases: Default::default(), }; @@ -714,7 +695,7 @@ pub fn run(mut krate: clean::Crate, // for future parallelization opportunities let cache = Arc::new(cache); CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone()); - CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear()); + CURRENT_DEPTH.with(|s| s.set(0)); // Write shared runs within a flock; disable thread dispatching of IO temporarily. Arc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true); @@ -751,7 +732,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -789,7 +770,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { } let crate_doc = krate.module.as_ref().map(|module| { - plain_summary_line_short(module.doc_value()) + shorten(plain_summary_line(module.doc_value())) }).unwrap_or(String::new()); let mut crate_data = BTreeMap::new(); @@ -876,22 +857,22 @@ r#"var themes = document.getElementById("theme-choices"); var themePicker = document.getElementById("theme-picker"); function showThemeButtonState() {{ - themes.style.display = "none"; - themePicker.style.borderBottomRightRadius = "3px"; - themePicker.style.borderBottomLeftRadius = "3px"; -}} - -function hideThemeButtonState() {{ themes.style.display = "block"; themePicker.style.borderBottomRightRadius = "0"; themePicker.style.borderBottomLeftRadius = "0"; }} +function hideThemeButtonState() {{ + themes.style.display = "none"; + themePicker.style.borderBottomRightRadius = "3px"; + themePicker.style.borderBottomLeftRadius = "3px"; +}} + function switchThemeButtonState() {{ if (themes.style.display === "block") {{ - showThemeButtonState(); - }} else {{ hideThemeButtonState(); + }} else {{ + showThemeButtonState(); }} }}; @@ -914,7 +895,7 @@ themePicker.onblur = handleThemeButtonsBlur; var but = document.createElement('button'); but.innerHTML = item; but.onclick = function(el) {{ - switchTheme(currentTheme, mainTheme, item); + switchTheme(currentTheme, mainTheme, item, true); }}; but.onblur = handleThemeButtonsBlur; themes.appendChild(but); @@ -1293,18 +1274,6 @@ themePicker.onblur = handleThemeButtonsBlur; Ok(()) } -fn render_sources(dst: &Path, scx: &mut SharedContext, - krate: clean::Crate) -> Result { - info!("emitting source files"); - let dst = dst.join("src").join(&krate.name); - scx.ensure_dir(&dst)?; - let mut folder = SourceCollector { - dst, - scx, - }; - Ok(folder.fold_crate(krate)) -} - fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bool ) -> Result<(), Error> { if enable_minification { @@ -1384,33 +1353,6 @@ fn write_minify_replacer( } } -/// Takes a path to a source file and cleans the path to it. This canonicalizes -/// things like ".." to components which preserve the "top down" hierarchy of a -/// static HTML tree. Each component in the cleaned path will be passed as an -/// argument to `f`. The very last component of the path (ie the file name) will -/// be passed to `f` if `keep_filename` is true, and ignored otherwise. -fn clean_srcpath(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) -where - F: FnMut(&OsStr), -{ - // make it relative, if possible - let p = p.strip_prefix(src_root).unwrap_or(p); - - let mut iter = p.components().peekable(); - - while let Some(c) = iter.next() { - if !keep_filename && iter.peek().is_none() { - break; - } - - match c { - Component::ParentDir => f("up".as_ref()), - Component::Normal(c) => f(c), - _ => continue, - } - } -} - /// Attempts to find where an external crate is located, given that we're /// rendering in to the specified source destination. fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path) @@ -1444,102 +1386,6 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat }).next().unwrap_or(Unknown) // Well, at least we tried. } -impl<'a> DocFolder for SourceCollector<'a> { - fn fold_item(&mut self, item: clean::Item) -> Option { - // If we're including source files, and we haven't seen this file yet, - // then we need to render it out to the filesystem. - if self.scx.include_sources - // skip all invalid or macro spans - && item.source.filename.is_real() - // skip non-local items - && item.def_id.is_local() { - - // If it turns out that we couldn't read this file, then we probably - // can't read any of the files (generating html output from json or - // something like that), so just don't include sources for the - // entire crate. The other option is maintaining this mapping on a - // per-file basis, but that's probably not worth it... - self.scx - .include_sources = match self.emit_source(&item.source.filename) { - Ok(()) => true, - Err(e) => { - println!("warning: source code was requested to be rendered, \ - but processing `{}` had an error: {}", - item.source.filename, e); - println!(" skipping rendering of source code"); - false - } - }; - } - self.fold_item_recur(item) - } -} - -impl<'a> SourceCollector<'a> { - /// Renders the given filename into its corresponding HTML source file. - fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { - let p = match *filename { - FileName::Real(ref file) => file, - _ => return Ok(()), - }; - if self.scx.local_sources.contains_key(&**p) { - // We've already emitted this source - return Ok(()); - } - - let contents = try_err!(fs::read_to_string(&p), &p); - - // Remove the utf-8 BOM if any - let contents = if contents.starts_with("\u{feff}") { - &contents[3..] - } else { - &contents[..] - }; - - // Create the intermediate directories - let mut cur = self.dst.clone(); - let mut root_path = String::from("../../"); - let mut href = String::new(); - clean_srcpath(&self.scx.src_root, &p, false, |component| { - cur.push(component); - root_path.push_str("../"); - href.push_str(&component.to_string_lossy()); - href.push('/'); - }); - self.scx.ensure_dir(&cur)?; - let mut fname = p.file_name() - .expect("source has no filename") - .to_os_string(); - fname.push(".html"); - cur.push(&fname); - href.push_str(&fname.to_string_lossy()); - - let mut v = Vec::new(); - let title = format!("{} -- source", cur.file_name().expect("failed to get file name") - .to_string_lossy()); - let desc = format!("Source to the Rust file `{}`.", filename); - let page = layout::Page { - title: &title, - css_class: "source", - root_path: &root_path, - static_root_path: self.scx.static_root_path.as_deref(), - description: &desc, - keywords: BASIC_KEYWORDS, - resource_suffix: &self.scx.resource_suffix, - extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], - static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], - }; - try_err!(layout::render(&mut v, &self.scx.layout, - &page, &(""), &Source(contents), - self.scx.css_file_extension.is_some(), - &self.scx.themes, - self.scx.generate_search_filter), &cur); - self.scx.fs.write(&cur, &v)?; - self.scx.local_sources.insert(p.clone(), href); - Ok(()) - } -} - impl DocFolder for Cache { fn fold_item(&mut self, item: clean::Item) -> Option { if item.def_id.is_local() { @@ -1565,12 +1411,6 @@ impl DocFolder for Cache { } } - // Register any generics to their corresponding string. This is used - // when pretty-printing types. - if let Some(generics) = item.inner.generics() { - self.generics(generics); - } - // Propagate a trait method's documentation to all implementors of the // trait. if let clean::TraitItem(ref t) = item.inner { @@ -1642,7 +1482,7 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent, parent_idx: None, search_type: get_index_search_type(&item), @@ -1803,18 +1643,6 @@ impl DocFolder for Cache { } impl Cache { - fn generics(&mut self, generics: &clean::Generics) { - for param in &generics.params { - match param.kind { - clean::GenericParamDefKind::Lifetime => {} - clean::GenericParamDefKind::Type { did, .. } | - clean::GenericParamDefKind::Const { did, .. } => { - self.param_names.insert(did, param.name.clone()); - } - } - } - } - fn add_aliases(&mut self, item: &clean::Item) { if item.def_id.index == CRATE_DEF_INDEX { return @@ -1836,7 +1664,7 @@ impl Cache { ty: item.type_(), name: item_name.to_string(), path: path.clone(), - desc: plain_summary_line_short(item.doc_value()), + desc: shorten(plain_summary_line(item.doc_value())), parent: None, parent_idx: None, search_type: get_index_search_type(&item), @@ -2057,31 +1885,6 @@ impl Context { "../".repeat(self.current.len()) } - /// Recurse in the directory structure and change the "root path" to make - /// sure it always points to the top (relatively). - fn recurse(&mut self, s: String, f: F) -> T where - F: FnOnce(&mut Context) -> T, - { - if s.is_empty() { - panic!("Unexpected empty destination: {:?}", self.current); - } - let prev = self.dst.clone(); - self.dst.push(&s); - self.current.push(s); - - info!("Recursing into {}", self.dst.display()); - - let ret = f(self); - - info!("Recursed; leaving {}", self.dst.display()); - - // Go back to where we were at - self.dst = prev; - self.current.pop().unwrap(); - - ret - } - /// Main method for rendering a crate. /// /// This currently isn't parallelized, but it'd be pretty easy to add @@ -2175,8 +1978,8 @@ impl Context { -> io::Result<()> { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. - CURRENT_LOCATION_KEY.with(|slot| { - *slot.borrow_mut() = self.current.clone(); + CURRENT_DEPTH.with(|slot| { + slot.set(self.current.len()); }); let mut title = if it.is_primitive() || it.is_keyword() { @@ -2262,42 +2065,50 @@ impl Context { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. let name = item.name.as_ref().unwrap().to_string(); - let mut item = Some(item); - let scx = self.shared.clone(); - self.recurse(name, |this| { - let item = item.take().unwrap(); - - let mut buf = Vec::new(); - this.render_item(&mut buf, &item, false).unwrap(); - // buf will be empty if the module is stripped and there is no redirect for it - if !buf.is_empty() { - this.shared.ensure_dir(&this.dst)?; - let joint_dst = this.dst.join("index.html"); - scx.fs.write(&joint_dst, buf)?; - } + let scx = &self.shared; + if name.is_empty() { + panic!("Unexpected empty destination: {:?}", self.current); + } + let prev = self.dst.clone(); + self.dst.push(&name); + self.current.push(name); - let m = match item.inner { - clean::StrippedItem(box clean::ModuleItem(m)) | - clean::ModuleItem(m) => m, - _ => unreachable!() - }; + info!("Recursing into {}", self.dst.display()); - // Render sidebar-items.js used throughout this module. - if !this.render_redirect_pages { - let items = this.build_sidebar_items(&m); - let js_dst = this.dst.join("sidebar-items.js"); - let mut v = Vec::new(); - try_err!(write!(&mut v, "initSidebarItems({});", - as_json(&items)), &js_dst); - scx.fs.write(&js_dst, &v)?; - } + let mut buf = Vec::new(); + self.render_item(&mut buf, &item, false).unwrap(); + // buf will be empty if the module is stripped and there is no redirect for it + if !buf.is_empty() { + self.shared.ensure_dir(&self.dst)?; + let joint_dst = self.dst.join("index.html"); + scx.fs.write(&joint_dst, buf)?; + } - for item in m.items { - f(this, item); - } + let m = match item.inner { + clean::StrippedItem(box clean::ModuleItem(m)) | + clean::ModuleItem(m) => m, + _ => unreachable!() + }; + + // Render sidebar-items.js used throughout this module. + if !self.render_redirect_pages { + let items = self.build_sidebar_items(&m); + let js_dst = self.dst.join("sidebar-items.js"); + let mut v = Vec::new(); + try_err!(write!(&mut v, "initSidebarItems({});", + as_json(&items)), &js_dst); + scx.fs.write(&js_dst, &v)?; + } + + for item in m.items { + f(self, item); + } - Ok(()) - })?; + info!("Recursed; leaving {}", self.dst.display()); + + // Go back to where we were at + self.dst = prev; + self.current.pop().unwrap(); } else if item.name.is_some() { let mut buf = Vec::new(); self.render_item(&mut buf, &item, true).unwrap(); @@ -2399,7 +2210,7 @@ impl<'a> Item<'a> { (_, _, Unknown) => return None, }; - clean_srcpath(&src_root, file, false, |component| { + sources::clean_path(&src_root, file, false, |component| { path.push_str(&component.to_string_lossy()); path.push('/'); }); @@ -2549,29 +2360,39 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -fn shorter(s: Option<&str>) -> String { - match s { - Some(s) => s.lines() - .skip_while(|s| s.chars().all(|c| c.is_whitespace())) - .take_while(|line|{ - (*line).chars().any(|chr|{ - !chr.is_whitespace() - }) - }).collect::>().join("\n"), - None => String::new() - } -} - #[inline] fn plain_summary_line(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], false) -} - -#[inline] -fn plain_summary_line_short(s: Option<&str>) -> String { - let line = shorter(s).replace("\n", " "); - markdown::plain_summary_line_full(&line[..], true) + let s = s.unwrap_or(""); + // This essentially gets the first paragraph of text in one line. + let mut line = s.lines() + .skip_while(|line| line.chars().all(|c| c.is_whitespace())) + .take_while(|line| line.chars().any(|c| !c.is_whitespace())) + .fold(String::new(), |mut acc, line| { + acc.push_str(line); + acc.push(' '); + acc + }); + // remove final whitespace + line.pop(); + markdown::plain_summary_line(&line[..]) +} + +fn shorten(s: String) -> String { + if s.chars().count() > 60 { + let mut len = 0; + let mut ret = s.split_whitespace() + .take_while(|p| { + // + 1 for the added character after the word. + len += p.chars().count() + 1; + len < 60 + }) + .collect::>() + .join(" "); + ret.push('…'); + ret + } else { + s + } } fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result { @@ -2584,13 +2405,14 @@ fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt } /// Render md_text as markdown. -fn render_markdown(w: &mut fmt::Formatter<'_>, - cx: &Context, - md_text: &str, - links: Vec<(String, String)>, - prefix: &str, - is_hidden: bool) - -> fmt::Result { +fn render_markdown( + w: &mut fmt::Formatter<'_>, + cx: &Context, + md_text: &str, + links: Vec<(String, String)>, + prefix: &str, + is_hidden: bool, +) -> fmt::Result { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}{}
", if is_hidden { " hidden" } else { "" }, @@ -2604,7 +2426,8 @@ fn document_short( cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, - prefix: &str, is_hidden: bool + prefix: &str, + is_hidden: bool, ) -> fmt::Result { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { @@ -2816,19 +2639,19 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, match myitem.inner { clean::ExternCrateItem(ref name, ref src) => { - use crate::html::format::HRef; + use crate::html::format::anchor; match *src { Some(ref src) => { write!(w, "{}extern crate {} as {};", VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, src), + anchor(myitem.def_id, src), name)? } None => { write!(w, "{}extern crate {};", VisSpace(&myitem.visibility), - HRef::new(myitem.def_id, name))? + anchor(myitem.def_id, name))? } } write!(w, "")?; @@ -4263,9 +4086,10 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_), }; - let (is_hidden, extra_class) = if trait_.is_none() || - item.doc_value().is_some() || - item.inner.is_associated() { + let (is_hidden, extra_class) = if (trait_.is_none() || + item.doc_value().is_some() || + item.inner.is_associated()) && + !is_default_item { (false, "") } else { (true, " hidden") @@ -5048,27 +4872,6 @@ fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt:: Ok(()) } -impl<'a> fmt::Display for Source<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Source(s) = *self; - let lines = s.lines().count(); - let mut cols = 0; - let mut tmp = lines; - while tmp > 0 { - cols += 1; - tmp /= 10; - } - write!(fmt, "
")?;
-        for i in 1..=lines {
-            write!(fmt, "{0:1$}\n", i, cols)?;
-        }
-        write!(fmt, "
")?; - write!(fmt, "{}", - highlight::render_with_highlighting(s, None, None, None))?; - Ok(()) - } -} - fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::Macro) -> fmt::Result { wrap_into_docblock(w, |w| { @@ -5125,7 +4928,7 @@ fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context, document(w, cx, it) } -const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; +crate const BASIC_KEYWORDS: &'static str = "rust, rustlang, rust-lang"; fn make_item_keywords(it: &clean::Item) -> String { format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap()) diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs new file mode 100644 index 0000000000000..c1f1f59d9149a --- /dev/null +++ b/src/librustdoc/html/sources.rs @@ -0,0 +1,187 @@ +use crate::clean; +use crate::docfs::PathError; +use crate::fold::DocFolder; +use crate::html::layout; +use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS}; +use crate::html::highlight; +use std::ffi::OsStr; +use std::fs; +use std::path::{Component, Path, PathBuf}; +use std::fmt; +use syntax::source_map::FileName; + +crate fn render(dst: &Path, scx: &mut SharedContext, + krate: clean::Crate) -> Result { + info!("emitting source files"); + let dst = dst.join("src").join(&krate.name); + scx.ensure_dir(&dst)?; + let mut folder = SourceCollector { + dst, + scx, + }; + Ok(folder.fold_crate(krate)) +} + +/// Helper struct to render all source code to HTML pages +struct SourceCollector<'a> { + scx: &'a mut SharedContext, + + /// Root destination to place all HTML output into + dst: PathBuf, +} + +impl<'a> DocFolder for SourceCollector<'a> { + fn fold_item(&mut self, item: clean::Item) -> Option { + // If we're including source files, and we haven't seen this file yet, + // then we need to render it out to the filesystem. + if self.scx.include_sources + // skip all invalid or macro spans + && item.source.filename.is_real() + // skip non-local items + && item.def_id.is_local() { + + // If it turns out that we couldn't read this file, then we probably + // can't read any of the files (generating html output from json or + // something like that), so just don't include sources for the + // entire crate. The other option is maintaining this mapping on a + // per-file basis, but that's probably not worth it... + self.scx + .include_sources = match self.emit_source(&item.source.filename) { + Ok(()) => true, + Err(e) => { + println!("warning: source code was requested to be rendered, \ + but processing `{}` had an error: {}", + item.source.filename, e); + println!(" skipping rendering of source code"); + false + } + }; + } + self.fold_item_recur(item) + } +} + +impl<'a> SourceCollector<'a> { + /// Renders the given filename into its corresponding HTML source file. + fn emit_source(&mut self, filename: &FileName) -> Result<(), Error> { + let p = match *filename { + FileName::Real(ref file) => file, + _ => return Ok(()), + }; + if self.scx.local_sources.contains_key(&**p) { + // We've already emitted this source + return Ok(()); + } + + let contents = match fs::read_to_string(&p) { + Ok(contents) => contents, + Err(e) => { + return Err(Error::new(e, &p)); + } + }; + + // Remove the utf-8 BOM if any + let contents = if contents.starts_with("\u{feff}") { + &contents[3..] + } else { + &contents[..] + }; + + // Create the intermediate directories + let mut cur = self.dst.clone(); + let mut root_path = String::from("../../"); + let mut href = String::new(); + clean_path(&self.scx.src_root, &p, false, |component| { + cur.push(component); + root_path.push_str("../"); + href.push_str(&component.to_string_lossy()); + href.push('/'); + }); + self.scx.ensure_dir(&cur)?; + let mut fname = p.file_name() + .expect("source has no filename") + .to_os_string(); + fname.push(".html"); + cur.push(&fname); + href.push_str(&fname.to_string_lossy()); + + let mut v = Vec::new(); + let title = format!("{} -- source", cur.file_name().expect("failed to get file name") + .to_string_lossy()); + let desc = format!("Source to the Rust file `{}`.", filename); + let page = layout::Page { + title: &title, + css_class: "source", + root_path: &root_path, + static_root_path: self.scx.static_root_path.as_deref(), + description: &desc, + keywords: BASIC_KEYWORDS, + resource_suffix: &self.scx.resource_suffix, + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], + static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], + }; + let result = layout::render(&mut v, &self.scx.layout, + &page, &(""), &Source(contents), + self.scx.css_file_extension.is_some(), + &self.scx.themes, + self.scx.generate_search_filter); + if let Err(e) = result { + return Err(Error::new(e, &cur)); + } + self.scx.fs.write(&cur, &v)?; + self.scx.local_sources.insert(p.clone(), href); + Ok(()) + } +} + +/// Takes a path to a source file and cleans the path to it. This canonicalizes +/// things like ".." to components which preserve the "top down" hierarchy of a +/// static HTML tree. Each component in the cleaned path will be passed as an +/// argument to `f`. The very last component of the path (ie the file name) will +/// be passed to `f` if `keep_filename` is true, and ignored otherwise. +pub fn clean_path(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) +where + F: FnMut(&OsStr), +{ + // make it relative, if possible + let p = p.strip_prefix(src_root).unwrap_or(p); + + let mut iter = p.components().peekable(); + + while let Some(c) = iter.next() { + if !keep_filename && iter.peek().is_none() { + break; + } + + match c { + Component::ParentDir => f("up".as_ref()), + Component::Normal(c) => f(c), + _ => continue, + } + } +} + +/// Wrapper struct to render the source code of a file. This will do things like +/// adding line numbers to the left-hand side. +struct Source<'a>(&'a str); + +impl<'a> fmt::Display for Source<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let Source(s) = *self; + let lines = s.lines().count(); + let mut cols = 0; + let mut tmp = lines; + while tmp > 0 { + cols += 1; + tmp /= 10; + } + write!(fmt, "
")?;
+        for i in 1..=lines {
+            write!(fmt, "{0:1$}\n", i, cols)?;
+        }
+        write!(fmt, "
")?; + write!(fmt, "{}", + highlight::render_with_highlighting(s, None, None, None))?; + Ok(()) + } +} diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 82d2c11b2497b..637c6ef8e8e0b 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -3,7 +3,7 @@ // Local js definitions: /* global addClass, getCurrentValue, hasClass */ -/* global isHidden onEach, removeClass, updateLocalStorage */ +/* global isHidden, onEach, removeClass, updateLocalStorage */ if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position) { @@ -105,9 +105,9 @@ if (!DOMTokenList.prototype.remove) { sidebar.appendChild(div); } } - var themePicker = document.getElementsByClassName("theme-picker"); - if (themePicker && themePicker.length > 0) { - themePicker[0].style.display = "none"; + var themePickers = document.getElementsByClassName("theme-picker"); + if (themePickers && themePickers.length > 0) { + themePickers[0].style.display = "none"; } } @@ -123,9 +123,9 @@ if (!DOMTokenList.prototype.remove) { filler.remove(); } document.getElementsByTagName("body")[0].style.marginTop = ""; - var themePicker = document.getElementsByClassName("theme-picker"); - if (themePicker && themePicker.length > 0) { - themePicker[0].style.display = null; + var themePickers = document.getElementsByClassName("theme-picker"); + if (themePickers && themePickers.length > 0) { + themePickers[0].style.display = null; } } @@ -445,6 +445,21 @@ if (!DOMTokenList.prototype.remove) { var OUTPUT_DATA = 1; var params = getQueryStringParams(); + // Set the crate filter from saved storage, if the current page has the saved crate filter. + // + // If not, ignore the crate filter -- we want to support filtering for crates on sites like + // doc.rust-lang.org where the crates may differ from page to page while on the same domain. + var savedCrate = getCurrentValue("rustdoc-saved-filter-crate"); + if (savedCrate !== null) { + onEachLazy(document.getElementById("crate-search").getElementsByTagName("option"), + function(e) { + if (e.value === savedCrate) { + document.getElementById("crate-search").value = e.value; + return true; + } + }); + } + // Populate search bar with query string search term when provided, // but only if the input bar is empty. This avoid the obnoxious issue // where you start trying to do a search, and the index loads, and @@ -1658,9 +1673,10 @@ if (!DOMTokenList.prototype.remove) { }; search_input.onpaste = search_input.onchange; - var selectCrate = document.getElementById('crate-search'); + var selectCrate = document.getElementById("crate-search"); if (selectCrate) { selectCrate.onchange = function() { + updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value); search(undefined, true); }; } @@ -2496,7 +2512,7 @@ if (!DOMTokenList.prototype.remove) { } function addSearchOptions(crates) { - var elem = document.getElementById('crate-search'); + var elem = document.getElementById("crate-search"); if (!elem) { return; diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 59d10668f11ab..244b24af43f35 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -54,6 +54,21 @@ box-sizing: border-box; } +/* This part handles the "default" theme being used depending on the system one. */ +html { + content: ""; +} +@media (prefers-color-scheme: light) { + html { + content: "light"; + } +} +@media (prefers-color-scheme: dark) { + html { + content: "dark"; + } +} + /* General structure and fonts */ body { diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index e3927350d1104..40a6a156972f6 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -57,7 +57,7 @@ function onEachLazy(lazyArray, func, reversed) { function usableLocalStorage() { // Check if the browser supports localStorage at all: - if (typeof(Storage) === "undefined") { + if (typeof Storage === "undefined") { return false; } // Check if we can access it; this access will fail if the browser @@ -86,7 +86,7 @@ function getCurrentValue(name) { return null; } -function switchTheme(styleElem, mainStyleElem, newTheme) { +function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { var fullBasicCss = "rustdoc" + resourcesSuffix + ".css"; var fullNewTheme = newTheme + resourcesSuffix + ".css"; var newHref = mainStyleElem.href.replace(fullBasicCss, fullNewTheme); @@ -109,8 +109,19 @@ function switchTheme(styleElem, mainStyleElem, newTheme) { }); if (found === true) { styleElem.href = newHref; - updateLocalStorage("rustdoc-theme", newTheme); + // If this new value comes from a system setting or from the previously saved theme, no + // need to save it. + if (saveTheme === true) { + updateLocalStorage("rustdoc-theme", newTheme); + } } } -switchTheme(currentTheme, mainTheme, getCurrentValue("rustdoc-theme") || "light"); +function getSystemValue() { + var property = getComputedStyle(document.documentElement).getPropertyValue('content'); + return property.replace(/\"\'/g, ""); +} + +switchTheme(currentTheme, mainTheme, + getCurrentValue("rustdoc-theme") || getSystemValue() || "light", + false); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e30b35937db9f..dfa0db0d23b74 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -46,7 +46,7 @@ use std::panic; use std::process; use rustc::session::{early_warn, early_error}; -use rustc::session::config::{ErrorOutputType, RustcOptGroup}; +use rustc::session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; #[macro_use] mod externalfiles; @@ -67,6 +67,7 @@ pub mod html { crate mod render; crate mod static_files; crate mod toc; + crate mod sources; } mod markdown; mod passes; @@ -132,6 +133,7 @@ fn opts() -> Vec { stable("crate-name", |o| { o.optopt("", "crate-name", "specify the name of this crate", "NAME") }), + make_crate_type_option(), stable("L", |o| { o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") @@ -240,9 +242,6 @@ fn opts() -> Vec { unstable("crate-version", |o| { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), - unstable("linker", |o| { - o.optopt("", "linker", "linker used for building executable test code", "PATH") - }), unstable("sort-modules-by-appearance", |o| { o.optflag("", "sort-modules-by-appearance", "sort modules by where they appear in the \ program, rather than alphabetically") diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index eaaae3261c728..a30fc05f36acd 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -142,11 +142,8 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { let mut opts = TestOptions::default(); opts.no_crate_inject = true; opts.display_warnings = options.display_warnings; - let mut collector = Collector::new(options.input.display().to_string(), options.cfgs, - options.libs, options.codegen_options, options.externs, - true, opts, options.maybe_sysroot, None, - Some(options.input), - options.linker, options.edition, options.persist_doctests); + let mut collector = Collector::new(options.input.display().to_string(), options.clone(), + true, opts, None, Some(options.input)); collector.set_position(DUMMY_SP); let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); @@ -154,6 +151,6 @@ pub fn test(mut options: Options, diag: &errors::Handler) -> i32 { options.test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&options.test_args, collector.tests, - testing::Options::new().display_output(options.display_warnings)); + Some(testing::Options::new().display_output(options.display_warnings))); 0 } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 357e17d2d1bc4..5c4159433c7b2 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -32,27 +32,39 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { dox[code_block.code].to_owned(), ); - let has_errors = { - let mut has_errors = false; + let validation_status = { + let mut has_syntax_errors = false; + let mut only_whitespace = true; + // even if there is a syntax error, we need to run the lexer over the whole file let mut lexer = Lexer::new(&sess, source_file, None); loop { match lexer.next_token().kind { token::Eof => break, - token::Unknown(..) => has_errors = true, - _ => (), + token::Whitespace => (), + token::Unknown(..) => has_syntax_errors = true, + _ => only_whitespace = false, } } - has_errors + + if has_syntax_errors { + Some(CodeBlockInvalid::SyntaxError) + } else if only_whitespace { + Some(CodeBlockInvalid::Empty) + } else { + None + } }; - if has_errors { + if let Some(code_block_invalid) = validation_status { let mut diag = if let Some(sp) = super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) { - let mut diag = self - .cx - .sess() - .struct_span_warn(sp, "could not parse code block as Rust code"); + let warning_message = match code_block_invalid { + CodeBlockInvalid::SyntaxError => "could not parse code block as Rust code", + CodeBlockInvalid::Empty => "Rust code block is empty", + }; + + let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); if code_block.syntax.is_none() && code_block.is_fenced { let sp = sp.from_inner(InnerSpan::new(0, 3)); @@ -96,3 +108,8 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { self.fold_item_recur(item) } } + +enum CodeBlockInvalid { + SyntaxError, + Empty, +} diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 83a8d3fc10999..adcc9930b6c33 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -2,10 +2,7 @@ use rustc_data_structures::sync::Lrc; use rustc_interface::interface; use rustc::hir; use rustc::hir::intravisit; -use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::{self, config, DiagnosticOutput}; -use rustc::session::config::{OutputType, OutputTypes, Externs, CodegenOptions}; -use rustc::session::search_paths::SearchPath; use rustc::util::common::ErrorReported; use syntax::ast; use syntax::with_globals; @@ -13,13 +10,11 @@ use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; use std::env; -use std::io::prelude::*; -use std::io; -use std::panic::{self, AssertUnwindSafe}; +use std::io::{self, Write}; +use std::panic; use std::path::PathBuf; -use std::process::{self, Command}; +use std::process::{self, Command, Stdio}; use std::str; -use std::sync::{Arc, Mutex}; use syntax::symbol::sym; use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; use tempfile::Builder as TempFileBuilder; @@ -43,10 +38,16 @@ pub struct TestOptions { pub fn run(options: Options) -> i32 { let input = config::Input::File(options.input.clone()); + let crate_types = if options.proc_macro_crate { + vec![config::CrateType::ProcMacro] + } else { + vec![config::CrateType::Dylib] + }; + let sessopts = config::Options { maybe_sysroot: options.maybe_sysroot.clone(), search_paths: options.libs.clone(), - crate_types: vec![config::CrateType::Dylib], + crate_types, cg: options.codegen_options.clone(), externs: options.externs.clone(), unstable_features: UnstableFeatures::from_environment(), @@ -83,18 +84,11 @@ pub fn run(options: Options) -> i32 { opts.display_warnings |= options.display_warnings; let mut collector = Collector::new( compiler.crate_name()?.peek().to_string(), - options.cfgs, - options.libs, - options.codegen_options, - options.externs, + options, false, opts, - options.maybe_sysroot, Some(compiler.source_map().clone()), None, - options.linker, - options.edition, - options.persist_doctests, ); let mut global_ctxt = compiler.global_ctxt()?.take(); @@ -120,7 +114,7 @@ pub fn run(options: Options) -> i32 { testing::test_main( &test_args, tests, - testing::Options::new().display_output(display_warnings) + Some(testing::Options::new().display_output(display_warnings)) ); 0 @@ -183,20 +177,14 @@ fn run_test( cratename: &str, filename: &FileName, line: usize, - cfgs: Vec, - libs: Vec, - cg: CodegenOptions, - externs: Externs, + options: Options, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option, - linker: Option, edition: Edition, - persist_doctests: Option, ) -> Result<(), TestFailure> { let (test, line_offset) = match panic::catch_unwind(|| { make_test(test, Some(cratename), as_test_harness, opts, edition) @@ -217,61 +205,6 @@ fn run_test( _ => PathBuf::from(r"doctest.rs"), }; - let input = config::Input::Str { - name: FileName::DocTest(path, line as isize - line_offset as isize), - input: test, - }; - let outputs = OutputTypes::new(&[(OutputType::Exe, None)]); - - let sessopts = config::Options { - maybe_sysroot, - search_paths: libs, - crate_types: vec![config::CrateType::Executable], - output_types: outputs, - externs, - cg: config::CodegenOptions { - linker, - ..cg - }, - test: as_test_harness, - unstable_features: UnstableFeatures::from_environment(), - debugging_opts: config::DebuggingOptions { - ..config::basic_debugging_options() - }, - edition, - ..config::Options::default() - }; - - // Shuffle around a few input and output handles here. We're going to pass - // an explicit handle into rustc to collect output messages, but we also - // want to catch the error message that rustc prints when it fails. - // - // We take our thread-local stderr (likely set by the test runner) and replace - // it with a sink that is also passed to rustc itself. When this function - // returns the output of the sink is copied onto the output of our own thread. - // - // The basic idea is to not use a default Handler for rustc, and then also - // not print things by default to the actual stderr. - struct Sink(Arc>>); - impl Write for Sink { - fn write(&mut self, data: &[u8]) -> io::Result { - Write::write(&mut *self.0.lock().unwrap(), data) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - struct Bomb(Arc>>, Option>); - impl Drop for Bomb { - fn drop(&mut self) { - let mut old = self.1.take().unwrap(); - let _ = old.write_all(&self.0.lock().unwrap()); - io::set_panic(Some(old)); - } - } - let data = Arc::new(Mutex::new(Vec::new())); - - let old = io::set_panic(Some(box Sink(data.clone()))); - let _bomb = Bomb(data.clone(), Some(old.unwrap_or(box io::stdout()))); - enum DirState { Temp(tempfile::TempDir), Perm(PathBuf), @@ -286,7 +219,7 @@ fn run_test( } } - let outdir = if let Some(mut path) = persist_doctests { + let outdir = if let Some(mut path) = options.persist_doctests { path.push(format!("{}_{}", filename .to_string() @@ -308,41 +241,63 @@ fn run_test( }; let output_file = outdir.path().join("rust_out"); - let config = interface::Config { - opts: sessopts, - crate_cfg: config::parse_cfgspecs(cfgs), - input, - input_path: None, - output_file: Some(output_file.clone()), - output_dir: None, - file_loader: None, - diagnostic_output: DiagnosticOutput::Raw(box Sink(data.clone())), - stderr: Some(data.clone()), - crate_name: None, - lint_caps: Default::default(), - }; + let mut compiler = Command::new(std::env::current_exe().unwrap().with_file_name("rustc")); + compiler.arg("--crate-type").arg("bin"); + for cfg in &options.cfgs { + compiler.arg("--cfg").arg(&cfg); + } + if let Some(sysroot) = options.maybe_sysroot { + compiler.arg("--sysroot").arg(sysroot); + } + compiler.arg("--edition").arg(&edition.to_string()); + compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path); + compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", + format!("{}", line as isize - line_offset as isize)); + compiler.arg("-o").arg(&output_file); + if as_test_harness { + compiler.arg("--test"); + } + for lib_str in &options.lib_strs { + compiler.arg("-L").arg(&lib_str); + } + for extern_str in &options.extern_strs { + compiler.arg("--extern").arg(&extern_str); + } + compiler.arg("-Ccodegen-units=1"); + for codegen_options_str in &options.codegen_options_strs { + compiler.arg("-C").arg(&codegen_options_str); + } + if no_run { + compiler.arg("--emit=metadata"); + } - let compile_result = panic::catch_unwind(AssertUnwindSafe(|| { - interface::run_compiler(config, |compiler| { - if no_run { - compiler.global_ctxt().and_then(|global_ctxt| global_ctxt.take().enter(|tcx| { - tcx.analysis(LOCAL_CRATE) - })).ok(); - } else { - compiler.compile().ok(); - }; - compiler.session().compile_status() - }) - })).map_err(|_| ()).and_then(|s| s.map_err(|_| ())); + compiler.arg("-"); + compiler.stdin(Stdio::piped()); + compiler.stderr(Stdio::piped()); + + let mut child = compiler.spawn().expect("Failed to spawn rustc process"); + { + let stdin = child.stdin.as_mut().expect("Failed to open stdin"); + stdin.write_all(test.as_bytes()).expect("could write out test sources"); + } + let output = child.wait_with_output().expect("Failed to read stdout"); + + struct Bomb<'a>(&'a str); + impl Drop for Bomb<'_> { + fn drop(&mut self) { + eprint!("{}",self.0); + } + } - match (compile_result, compile_fail) { - (Ok(()), true) => { + let out = str::from_utf8(&output.stderr).unwrap(); + let _bomb = Bomb(&out); + match (output.status.success(), compile_fail) { + (true, true) => { return Err(TestFailure::UnexpectedCompilePass); } - (Ok(()), false) => {} - (Err(_), true) => { + (true, false) => {} + (false, true) => { if !error_codes.is_empty() { - let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap(); error_codes.retain(|err| !out.contains(err)); if !error_codes.is_empty() { @@ -350,7 +305,7 @@ fn run_test( } } } - (Err(_), false) => { + (false, false) => { return Err(TestFailure::CompileError); } } @@ -427,7 +382,7 @@ pub fn make_test(s: &str, // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); @@ -646,45 +601,28 @@ pub struct Collector { // the `names` vector of that test will be `["Title", "Subtitle"]`. names: Vec, - cfgs: Vec, - libs: Vec, - cg: CodegenOptions, - externs: Externs, + options: Options, use_headers: bool, cratename: String, opts: TestOptions, - maybe_sysroot: Option, position: Span, source_map: Option>, filename: Option, - linker: Option, - edition: Edition, - persist_doctests: Option, } impl Collector { - pub fn new(cratename: String, cfgs: Vec, libs: Vec, cg: CodegenOptions, - externs: Externs, use_headers: bool, opts: TestOptions, - maybe_sysroot: Option, source_map: Option>, - filename: Option, linker: Option, edition: Edition, - persist_doctests: Option) -> Collector { + pub fn new(cratename: String, options: Options, use_headers: bool, opts: TestOptions, + source_map: Option>, filename: Option,) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), - cfgs, - libs, - cg, - externs, + options, use_headers, cratename, opts, - maybe_sysroot, position: DUMMY_SP, source_map, filename, - linker, - edition, - persist_doctests, } } @@ -719,16 +657,10 @@ impl Tester for Collector { fn add_test(&mut self, test: String, config: LangString, line: usize) { let filename = self.get_filename(); let name = self.generate_name(line, &filename); - let cfgs = self.cfgs.clone(); - let libs = self.libs.clone(); - let cg = self.cg.clone(); - let externs = self.externs.clone(); let cratename = self.cratename.to_string(); let opts = self.opts.clone(); - let maybe_sysroot = self.maybe_sysroot.clone(); - let linker = self.linker.clone(); - let edition = config.edition.unwrap_or(self.edition); - let persist_doctests = self.persist_doctests.clone(); + let edition = config.edition.unwrap_or(self.options.edition.clone()); + let options = self.options.clone(); debug!("creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { @@ -745,20 +677,14 @@ impl Tester for Collector { &cratename, &filename, line, - cfgs, - libs, - cg, - externs, + options, config.should_panic, config.no_run, config.test_harness, config.compile_fail, config.error_codes, &opts, - maybe_sysroot, - linker, edition, - persist_doctests ); if let Err(err) = res { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 903ed3aae1470..ee330cb32111e 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -41,7 +41,7 @@ fn def_id_to_path( // framework from syntax?. pub struct RustdocVisitor<'a, 'tcx> { - cx: &'a core::DocContext<'tcx>, + cx: &'a mut core::DocContext<'tcx>, view_item_stack: FxHashSet, inlining: bool, /// Are the current module and all of its parents public? @@ -51,7 +51,7 @@ pub struct RustdocVisitor<'a, 'tcx> { impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn new( - cx: &'a core::DocContext<'tcx> + cx: &'a mut core::DocContext<'tcx> ) -> RustdocVisitor<'a, 'tcx> { // If the root is re-exported, terminate all recursion. let mut stack = FxHashSet::default(); @@ -84,7 +84,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ); module.is_crate = true; - self.cx.renderinfo.borrow_mut().exact_paths = self.exact_paths; + self.cx.renderinfo.get_mut().exact_paths = self.exact_paths; module } @@ -292,7 +292,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { Res::Def(DefKind::ForeignTy, did) | Res::Def(DefKind::TyAlias, did) if !self_is_hidden => { self.cx.renderinfo - .borrow_mut() + .get_mut() .access_levels.map .insert(did, AccessLevel::Public); }, diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 2547e3a06e9ef..b229b5f6884d8 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -1,12 +1,10 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; -use rustc::ty::Visibility; +use rustc::ty::{TyCtxt, Visibility}; use rustc::util::nodemap::FxHashSet; use syntax::symbol::sym; -use std::cell::RefMut; - use crate::clean::{AttributesExt, NestedAttributesExt}; // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses @@ -14,9 +12,9 @@ use crate::clean::{AttributesExt, NestedAttributesExt}; /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes /// specific rustdoc annotations into account (i.e., `doc(hidden)`) pub struct LibEmbargoVisitor<'a, 'tcx> { - cx: &'a crate::core::DocContext<'tcx>, + tcx: TyCtxt<'tcx>, // Accessibility levels for reachable nodes - access_levels: RefMut<'a, AccessLevels>, + access_levels: &'a mut AccessLevels, // Previous accessibility level, None means unreachable prev_level: Option, // Keeps track of already visited modules, in case a module re-exports its parent @@ -25,13 +23,13 @@ pub struct LibEmbargoVisitor<'a, 'tcx> { impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { pub fn new( - cx: &'a crate::core::DocContext<'tcx> + cx: &'a mut crate::core::DocContext<'tcx> ) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { - cx, - access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels), + tcx: cx.tcx, + access_levels: &mut cx.renderinfo.get_mut().access_levels, prev_level: Some(AccessLevel::Public), - visited_mods: FxHashSet::default() + visited_mods: FxHashSet::default(), } } @@ -43,7 +41,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); + let is_hidden = self.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow @@ -60,9 +58,9 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { return; } - for item in self.cx.tcx.item_children(def_id).iter() { + for item in self.tcx.item_children(def_id).iter() { if let Some(def_id) = item.res.opt_def_id() { - if self.cx.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || + if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index) || item.vis == Visibility::Public { self.visit_item(item.res); } @@ -72,7 +70,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { fn visit_item(&mut self, res: Res) { let def_id = res.def_id(); - let vis = self.cx.tcx.visibility(def_id); + let vis = self.tcx.visibility(def_id); let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index bb77a5bdea493..157faa0af9bca 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -70,11 +70,6 @@ llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] -# An off-by-default feature which enables a linux-syscall-like ABI for libstd to -# interoperate with the host environment. Currently not well documented and -# requires rebuilding the standard library to use it. -wasm_syscall = [] - # Enable std_detect default features for stdarch/crates/std_detect: # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = [] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index f649170c40372..795830a52c545 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -236,7 +236,7 @@ impl f32 { /// let b = 60.0_f32; /// /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -318,7 +318,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.powi(2) - x*x).abs(); + /// let abs_difference = (x.powi(2) - (x * x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -336,7 +336,7 @@ impl f32 { /// use std::f32; /// /// let x = 2.0_f32; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -600,7 +600,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI/2.0; + /// let x = f32::consts::FRAC_PI_2; /// /// let abs_difference = (x.sin() - 1.0).abs(); /// @@ -623,7 +623,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = 2.0*f32::consts::PI; + /// let x = 2.0 * f32::consts::PI; /// /// let abs_difference = (x.cos() - 1.0).abs(); /// @@ -646,7 +646,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI / 4.0; + /// let x = f32::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -666,10 +666,10 @@ impl f32 { /// ``` /// use std::f32; /// - /// let f = f32::consts::PI / 2.0; + /// let f = f32::consts::FRAC_PI_2; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f32::consts::PI / 2.0).abs(); + /// let abs_difference = (f.sin().asin() - f32::consts::FRAC_PI_2).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -688,10 +688,10 @@ impl f32 { /// ``` /// use std::f32; /// - /// let f = f32::consts::PI / 4.0; + /// let f = f32::consts::FRAC_PI_4; /// /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f32::consts::PI / 4.0).abs(); + /// let abs_difference = (f.cos().acos() - f32::consts::FRAC_PI_4).abs(); /// /// assert!(abs_difference <= f32::EPSILON); /// ``` @@ -734,7 +734,6 @@ impl f32 { /// ``` /// use std::f32; /// - /// let pi = f32::consts::PI; /// // Positive angles measured counter-clockwise /// // from positive x axis /// // -pi/4 radians (45 deg clockwise) @@ -745,8 +744,8 @@ impl f32 { /// let x2 = -3.0f32; /// let y2 = 3.0f32; /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// let abs_difference_1 = (y1.atan2(x1) - (-f32::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * f32::consts::FRAC_PI_4)).abs(); /// /// assert!(abs_difference_1 <= f32::EPSILON); /// assert!(abs_difference_2 <= f32::EPSILON); @@ -765,7 +764,7 @@ impl f32 { /// ``` /// use std::f32; /// - /// let x = f32::consts::PI/4.0; + /// let x = f32::consts::FRAC_PI_4; /// let f = x.sin_cos(); /// /// let abs_difference_0 = (f.0 - x.sin()).abs(); @@ -834,7 +833,7 @@ impl f32 { /// /// let f = x.sinh(); /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); + /// let g = ((e * e) - 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -856,7 +855,7 @@ impl f32 { /// let x = 1.0f32; /// let f = x.cosh(); /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); + /// let g = ((e * e) + 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// // Same result @@ -880,7 +879,7 @@ impl f32 { /// /// let f = x.tanh(); /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference <= f32::EPSILON); @@ -911,7 +910,7 @@ impl f32 { if self == NEG_INFINITY { NEG_INFINITY } else { - (self + ((self * self) + 1.0).sqrt()).ln() + (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) } } @@ -932,9 +931,10 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f32 { - match self { - x if x < 1.0 => crate::f32::NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), + if self < 1.0 { + crate::f32::NAN + } else { + (self + ((self * self) - 1.0).sqrt()).ln() } } @@ -1488,6 +1488,7 @@ mod tests { assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); + assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index f61630997dcdb..44d25f1b47657 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -212,7 +212,7 @@ impl f64 { /// let b = 60.0_f64; /// /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); + /// let abs_difference = (m.mul_add(x, b) - ((m * x) + b)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -244,7 +244,7 @@ impl f64 { pub fn div_euclid(self, rhs: f64) -> f64 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { - return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 }; } q } @@ -291,7 +291,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.powi(2) - x*x).abs(); + /// let abs_difference = (x.powi(2) - (x * x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -307,7 +307,7 @@ impl f64 { /// /// ``` /// let x = 2.0_f64; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); + /// let abs_difference = (x.powf(2.0) - (x * x)).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -437,9 +437,9 @@ impl f64 { pub fn log2(self) -> f64 { self.log_wrapper(|n| { #[cfg(target_os = "android")] - return crate::sys::android::log2f64(n); + return crate::sys::android::log2f64(n); #[cfg(not(target_os = "android"))] - return unsafe { intrinsics::log2f64(n) }; + return unsafe { intrinsics::log2f64(n) }; }) } @@ -481,16 +481,16 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] #[rustc_deprecated(since = "1.10.0", - reason = "you probably meant `(self - other).abs()`: \ + reason = "you probably meant `(self - other).abs()`: \ this operation is `(self - other).max(0.0)` \ except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ filing an issue describing your use-case too).")] - pub fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } + pub fn abs_sub(self, other: f64) -> f64 { + unsafe { cmath::fdim(self, other) } + } /// Takes the cubic root of a number. /// @@ -537,7 +537,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/2.0; + /// let x = f64::consts::FRAC_PI_2; /// /// let abs_difference = (x.sin() - 1.0).abs(); /// @@ -556,7 +556,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = 2.0*f64::consts::PI; + /// let x = 2.0 * f64::consts::PI; /// /// let abs_difference = (x.cos() - 1.0).abs(); /// @@ -575,7 +575,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/4.0; + /// let x = f64::consts::FRAC_PI_4; /// let abs_difference = (x.tan() - 1.0).abs(); /// /// assert!(abs_difference < 1e-14); @@ -595,10 +595,10 @@ impl f64 { /// ``` /// use std::f64; /// - /// let f = f64::consts::PI / 2.0; + /// let f = f64::consts::FRAC_PI_2; /// /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); + /// let abs_difference = (f.sin().asin() - f64::consts::FRAC_PI_2).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -617,10 +617,10 @@ impl f64 { /// ``` /// use std::f64; /// - /// let f = f64::consts::PI / 4.0; + /// let f = f64::consts::FRAC_PI_4; /// /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); + /// let abs_difference = (f.cos().acos() - f64::consts::FRAC_PI_4).abs(); /// /// assert!(abs_difference < 1e-10); /// ``` @@ -661,7 +661,6 @@ impl f64 { /// ``` /// use std::f64; /// - /// let pi = f64::consts::PI; /// // Positive angles measured counter-clockwise /// // from positive x axis /// // -pi/4 radians (45 deg clockwise) @@ -672,8 +671,8 @@ impl f64 { /// let x2 = -3.0_f64; /// let y2 = 3.0_f64; /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); + /// let abs_difference_1 = (y1.atan2(x1) - (-f64::consts::FRAC_PI_4)).abs(); + /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * f64::consts::FRAC_PI_4)).abs(); /// /// assert!(abs_difference_1 < 1e-10); /// assert!(abs_difference_2 < 1e-10); @@ -692,7 +691,7 @@ impl f64 { /// ``` /// use std::f64; /// - /// let x = f64::consts::PI/4.0; + /// let x = f64::consts::FRAC_PI_4; /// let f = x.sin_cos(); /// /// let abs_difference_0 = (f.0 - x.sin()).abs(); @@ -759,7 +758,7 @@ impl f64 { /// /// let f = x.sinh(); /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); + /// let g = ((e * e) - 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference < 1e-10); @@ -781,7 +780,7 @@ impl f64 { /// let x = 1.0_f64; /// let f = x.cosh(); /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); + /// let g = ((e * e) + 1.0) / (2.0 * e); /// let abs_difference = (f - g).abs(); /// /// // Same result @@ -805,7 +804,7 @@ impl f64 { /// /// let f = x.tanh(); /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); + /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2)); /// let abs_difference = (f - g).abs(); /// /// assert!(abs_difference < 1.0e-10); @@ -834,7 +833,7 @@ impl f64 { if self == NEG_INFINITY { NEG_INFINITY } else { - (self + ((self * self) + 1.0).sqrt()).ln() + (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) } } @@ -853,9 +852,10 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn acosh(self) -> f64 { - match self { - x if x < 1.0 => NAN, - x => (x + ((x * x) - 1.0).sqrt()).ln(), + if self < 1.0 { + NAN + } else { + (self + ((self * self) - 1.0).sqrt()).ln() } } @@ -1188,7 +1188,7 @@ mod tests { assert_eq!((-0f64).abs(), 0f64); assert_eq!((-1f64).abs(), 1f64); assert_eq!(NEG_INFINITY.abs(), INFINITY); - assert_eq!((1f64/NEG_INFINITY).abs(), 0f64); + assert_eq!((1f64 / NEG_INFINITY).abs(), 0f64); assert!(NAN.abs().is_nan()); } @@ -1200,7 +1200,7 @@ mod tests { assert_eq!((-0f64).signum(), -1f64); assert_eq!((-1f64).signum(), -1f64); assert_eq!(NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64/NEG_INFINITY).signum(), -1f64); + assert_eq!((1f64 / NEG_INFINITY).signum(), -1f64); assert!(NAN.signum().is_nan()); } @@ -1212,7 +1212,7 @@ mod tests { assert!(!(-0f64).is_sign_positive()); assert!(!(-1f64).is_sign_positive()); assert!(!NEG_INFINITY.is_sign_positive()); - assert!(!(1f64/NEG_INFINITY).is_sign_positive()); + assert!(!(1f64 / NEG_INFINITY).is_sign_positive()); assert!(NAN.is_sign_positive()); assert!(!(-NAN).is_sign_positive()); } @@ -1225,7 +1225,7 @@ mod tests { assert!((-0f64).is_sign_negative()); assert!((-1f64).is_sign_negative()); assert!(NEG_INFINITY.is_sign_negative()); - assert!((1f64/NEG_INFINITY).is_sign_negative()); + assert!((1f64 / NEG_INFINITY).is_sign_negative()); assert!(!NAN.is_sign_negative()); assert!((-NAN).is_sign_negative()); } @@ -1434,6 +1434,8 @@ mod tests { assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); + assert!((-0.0f64).asinh().is_sign_negative()); + // issue 63271 assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 512839a12c0e4..65f4e0cafe09e 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -572,8 +572,8 @@ impl CString { /// use std::ffi::{CString, CStr}; /// /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); - /// let c_str = c_string.as_c_str(); - /// assert_eq!(c_str, + /// let cstr = c_string.as_c_str(); + /// assert_eq!(cstr, /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); /// ``` #[inline] @@ -994,8 +994,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"hello"); - /// assert!(c_str.is_err()); + /// let cstr = CStr::from_bytes_with_nul(b"hello"); + /// assert!(cstr.is_err()); /// ``` /// /// Creating a `CStr` with an interior nul byte is an error: @@ -1003,8 +1003,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"he\0llo\0"); - /// assert!(c_str.is_err()); + /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); + /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) @@ -1111,8 +1111,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_bytes(), b"foo"); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_bytes(), b"foo"); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1137,8 +1137,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0"); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1164,8 +1164,8 @@ impl CStr { /// ``` /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_str(), Ok("foo")); + /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); + /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] pub fn to_str(&self) -> Result<&str, str::Utf8Error> { @@ -1205,9 +1205,9 @@ impl CStr { /// use std::borrow::Cow; /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello World\0") + /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0") /// .expect("CStr::from_bytes_with_nul failed"); - /// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World")); + /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World")); /// ``` /// /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: @@ -1216,10 +1216,10 @@ impl CStr { /// use std::borrow::Cow; /// use std::ffi::CStr; /// - /// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") + /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") /// .expect("CStr::from_bytes_with_nul failed"); /// assert_eq!( - /// c_str.to_string_lossy(), + /// cstr.to_string_lossy(), /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 1f384cbada3da..6cf062d4f30c0 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -233,7 +233,7 @@ impl OsString { /// ``` /// use std::ffi::OsString; /// - /// let mut os_string = OsString::with_capacity(10); + /// let os_string = OsString::with_capacity(10); /// assert!(os_string.capacity() >= 10); /// ``` #[stable(feature = "osstring_simple_functions", since = "1.9.0")] @@ -616,7 +616,7 @@ impl OsStr { /// Note that this does **not** return the number of bytes in the string in /// OS string form. /// - /// The length returned is that of the underlying storage used by `OsStr`; + /// The length returned is that of the underlying storage used by `OsStr`. /// As discussed in the [`OsString`] introduction, [`OsString`] and `OsStr` /// store strings in a form best suited for cheap inter-conversion between /// native-platform and Rust string forms, which may differ significantly diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index aaf628e6c260f..9593a1bae0a3c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -9,21 +9,21 @@ use crate::io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom, IoSliceMut}; use crate::memchr; -/// The `BufReader` struct adds buffering to any reader. +/// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. /// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader` performs large, infrequent reads on +/// results in a system call. A `BufReader` performs large, infrequent reads on /// the underlying [`Read`] and maintains an in-memory buffer of the results. /// -/// `BufReader` can improve the speed of programs that make *small* and +/// `BufReader` can improve the speed of programs that make *small* and /// *repeated* read calls to the same file or network socket. It does not /// help when reading very large amounts at once, or reading just one or a few /// times. It also provides no advantage when reading from a source that is /// already in memory, like a `Vec`. /// -/// When the `BufReader` is dropped, the contents of its buffer will be -/// discarded. Creating multiple instances of a `BufReader` on the same +/// When the `BufReader` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader` on the same /// stream can cause data loss. /// /// [`Read`]: ../../std/io/trait.Read.html @@ -56,7 +56,7 @@ pub struct BufReader { } impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB, /// but may change in the future. /// /// # Examples @@ -76,7 +76,7 @@ impl BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufReader` with the specified buffer capacity. + /// Creates a new `BufReader` with the specified buffer capacity. /// /// # Examples /// @@ -177,7 +177,7 @@ impl BufReader { &self.buf[self.pos..self.cap] } - /// Unwraps this `BufReader`, returning the underlying reader. + /// Unwraps this `BufReader`, returning the underlying reader. /// /// Note that any leftover data in the internal buffer is lost. /// @@ -304,7 +304,7 @@ impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// /// The position used for seeking with `SeekFrom::Current(_)` is the - /// position the underlying reader would be at if the `BufReader` had no + /// position the underlying reader would be at if the `BufReader` had no /// internal buffer. /// /// Seeking always discards the internal buffer, even if the seek position @@ -355,19 +355,20 @@ impl Seek for BufReader { /// It can be excessively inefficient to work directly with something that /// implements [`Write`]. For example, every call to /// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying /// writer in large, infrequent batches. /// -/// `BufWriter` can improve the speed of programs that make *small* and +/// `BufWriter` can improve the speed of programs that make *small* and /// *repeated* write calls to the same file or network socket. It does not /// help when writing very large amounts at once, or writing just one or a few /// times. It also provides no advantage when writing to a destination that is /// in memory, like a `Vec`. /// -/// When the `BufWriter` is dropped, the contents of its buffer will be written -/// out. However, any errors that happen in the process of flushing the buffer -/// when the writer is dropped will be ignored. Code that wishes to handle such -/// errors must manually call [`flush`] before the writer is dropped. +/// It is critical to call [`flush`] before `BufWriter` is dropped. Though +/// dropping will attempt to flush the the contents of the buffer, any errors +/// that happen in the process of dropping will be ignored. Calling ['flush'] +/// ensures that the buffer is empty and thus dropping will not even attempt +/// file operations. /// /// # Examples /// @@ -386,7 +387,7 @@ impl Seek for BufReader { /// /// Because we're not buffering, we write each one in turn, incurring the /// overhead of a system call per byte written. We can fix this with a -/// `BufWriter`: +/// `BufWriter`: /// /// ```no_run /// use std::io::prelude::*; @@ -398,11 +399,12 @@ impl Seek for BufReader { /// for i in 0..10 { /// stream.write(&[i+1]).unwrap(); /// } +/// stream.flush().unwrap(); /// ``` /// -/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped -/// together by the buffer, and will all be written out in one system call when -/// the `stream` is dropped. +/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped +/// together by the buffer and will all be written out in one system call when +/// the `stream` is flushed. /// /// [`Write`]: ../../std/io/trait.Write.html /// [`TcpStream::write`]: ../../std/net/struct.TcpStream.html#method.write @@ -447,7 +449,7 @@ pub struct BufWriter { pub struct IntoInnerError(W, Error); impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, + /// Creates a new `BufWriter` with a default buffer capacity. The default is currently 8 KB, /// but may change in the future. /// /// # Examples @@ -463,7 +465,7 @@ impl BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - /// Creates a new `BufWriter` with the specified buffer capacity. + /// Creates a new `BufWriter` with the specified buffer capacity. /// /// # Examples /// @@ -564,7 +566,7 @@ impl BufWriter { &self.buf } - /// Unwraps this `BufWriter`, returning the underlying writer. + /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. /// diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 85a9dea09ed0d..a8dfe924fdf06 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -681,14 +681,15 @@ mod while_keyword { } /// # break; /// } /// -/// let mut i = 0; +/// let mut i = 1; /// loop { /// println!("i is {}", i); -/// if i > 10 { +/// if i > 100 { /// break; /// } -/// i += 1; +/// i *= 2; /// } +/// assert_eq!(i, 128); /// ``` /// /// Unlike the other kinds of loops in Rust (`while`, `while let`, and `for`), loops can be used as diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index d9a3da66a6786..45816ffd229f0 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -655,7 +655,7 @@ mod prim_slice { } /// [`len`]: #method.len /// /// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `as_slice` +/// used to get a string slice under normal circumstances. Use `as_str` /// instead. #[stable(feature = "rust1", since = "1.0.0")] mod prim_str { } diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index aeff57716e86b..65ce19f2a1b3a 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -28,14 +28,14 @@ impl WaitTimeoutResult { /// once the boolean has been updated and notified. /// /// ``` - /// use std::sync::{Arc, Mutex, Condvar}; + /// use std::sync::{Arc, Condvar, Mutex}; /// use std::thread; /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); /// let pair2 = pair.clone(); /// - /// thread::spawn(move|| { + /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; /// /// // Let's wait 20 milliseconds before notifying the condvar. diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index a9711c71b7aa3..e6a742bd45d0b 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -178,23 +178,22 @@ impl Command { cvt_r(|| libc::dup2(fd, libc::STDERR_FILENO))?; } - if cfg!(not(any(target_os = "l4re"))) { + #[cfg(not(target_os = "l4re"))] + { if let Some(u) = self.get_gid() { cvt(libc::setgid(u as gid_t))?; } if let Some(u) = self.get_uid() { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. //FIXME: Redox kernel does not support setgroups yet - if cfg!(not(target_os = "redox")) { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - let _ = libc::setgroups(0, ptr::null()); - } - + #[cfg(not(target_os = "redox"))] + let _ = libc::setgroups(0, ptr::null()); cvt(libc::setuid(u as uid_t))?; } } @@ -203,7 +202,7 @@ impl Command { } // emscripten has no signal support. - #[cfg(not(any(target_os = "emscripten")))] + #[cfg(not(target_os = "emscripten"))] { use crate::mem::MaybeUninit; // Reset signal handling so the child process starts in a diff --git a/src/libstd/sys/vxworks/backtrace/mod.rs b/src/libstd/sys/vxworks/backtrace/mod.rs deleted file mode 100644 index 0887e5a4df937..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on macOS, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering thread -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on macOS. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for macOS, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not macOS, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. - -pub use self::tracing::unwind_backtrace; -pub use self::printing::{foreach_symbol_fileline, resolve_symname}; - -// tracing impls: -mod tracing; -// symbol resolvers: -mod printing; - -#[cfg(not(target_os = "emscripten"))] -pub mod gnu { - use crate::io; - use crate::fs; - - use libc::c_char; - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn get_executable_filename() -> io::Result<(Vec, fs::File)> { - use crate::env; - use crate::os::unix::ffi::OsStrExt; - - let filename = env::current_exe()?; - let file = fs::File::open(&filename)?; - let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter() - .map(|&x| x as c_char).collect(); - filename_cstr.push(0); // Null terminate - Ok((filename_cstr, file)) - } -} - -pub struct BacktraceContext; diff --git a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs b/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs deleted file mode 100644 index 202164dd3c4d7..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/dladdr.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::io; -use crate::intrinsics; -use crate::ffi::CStr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -pub fn resolve_symname(frame: Frame, - callback: F, - _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> -{ - unsafe { - let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || - info.dli_sname.is_null() { - None - } else { - CStr::from_ptr(info.dli_sname).to_str().ok() - }; - callback(symname) - } -} - -#[repr(C)] -struct Dl_info { - dli_fname: *const libc::c_char, - dli_fbase: *mut libc::c_void, - dli_sname: *const libc::c_char, - dli_saddr: *mut libc::c_void, -} - -extern { - #[ link_name = "_rtld_dladdr" ] - fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/printing/mod.rs b/src/libstd/sys/vxworks/backtrace/printing/mod.rs deleted file mode 100644 index d090caede437a..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/printing/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -mod dladdr; - -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; -use crate::io; - -#[cfg(target_os = "emscripten")] -pub use self::dladdr::resolve_symname; - -#[cfg(target_os = "emscripten")] -pub fn foreach_symbol_fileline(_: Frame, _: F, _: &BacktraceContext) -> io::Result -where - F: FnMut(&[u8], u32) -> io::Result<()> -{ - Ok(false) -} - -#[cfg(not(target_os = "emscripten"))] -pub use crate::sys_common::gnu::libbacktrace::foreach_symbol_fileline; - -#[cfg(not(target_os = "emscripten"))] -pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> -where - F: FnOnce(Option<&str>) -> io::Result<()> -{ - crate::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) - } else { - dladdr::resolve_symname(frame, callback, bc) - } - }, bc) -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs deleted file mode 100644 index a628d107ad6fb..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/backtrace_fn.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// As always - iOS on arm uses SjLj exceptions and -/// _Unwind_Backtrace is even not available there. Still, -/// backtraces could be extracted using a backtrace function, -/// which thanks god is public -/// -/// As mentioned in a huge comment block in `super::super`, backtrace -/// doesn't play well with green threads, so while it is extremely nice and -/// simple to use it should be used only on iOS devices as the only viable -/// option. - -use crate::io; -use crate::ptr; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - const FRAME_LEN: usize = 100; - assert!(FRAME_LEN >= frames.len()); - let mut raw_frames = [ptr::null_mut(); FRAME_LEN]; - let nb_frames = unsafe { - backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int) - } as usize; - for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { - *to = Frame { - exact_position: *from as *mut u8, - symbol_addr: *from as *mut u8, - inline_context: 0, - }; - } - Ok((nb_frames as usize, BacktraceContext)) -} - -extern { - fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int; -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs b/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs deleted file mode 100644 index e6379132bafbe..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/gcc_s.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::error::Error; -use crate::fmt; -use crate::io; -use crate::sys::backtrace::BacktraceContext; -use crate::sys_common::backtrace::Frame; - -use unwind as uw; - -struct Context<'a> { - idx: usize, - frames: &'a mut [Frame], -} - -#[derive(Debug)] -struct UnwindError(uw::_Unwind_Reason_Code); - -impl Error for UnwindError { - fn description(&self) -> &'static str { - "unexpected return value while unwinding" - } -} - -impl fmt::Display for UnwindError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}: {:?}", self.description(), self.0) - } -} - -#[inline(never)] // if we know this is a function call, we can skip it when - // tracing -pub fn unwind_backtrace(frames: &mut [Frame]) - -> io::Result<(usize, BacktraceContext)> -{ - let mut cx = Context { - idx: 0, - frames, - }; - let result_unwind = unsafe { - uw::_Unwind_Backtrace(trace_fn, - &mut cx as *mut Context<'_> - as *mut libc::c_void) - }; - // See libunwind:src/unwind/Backtrace.c for the return values. - // No, there is no doc. - match result_unwind { - // These return codes seem to be benign and need to be ignored for backtraces - // to show up properly on all tested platforms. - uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => { - Ok((cx.idx, BacktraceContext)) - } - _ => { - Err(io::Error::new(io::ErrorKind::Other, - UnwindError(result_unwind))) - } - } -} - -extern fn trace_fn(ctx: *mut uw::_Unwind_Context, - arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { - let cx = unsafe { &mut *(arg as *mut Context<'_>) }; - if cx.idx >= cx.frames.len() { - return uw::_URC_NORMAL_STOP; - } - - let mut ip_before_insn = 0; - let mut ip = unsafe { - uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void - }; - if !ip.is_null() && ip_before_insn == 0 { - // this is a non-signaling frame, so `ip` refers to the address - // after the calling instruction. account for that. - ip = (ip as usize - 1) as *mut _; - } - - // dladdr() on osx gets whiny when we use FindEnclosingFunction, and - // it appears to work fine without it, so we only use - // FindEnclosingFunction on non-osx platforms. In doing so, we get a - // slightly more accurate stack trace in the process. - // - // This is often because panic involves the last instruction of a - // function being "call std::rt::begin_unwind", with no ret - // instructions after it. This means that the return instruction - // pointer points *outside* of the calling function, and by - // unwinding it we go back to the original function. - let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { - ip - } else { - unsafe { uw::_Unwind_FindEnclosingFunction(ip) } - }; - - cx.frames[cx.idx] = Frame { - symbol_addr: symaddr as *mut u8, - exact_position: ip as *mut u8, - inline_context: 0, - }; - cx.idx += 1; - - uw::_URC_NO_REASON -} diff --git a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs b/src/libstd/sys/vxworks/backtrace/tracing/mod.rs deleted file mode 100644 index 11863e6454525..0000000000000 --- a/src/libstd/sys/vxworks/backtrace/tracing/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub use self::imp::*; - -#[cfg(not(all(target_os = "ios", target_arch = "arm")))] -#[path = "gcc_s.rs"] -mod imp; -#[cfg(all(target_os = "ios", target_arch = "arm"))] -#[path = "backtrace_fn.rs"] -mod imp; diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/fast_thread_local.rs index f5a2e263d25e7..2e021980778e5 100644 --- a/src/libstd/sys/vxworks/fast_thread_local.rs +++ b/src/libstd/sys/vxworks/fast_thread_local.rs @@ -1,33 +1,10 @@ +// Copyright (c) 2019 Wind River Systems, Inc. + #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "0")] -// Since what appears to be glibc 2.18 this symbol has been shipped which -// GCC and clang both use to invoke destructors in thread_local globals, so -// let's do the same! -// -// Note, however, that we run on lots older linuxes, as well as cross -// compiling from a newer linux to an older linux, so we also have a -// fallback implementation to use as well. -// -// Due to rust-lang/rust#18804, make sure this is not generic! pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use crate::mem; use crate::sys_common::thread_local::register_dtor_fallback; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } register_dtor_fallback(t, dtor); } diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs index 58af8cbe48e36..ef896f6a6e8cf 100644 --- a/src/libstd/sys/vxworks/thread.rs +++ b/src/libstd/sys/vxworks/thread.rs @@ -77,7 +77,7 @@ impl Thread { } pub fn set_name(_name: &CStr) { - assert!(false, "FIXME: set_name"); + // VxWorks does not provide a way to set the task name except at creation time } pub fn sleep(dur: Duration) { diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index f842869e08ee6..57da81b41e7ca 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -64,8 +64,24 @@ pub fn unsupported_err() -> Error { Error::new(ErrorKind::Other, "operation not supported on wasm yet") } -pub fn decode_error_kind(_code: i32) -> ErrorKind { - ErrorKind::Other +pub fn decode_error_kind(errno: i32) -> ErrorKind { + match errno as libc::c_int { + libc::ECONNREFUSED => ErrorKind::ConnectionRefused, + libc::ECONNRESET => ErrorKind::ConnectionReset, + libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, + libc::EPIPE => ErrorKind::BrokenPipe, + libc::ENOTCONN => ErrorKind::NotConnected, + libc::ECONNABORTED => ErrorKind::ConnectionAborted, + libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + libc::EADDRINUSE => ErrorKind::AddrInUse, + libc::ENOENT => ErrorKind::NotFound, + libc::EINTR => ErrorKind::Interrupted, + libc::EINVAL => ErrorKind::InvalidInput, + libc::ETIMEDOUT => ErrorKind::TimedOut, + libc::EEXIST => ErrorKind::AlreadyExists, + libc::EAGAIN => ErrorKind::WouldBlock, + _ => ErrorKind::Other, + } } // This enum is used as the storage for a bunch of types which can't actually diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index b3c77b8699563..8279e5280e924 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -1,7 +1,6 @@ use crate::ffi::OsString; use crate::marker::PhantomData; use crate::vec; -use crate::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 @@ -11,9 +10,8 @@ pub unsafe fn cleanup() { } pub fn args() -> Args { - let v = ArgsSysCall::perform(); Args { - iter: v.into_iter(), + iter: Vec::new().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 56cbafcfdb8a2..de0bb38dc319e 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -15,11 +15,6 @@ //! guaranteed to be a runtime error! use crate::os::raw::c_char; -use crate::ptr; -use crate::sys::os_str::Buf; -use crate::sys_common::{AsInner, FromInner}; -use crate::ffi::{OsString, OsStr}; -use crate::time::Duration; pub mod alloc; pub mod args; @@ -89,7 +84,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { } pub unsafe fn abort_internal() -> ! { - ExitSysCall::perform(1) + crate::arch::wasm32::unreachable() } // We don't have randomness yet, but I totally used a random number generator to @@ -100,218 +95,3 @@ 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); - crate::intrinsics::abort(); - } - } -} - -fn receive_buffer Result>(estimate: usize, mut f: F) - -> Result, 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 { - receive_buffer(1024, |buffer| -> Result { - 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 { - 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(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 5d21999a991e1..890049e8bfae5 100644 --- a/src/libstd/sys/wasm/os.rs +++ b/src/libstd/sys/wasm/os.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::io; use crate::path::{self, PathBuf}; use crate::str; -use crate::sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall}; +use crate::sys::{unsupported, Void}; pub fn errno() -> i32 { 0 @@ -73,16 +73,16 @@ pub fn env() -> Env { panic!("not supported on web assembly") } -pub fn getenv(k: &OsStr) -> io::Result> { - Ok(GetEnvSysCall::perform(k)) +pub fn getenv(_: &OsStr) -> io::Result> { + Ok(None) } -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, Some(v))) +pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot set env vars on wasm32-unknown-unknown")) } -pub fn unsetenv(k: &OsStr) -> io::Result<()> { - Ok(SetEnvSysCall::perform(k, None)) +pub fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "cannot unset env vars on wasm32-unknown-unknown")) } pub fn temp_dir() -> PathBuf { @@ -94,7 +94,9 @@ pub fn home_dir() -> Option { } pub fn exit(_code: i32) -> ! { - ExitSysCall::perform(_code as isize as usize) + unsafe { + crate::arch::wasm32::unreachable(); + } } pub fn getpid() -> u32 { diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs index b8899a9c84746..5a4e4505e93bd 100644 --- a/src/libstd/sys/wasm/stdio.rs +++ b/src/libstd/sys/wasm/stdio.rs @@ -1,5 +1,4 @@ use crate::io; -use crate::sys::{ReadSysCall, WriteSysCall}; pub struct Stdin; pub struct Stdout; @@ -12,8 +11,8 @@ impl Stdin { } impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - Ok(ReadSysCall::perform(0, buf)) + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) } } @@ -25,7 +24,6 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - WriteSysCall::perform(1, buf); Ok(buf.len()) } @@ -42,7 +40,6 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - WriteSysCall::perform(2, buf); Ok(buf.len()) } @@ -57,10 +54,6 @@ pub fn is_ebadf(_err: &io::Error) -> bool { true } -pub fn panic_output() -> Option { - if cfg!(feature = "wasm_syscall") { - Stderr::new().ok() - } else { - None - } +pub fn panic_output() -> Option> { + None } diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs index 3f71461eea487..dd9ad3760b050 100644 --- a/src/libstd/sys/wasm/time.rs +++ b/src/libstd/sys/wasm/time.rs @@ -1,5 +1,4 @@ use crate::time::Duration; -use crate::sys::{TimeSysCall, TimeClock}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Duration); @@ -11,7 +10,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0)); impl Instant { pub fn now() -> Instant { - Instant(TimeSysCall::perform(TimeClock::Monotonic)) + panic!("time not implemented on wasm32-unknown-unknown") } pub const fn zero() -> Instant { @@ -37,7 +36,7 @@ impl Instant { impl SystemTime { pub fn now() -> SystemTime { - SystemTime(TimeSysCall::perform(TimeClock::System)) + panic!("time not implemented on wasm32-unknown-unknown") } pub fn sub_time(&self, other: &SystemTime) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 50e428ea0cca6..6be00bcef45c0 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1789,11 +1789,11 @@ pub struct InlineAsm { pub dialect: AsmDialect, } -/// An argument in a function header. +/// A parameter in a function header. /// /// E.g., `bar: usize` as in `fn foo(bar: usize)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct Arg { +pub struct Param { pub attrs: ThinVec, pub ty: P, pub pat: P, @@ -1816,7 +1816,7 @@ pub enum SelfKind { pub type ExplicitSelf = Spanned; -impl Arg { +impl Param { pub fn to_self(&self) -> Option { if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.node { if ident.name == kw::SelfLower { @@ -1843,14 +1843,14 @@ impl Arg { } } - pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Arg { + pub fn from_self(attrs: ThinVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::ImplicitSelf, span, }); - let arg = |mutbl, ty| Arg { + let param = |mutbl, ty| Param { attrs, pat: P(Pat { id: DUMMY_NODE_ID, @@ -1862,9 +1862,9 @@ impl Arg { id: DUMMY_NODE_ID, }; match eself.node { - SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty), - SelfKind::Value(mutbl) => arg(mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => arg( + SelfKind::Explicit(ty, mutbl) => param(mutbl, ty), + SelfKind::Value(mutbl) => param(mutbl, infer_ty), + SelfKind::Region(lt, mutbl) => param( Mutability::Immutable, P(Ty { id: DUMMY_NODE_ID, @@ -1887,17 +1887,17 @@ impl Arg { /// E.g., `fn foo(bar: baz)`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FnDecl { - pub inputs: Vec, + pub inputs: Vec, pub output: FunctionRetTy, pub c_variadic: bool, } impl FnDecl { pub fn get_self(&self) -> Option { - self.inputs.get(0).and_then(Arg::to_self) + self.inputs.get(0).and_then(Param::to_self) } pub fn has_self(&self) -> bool { - self.inputs.get(0).map(Arg::is_self).unwrap_or(false) + self.inputs.get(0).map(Param::is_self).unwrap_or(false) } } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index bcf03b5237a8d..0e5cfa73a9e3a 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -714,7 +714,7 @@ macro_rules! derive_has_attrs { derive_has_attrs! { Item, Expr, Local, ast::ForeignItem, ast::StructField, ast::ImplItem, ast::TraitItem, ast::Arm, - ast::Field, ast::FieldPat, ast::Variant, ast::Arg + ast::Field, ast::FieldPat, ast::Variant, ast::Param } pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) -> ast::Crate { diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs deleted file mode 100644 index 53f37bb10bdc0..0000000000000 --- a/src/libsyntax/diagnostics/metadata.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! This module contains utilities for outputting metadata for diagnostic errors. -//! -//! Each set of errors is mapped to a metadata file by a name, which is -//! currently always a crate name. - -use std::collections::BTreeMap; -use std::env; -use std::fs::{remove_file, create_dir_all, File}; -use std::io::Write; -use std::path::PathBuf; -use std::error::Error; -use rustc_serialize::json::as_json; - -use syntax_pos::{Span, FileName}; - -use crate::ext::base::ExtCtxt; -use crate::diagnostics::plugin::{ErrorMap, ErrorInfo}; - -/// JSON encodable/decodable version of `ErrorInfo`. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorMetadata { - pub description: Option, - pub use_site: Option -} - -/// Mapping from error codes to metadata that can be (de)serialized. -pub type ErrorMetadataMap = BTreeMap; - -/// JSON encodable error location type with filename and line number. -#[derive(PartialEq, RustcDecodable, RustcEncodable)] -pub struct ErrorLocation { - pub filename: FileName, - pub line: usize -} - -impl ErrorLocation { - /// Creates an error location from a span. - pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation { - let loc = ecx.source_map().lookup_char_pos(sp.lo()); - ErrorLocation { - filename: loc.file.name.clone(), - line: loc.line - } - } -} - -/// Gets the directory where metadata for a given `prefix` should be stored. -/// -/// See `output_metadata`. -pub fn get_metadata_dir(prefix: &str) -> PathBuf { - env::var_os("RUSTC_ERROR_METADATA_DST") - .map(PathBuf::from) - .expect("env var `RUSTC_ERROR_METADATA_DST` isn't set") - .join(prefix) -} - -/// Map `name` to a path in the given directory: /.json -fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf { - directory.join(format!("{}.json", name)) -} - -/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`. -/// -/// For our current purposes the prefix is the target architecture and the name is a crate name. -/// If an error occurs steps will be taken to ensure that no file is created. -pub fn output_metadata(ecx: &ExtCtxt<'_>, prefix: &str, name: &str, err_map: &ErrorMap) - -> Result<(), Box> -{ - // Create the directory to place the file in. - let metadata_dir = get_metadata_dir(prefix); - create_dir_all(&metadata_dir)?; - - // Open the metadata file. - let metadata_path = get_metadata_path(metadata_dir, name); - let mut metadata_file = File::create(&metadata_path)?; - - // Construct a serializable map. - let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| { - let key = k.as_str().to_string(); - let value = ErrorMetadata { - description: description.map(|n| n.as_str().to_string()), - use_site: use_site.map(|sp| ErrorLocation::from_span(ecx, sp)) - }; - (key, value) - }).collect::(); - - // Write the data to the file, deleting it if the write fails. - let result = write!(&mut metadata_file, "{}", as_json(&json_map)); - if result.is_err() { - remove_file(&metadata_path)?; - } - Ok(result?) -} diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 9618b5acfb0f1..e9a55af52e878 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::env; use crate::ast::{self, Ident, Name}; use crate::source_map; @@ -12,8 +11,6 @@ use crate::tokenstream::{TokenTree}; use smallvec::smallvec; use syntax_pos::Span; -use crate::diagnostics::metadata::output_metadata; - pub use errors::*; // Maximum width of any line in an extended error description (inclusive). @@ -127,36 +124,13 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>, token_tree: &[TokenTree]) -> Box { assert_eq!(token_tree.len(), 3); - let (crate_name, ident) = match (&token_tree[0], &token_tree[2]) { - ( - // Crate name. - &TokenTree::Token(Token { kind: token::Ident(crate_name, _), .. }), - // DIAGNOSTICS ident. - &TokenTree::Token(Token { kind: token::Ident(name, _), span }) - ) => (crate_name, Ident::new(name, span)), + let ident = match &token_tree[2] { + // DIAGNOSTICS ident. + &TokenTree::Token(Token { kind: token::Ident(name, _), span }) + => Ident::new(name, span), _ => unreachable!() }; - // Output error metadata to `tmp/extended-errors//.json` - if let Ok(target_triple) = env::var("CFG_COMPILER_HOST_TRIPLE") { - ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { - if let Err(e) = output_metadata(ecx, - &target_triple, - &crate_name.as_str(), - diagnostics) { - ecx.span_bug(span, &format!( - "error writing metadata for triple `{}` and crate `{}`, error: {}, \ - cause: {:?}", - target_triple, crate_name, e.description(), e.source() - )); - } - }); - } else { - ecx.span_err(span, &format!( - "failed to write metadata for crate `{}` because $CFG_COMPILER_HOST_TRIPLE is not set", - crate_name)); - } - // Construct the output expression. let (count, expr) = ecx.parse_sess.registered_diagnostics.with_lock(|diagnostics| { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b0a4a6af9839c..5d68983d7cb66 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -1,16 +1,17 @@ use crate::ast::{self, NodeId, Attribute, Name, PatKind}; -use crate::attr::{HasAttrs, Stability, Deprecation}; +use crate::attr::{self, HasAttrs, Stability, Deprecation}; use crate::source_map::SourceMap; use crate::edition::Edition; use crate::ext::expand::{self, AstFragment, Invocation}; -use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency}; +use crate::ext::hygiene::{ExpnId, Transparency}; use crate::mut_visit::{self, MutVisitor}; -use crate::parse::{self, parser, DirectoryOwnership}; +use crate::parse::{self, parser, ParseSess, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; use crate::tokenstream::{self, TokenStream, TokenTree}; +use crate::visit::Visitor; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; @@ -72,6 +73,17 @@ impl Annotatable { } } + pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) { + match self { + Annotatable::Item(item) => visitor.visit_item(item), + Annotatable::TraitItem(trait_item) => visitor.visit_trait_item(trait_item), + Annotatable::ImplItem(impl_item) => visitor.visit_impl_item(impl_item), + Annotatable::ForeignItem(foreign_item) => visitor.visit_foreign_item(foreign_item), + Annotatable::Stmt(stmt) => visitor.visit_stmt(stmt), + Annotatable::Expr(expr) => visitor.visit_expr(expr), + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -549,8 +561,6 @@ pub struct SyntaxExtension { pub kind: SyntaxExtensionKind, /// Span of the macro definition. pub span: Span, - /// Hygienic properties of spans produced by this macro by default. - pub default_transparency: Transparency, /// Whitelist of unstable features that are treated as stable inside this macro. pub allow_internal_unstable: Option>, /// Suppresses the `unsafe_code` lint for code produced by this macro. @@ -572,22 +582,6 @@ pub struct SyntaxExtension { pub is_derive_copy: bool, } -impl SyntaxExtensionKind { - /// When a syntax extension is constructed, - /// its transparency can often be inferred from its kind. - fn default_transparency(&self) -> Transparency { - match self { - SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::Attr(..) | - SyntaxExtensionKind::Derive(..) | - SyntaxExtensionKind::NonMacroAttr { .. } => Transparency::Opaque, - SyntaxExtensionKind::LegacyBang(..) | - SyntaxExtensionKind::LegacyAttr(..) | - SyntaxExtensionKind::LegacyDerive(..) => Transparency::SemiTransparent, - } - } -} - impl SyntaxExtension { /// Returns which kind of macro calls this syntax extension. pub fn macro_kind(&self) -> MacroKind { @@ -606,7 +600,6 @@ impl SyntaxExtension { pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { SyntaxExtension { span: DUMMY_SP, - default_transparency: kind.default_transparency(), allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, @@ -620,6 +613,69 @@ impl SyntaxExtension { } } + /// Constructs a syntax extension with the given properties + /// and other properties converted from attributes. + pub fn new( + sess: &ParseSess, + kind: SyntaxExtensionKind, + span: Span, + helper_attrs: Vec, + edition: Edition, + name: Name, + attrs: &[ast::Attribute], + ) -> SyntaxExtension { + let allow_internal_unstable = + attr::find_by_name(attrs, sym::allow_internal_unstable).map(|attr| { + attr.meta_item_list() + .map(|list| { + list.iter() + .filter_map(|it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + sess.span_diagnostic.span_err( + it.span(), "allow internal unstable expects feature names" + ) + } + name + }) + .collect::>() + .into() + }) + .unwrap_or_else(|| { + sess.span_diagnostic.span_warn( + attr.span, + "allow_internal_unstable expects list of feature names. In the future \ + this will become a hard error. Please use `allow_internal_unstable(\ + foo, bar)` to only allow the `foo` and `bar` features", + ); + vec![sym::allow_internal_unstable_backcompat_hack].into() + }) + }); + + let mut local_inner_macros = false; + if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) { + if let Some(l) = macro_export.meta_item_list() { + local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); + } + } + + let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro); + + SyntaxExtension { + kind, + span, + allow_internal_unstable, + allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe), + local_inner_macros, + stability: attr::find_stability(&sess, attrs, span), + deprecation: attr::find_deprecation(&sess, attrs, span), + helper_attrs, + edition, + is_builtin, + is_derive_copy: is_builtin && name == sym::Copy, + } + } + pub fn dummy_bang(edition: Edition) -> SyntaxExtension { fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree]) -> Box { @@ -646,7 +702,6 @@ impl SyntaxExtension { parent, call_site, def_site: self.span, - default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), allow_internal_unsafe: self.allow_internal_unsafe, local_inner_macros: self.local_inner_macros, @@ -657,6 +712,12 @@ impl SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); +/// Result of resolving a macro invocation. +pub enum InvocationRes { + Single(Lrc), + DeriveContainer(Vec>), +} + /// Error type that denotes indeterminacy. pub struct Indeterminate; @@ -682,8 +743,9 @@ pub trait Resolver { fn resolve_imports(&mut self); - fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: ExpnId, force: bool) - -> Result>, Indeterminate>; + fn resolve_macro_invocation( + &mut self, invoc: &Invocation, eager_expansion_root: ExpnId, force: bool + ) -> Result; fn check_unused_macros(&self); @@ -759,23 +821,39 @@ impl<'a> ExtCtxt<'a> { pub fn call_site(&self) -> Span { self.current_expansion.id.expn_data().call_site } - pub fn backtrace(&self) -> SyntaxContext { - SyntaxContext::root().apply_mark(self.current_expansion.id) + + /// Equivalent of `Span::def_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_def_site_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Opaque) + } + + /// Equivalent of `Span::call_site` from the proc macro API, + /// except that the location is taken from the span passed as an argument. + pub fn with_call_site_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Transparent) + } + + /// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items). + /// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably), + /// or with `with_call_site_ctxt` (where necessary). + pub fn with_legacy_ctxt(&self, span: Span) -> Span { + span.with_ctxt_from_mark(self.current_expansion.id, Transparency::SemiTransparent) } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Option { - let mut ctxt = self.backtrace(); + let mut expn_id = self.current_expansion.id; let mut last_macro = None; loop { - let expn_data = ctxt.outer_expn_data(); + let expn_data = expn_id.expn_data(); // Stop going up the backtrace once include! is encountered if expn_data.is_root() || expn_data.kind.descr() == sym::include { break; } - ctxt = expn_data.call_site.ctxt(); + expn_id = expn_data.call_site.ctxt().outer_expn(); last_macro = Some(expn_data.call_site); } last_macro @@ -864,7 +942,7 @@ impl<'a> ExtCtxt<'a> { ast::Ident::from_str(st) } pub fn std_path(&self, components: &[Symbol]) -> Vec { - let def_site = DUMMY_SP.apply_mark(self.current_expansion.id); + let def_site = self.with_def_site_ctxt(DUMMY_SP); iter::once(Ident::new(kw::DollarCrate, def_site)) .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) .collect() @@ -908,12 +986,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns `None`. pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, - mut expr: P, + expr: P, err_msg: &str, ) -> Result<(Symbol, ast::StrStyle, Span), Option>> { - // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. - expr.span = expr.span.apply_mark(cx.current_expansion.id); - // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index e2ac4d573a1e0..e894fd17ff587 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -655,7 +655,7 @@ impl<'a> ExtCtxt<'a> { body: P) -> P { let fn_decl = self.fn_decl( - ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), + ids.iter().map(|id| self.param(span, *id, self.ty_infer(span))).collect(), ast::FunctionRetTy::Default(span)); // FIXME -- We are using `span` as the span of the `|...|` @@ -693,9 +693,9 @@ impl<'a> ExtCtxt<'a> { self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } - pub fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { + pub fn param(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Param { let arg_pat = self.pat_ident(span, ident); - ast::Arg { + ast::Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat: arg_pat, @@ -705,7 +705,7 @@ impl<'a> ExtCtxt<'a> { } // FIXME: unused `self` - pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { + pub fn fn_decl(&self, inputs: Vec, output: ast::FunctionRetTy) -> P { P(ast::FnDecl { inputs, output, @@ -731,7 +731,7 @@ impl<'a> ExtCtxt<'a> { pub fn item_fn_poly(&self, span: Span, name: Ident, - inputs: Vec , + inputs: Vec , output: P, generics: Generics, body: P) -> P { @@ -752,7 +752,7 @@ impl<'a> ExtCtxt<'a> { pub fn item_fn(&self, span: Span, name: Ident, - inputs: Vec , + inputs: Vec , output: P, body: P ) -> P { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1d52c9745529..7b4a516744642 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs}; use crate::source_map::respan; use crate::config::StripUnconfigured; use crate::ext::base::*; -use crate::ext::proc_macro::collect_derives; +use crate::ext::proc_macro::{collect_derives, MarkAttrs}; use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; use crate::ext::tt::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; @@ -305,10 +305,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { continue }; - let scope = + let eager_expansion_root = if self.monotonic { invoc.expansion_data.id } else { orig_expansion_data.id }; - let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { - Ok(ext) => ext, + let res = match self.cx.resolver.resolve_macro_invocation( + &invoc, eager_expansion_root, force + ) { + Ok(res) => res, Err(Indeterminate) => { undetermined_invocations.push(invoc); continue @@ -318,57 +320,74 @@ impl<'a, 'b> MacroExpander<'a, 'b> { progress = true; let ExpansionData { depth, id: expn_id, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - self.cx.current_expansion.id = scope; // FIXME(jseyfried): Refactor out the following logic - let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let fragment = self.expand_invoc(invoc, &ext.kind); - self.collect_invocations(fragment, &[]) - } else if let InvocationKind::DeriveContainer { derives: traits, item } = invoc.kind { - if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.mut_span_err(span, - "`derive` may only be applied to \ - structs, enums and unions"); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = traits.iter() - .map(|t| t.to_string()).collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, "try an outer attribute", suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect - ); - } - err.emit(); + let (expanded_fragment, new_invocations) = match res { + InvocationRes::Single(ext) => { + let fragment = self.expand_invoc(invoc, &ext.kind); + self.collect_invocations(fragment, &[]) } + InvocationRes::DeriveContainer(exts) => { + let (derives, item) = match invoc.kind { + InvocationKind::DeriveContainer { derives, item } => (derives, item), + _ => unreachable!(), + }; + if !item.derive_allowed() { + let attr = attr::find_by_name(item.attrs(), sym::derive) + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.mut_span_err(span, + "`derive` may only be applied to structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = derives.iter() + .map(|t| t.to_string()).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, "try an outer attribute", suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect + ); + } + err.emit(); + } - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); - let derive_placeholders = - all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); - - derive_placeholders.reserve(traits.len()); - invocations.reserve(traits.len()); - for path in traits { - let expn_id = ExpnId::fresh(None); - derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); - invocations.push(Invocation { - kind: InvocationKind::Derive { path, item: item.clone() }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - id: expn_id, - ..invoc.expansion_data.clone() - }, - }); + let mut item = self.fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + let mut helper_attrs = Vec::new(); + let mut has_copy = false; + for ext in exts { + helper_attrs.extend(&ext.helper_attrs); + has_copy |= ext.is_derive_copy; + } + // Mark derive helpers inside this item as known and used. + // FIXME: This is a hack, derive helpers should be integrated with regular name + // resolution instead. For example, helpers introduced by a derive container + // can be in scope for all code produced by that container's expansion. + item.visit_with(&mut MarkAttrs(&helper_attrs)); + if has_copy { + self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY); + } + + let derive_placeholders = + all_derive_placeholders.entry(invoc.expansion_data.id).or_default(); + derive_placeholders.reserve(derives.len()); + invocations.reserve(derives.len()); + for path in derives { + let expn_id = ExpnId::fresh(None); + derive_placeholders.push(NodeId::placeholder_from_expn_id(expn_id)); + invocations.push(Invocation { + kind: InvocationKind::Derive { path, item: item.clone() }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + id: expn_id, + ..invoc.expansion_data.clone() + }, + }); + } + let fragment = invoc.fragment_kind + .expect_from_annotatables(::std::iter::once(item)); + self.collect_invocations(fragment, derive_placeholders) } - let fragment = invoc.fragment_kind - .expect_from_annotatables(::std::iter::once(item)); - self.collect_invocations(fragment, derive_placeholders) - } else { - unreachable!() }; if expanded_fragments.len() < depth { @@ -564,7 +583,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return fragment_kind.dummy(span); } let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path }; - let span = span.with_ctxt(self.cx.backtrace()); let items = expander.expand(self.cx, span, &meta, item); fragment_kind.expect_from_annotatables(items) } @@ -1209,9 +1227,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - fn visit_generic_params(&mut self, params: &mut Vec) { - self.cfg.configure_generic_params(params); - noop_visit_generic_params(params, self); + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam + ) -> SmallVec<[ast::GenericParam; 1]> + { + let param = configure!(self, param); + noop_flat_map_generic_param(param, self) } fn visit_attribute(&mut self, at: &mut ast::Attribute) { @@ -1388,17 +1410,3 @@ impl<'feat> ExpansionConfig<'feat> { self.features.map_or(false, |features| features.custom_inner_attributes) } } - -// A Marker adds the given mark to the syntax context. -#[derive(Debug)] -pub struct Marker(pub ExpnId); - -impl MutVisitor for Marker { - fn visit_span(&mut self, span: &mut Span) { - *span = span.apply_mark(self.0) - } - - fn visit_mac(&mut self, mac: &mut ast::Mac) { - noop_visit_mac(mac, self) - } -} diff --git a/src/libsyntax/ext/proc_macro.rs b/src/libsyntax/ext/proc_macro.rs index c17b6f6b4248a..4a44c9a9f1f31 100644 --- a/src/libsyntax/ext/proc_macro.rs +++ b/src/libsyntax/ext/proc_macro.rs @@ -78,7 +78,6 @@ pub struct ProcMacroDerive { pub client: proc_macro::bridge::client::Client< fn(proc_macro::TokenStream) -> proc_macro::TokenStream, >, - pub attrs: Vec, } impl MultiItemModifier for ProcMacroDerive { @@ -111,9 +110,6 @@ impl MultiItemModifier for ProcMacroDerive { } } - // Mark attributes as known, and used. - MarkAttrs(&self.attrs).visit_item(&item); - let token = token::Interpolated(Lrc::new(token::NtItem(item))); let input = tokenstream::TokenTree::token(token, DUMMY_SP).into(); @@ -164,7 +160,7 @@ impl MultiItemModifier for ProcMacroDerive { } } -struct MarkAttrs<'a>(&'a [ast::Name]); +crate struct MarkAttrs<'a>(crate &'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { diff --git a/src/libsyntax/ext/proc_macro_server.rs b/src/libsyntax/ext/proc_macro_server.rs index 1619fa6994198..1a26b17dac782 100644 --- a/src/libsyntax/ext/proc_macro_server.rs +++ b/src/libsyntax/ext/proc_macro_server.rs @@ -7,7 +7,6 @@ use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint} use errors::{Diagnostic, DiagnosticBuilder}; use rustc_data_structures::sync::Lrc; use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span}; -use syntax_pos::hygiene::{SyntaxContext, Transparency}; use syntax_pos::symbol::{kw, sym, Symbol}; use proc_macro::{Delimiter, Level, LineColumn, Spacing}; @@ -361,18 +360,11 @@ pub(crate) struct Rustc<'a> { impl<'a> Rustc<'a> { pub fn new(cx: &'a ExtCtxt<'_>) -> Self { - // No way to determine def location for a proc macro right now, so use call location. - let location = cx.current_expansion.id.expn_data().call_site; - let to_span = |transparency| { - location.with_ctxt( - SyntaxContext::root() - .apply_mark_with_transparency(cx.current_expansion.id, transparency), - ) - }; + let expn_data = cx.current_expansion.id.expn_data(); Rustc { sess: cx.parse_sess, - def_site: to_span(Transparency::Opaque), - call_site: to_span(Transparency::Transparent), + def_site: cx.with_def_site_ctxt(expn_data.def_site), + call_site: cx.with_call_site_ctxt(expn_data.call_site), } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index b057a9ad44d0b..46ffa52f7f572 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -1,3 +1,5 @@ +use crate::ast; +use crate::attr::{self, TransparencyError}; use crate::edition::Edition; use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind}; @@ -15,10 +17,10 @@ use crate::parse::token::{self, NtTT, Token}; use crate::parse::{Directory, ParseSess}; use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use crate::{ast, attr, attr::TransparencyError}; use errors::{DiagnosticBuilder, FatalError}; use log::debug; +use syntax_pos::hygiene::Transparency; use syntax_pos::Span; use rustc_data_structures::fx::FxHashMap; @@ -128,6 +130,7 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, span: Span, + transparency: Transparency, lhses: Vec, rhses: Vec, valid: bool, @@ -143,7 +146,9 @@ impl TTMacroExpander for MacroRulesMacroExpander { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, sp, self.span, self.name, input, &self.lhses, &self.rhses) + generic_extension( + cx, sp, self.span, self.name, self.transparency, input, &self.lhses, &self.rhses + ) } } @@ -158,6 +163,7 @@ fn generic_extension<'cx>( sp: Span, def_span: Span, name: ast::Ident, + transparency: Transparency, arg: TokenStream, lhses: &[quoted::TokenTree], rhses: &[quoted::TokenTree], @@ -187,7 +193,7 @@ fn generic_extension<'cx>( let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = transcribe(cx, &named_matches, rhs); + let mut tts = transcribe(cx, &named_matches, rhs, transparency); // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. @@ -285,6 +291,7 @@ pub fn compile( def: &ast::Item, edition: Edition, ) -> SyntaxExtension { + let diag = &sess.span_diagnostic; let lhs_nm = ast::Ident::new(sym::lhs, def.span); let rhs_nm = ast::Ident::new(sym::rhs, def.span); let tt_spec = ast::Ident::new(sym::tt, def.span); @@ -415,75 +422,28 @@ pub fn compile( // that is not lint-checked and trigger the "failed to process buffered lint here" bug. valid &= macro_check::check_meta_variables(sess, ast::CRATE_NODE_ID, def.span, &lhses, &rhses); - let expander: Box<_> = - Box::new(MacroRulesMacroExpander { name: def.ident, span: def.span, lhses, rhses, valid }); - - let (default_transparency, transparency_error) = - attr::find_transparency(&def.attrs, body.legacy); + let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => - sess.span_diagnostic.span_err( - span, &format!("unknown macro transparency: `{}`", value) - ), + diag.span_err(span, &format!("unknown macro transparency: `{}`", value)), Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => - sess.span_diagnostic.span_err( - vec![old_span, new_span], "multiple macro transparency attributes" - ), + diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"), None => {} } - let allow_internal_unstable = - attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| { - attr.meta_item_list() - .map(|list| { - list.iter() - .filter_map(|it| { - let name = it.ident().map(|ident| ident.name); - if name.is_none() { - sess.span_diagnostic.span_err( - it.span(), - "allow internal unstable expects feature names", - ) - } - name - }) - .collect::>() - .into() - }) - .unwrap_or_else(|| { - sess.span_diagnostic.span_warn( - attr.span, - "allow_internal_unstable expects list of feature names. In the \ - future this will become a hard error. Please use `allow_internal_unstable(\ - foo, bar)` to only allow the `foo` and `bar` features", - ); - vec![sym::allow_internal_unstable_backcompat_hack].into() - }) - }); - - let mut local_inner_macros = false; - if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); - } - } + let expander: Box<_> = Box::new(MacroRulesMacroExpander { + name: def.ident, span: def.span, transparency, lhses, rhses, valid + }); - let is_builtin = attr::contains_name(&def.attrs, sym::rustc_builtin_macro); - - SyntaxExtension { - kind: SyntaxExtensionKind::LegacyBang(expander), - span: def.span, - default_transparency, - allow_internal_unstable, - allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe), - local_inner_macros, - stability: attr::find_stability(&sess, &def.attrs, def.span), - deprecation: attr::find_deprecation(&sess, &def.attrs, def.span), - helper_attrs: Vec::new(), + SyntaxExtension::new( + sess, + SyntaxExtensionKind::LegacyBang(expander), + def.span, + Vec::new(), edition, - is_builtin, - is_derive_copy: is_builtin && def.ident.name == sym::Copy, - } + def.ident.name, + &def.attrs, + ) } fn check_lhs_nt_follows( diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 214e721fd1506..30d5df13dcedb 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -1,9 +1,8 @@ -use crate::ast::Ident; +use crate::ast::{Ident, Mac}; use crate::ext::base::ExtCtxt; -use crate::ext::expand::Marker; use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use crate::ext::tt::quoted; -use crate::mut_visit::noop_visit_tt; +use crate::mut_visit::{self, MutVisitor}; use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; @@ -11,8 +10,31 @@ use smallvec::{smallvec, SmallVec}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use syntax_pos::hygiene::{ExpnId, Transparency}; +use syntax_pos::Span; + use std::mem; +// A Marker adds the given mark to the syntax context. +struct Marker(ExpnId, Transparency); + +impl MutVisitor for Marker { + fn visit_span(&mut self, span: &mut Span) { + *span = span.apply_mark(self.0, self.1) + } + + fn visit_mac(&mut self, mac: &mut Mac) { + mut_visit::noop_visit_mac(mac, self) + } +} + +impl Marker { + fn visit_delim_span(&mut self, dspan: &mut DelimSpan) { + self.visit_span(&mut dspan.open); + self.visit_span(&mut dspan.close); + } +} + /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { Delimited { forest: Lrc, idx: usize, span: DelimSpan }, @@ -68,6 +90,7 @@ pub(super) fn transcribe( cx: &ExtCtxt<'_>, interp: &FxHashMap, src: Vec, + transparency: Transparency, ) -> TokenStream { // Nothing for us to transcribe... if src.is_empty() { @@ -96,6 +119,7 @@ pub(super) fn transcribe( // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); + let mut marker = Marker(cx.current_expansion.id, transparency); loop { // Look at the last frame on the stack. @@ -207,7 +231,7 @@ pub(super) fn transcribe( } // Replace the meta-var with the matched token tree from the invocation. - quoted::TokenTree::MetaVar(mut sp, ident) => { + quoted::TokenTree::MetaVar(mut sp, mut ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { @@ -218,7 +242,7 @@ pub(super) fn transcribe( if let NtTT(ref tt) = **nt { result.push(tt.clone().into()); } else { - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); let token = TokenTree::token(token::Interpolated(nt.clone()), sp); result.push(token.into()); } @@ -232,9 +256,8 @@ pub(super) fn transcribe( } else { // If we aren't able to match the meta-var, we push it back into the result but // with modified syntax context. (I believe this supports nested macros). - let ident = - Ident::new(ident.name, ident.span.apply_mark(cx.current_expansion.id)); - sp = sp.apply_mark(cx.current_expansion.id); + marker.visit_span(&mut sp); + marker.visit_ident(&mut ident); result.push(TokenTree::token(token::Dollar, sp).into()); result.push(TokenTree::Token(Token::from_ast_ident(ident)).into()); } @@ -246,7 +269,7 @@ pub(super) fn transcribe( // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). quoted::TokenTree::Delimited(mut span, delimited) => { - span = span.apply_mark(cx.current_expansion.id); + marker.visit_delim_span(&mut span); stack.push(Frame::Delimited { forest: delimited, idx: 0, span }); result_stack.push(mem::take(&mut result)); } @@ -254,9 +277,8 @@ pub(super) fn transcribe( // Nothing much to do here. Just push the token to the result, being careful to // preserve syntax context. quoted::TokenTree::Token(token) => { - let mut marker = Marker(cx.current_expansion.id); let mut tt = TokenTree::Token(token); - noop_visit_tt(&mut tt, &mut marker); + marker.visit_tt(&mut tt); result.push(tt.into()); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs deleted file mode 100644 index bce0b07db1c23..0000000000000 --- a/src/libsyntax/feature_gate.rs +++ /dev/null @@ -1,2495 +0,0 @@ -//! # Feature gating -//! -//! This module implements the gating necessary for preventing certain compiler -//! features from being used by default. This module will crawl a pre-expanded -//! AST to ensure that there are no features which are used that are not -//! enabled. -//! -//! Features are enabled in programs via the crate-level attributes of -//! `#![feature(...)]` with a comma-separated list of features. -//! -//! For the purpose of future feature-tracking, once code for detection of feature -//! gate usage is added, *do not remove it again* even once the feature -//! becomes stable. - -use AttributeType::*; -use AttributeGate::*; - -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, -}; -use crate::attr::{self, check_builtin_attribute, AttributeTemplate}; -use crate::source_map::Spanned; -use crate::edition::{ALL_EDITIONS, Edition}; -use crate::visit::{self, FnKind, Visitor}; -use crate::parse::{token, ParseSess}; -use crate::parse::parser::Parser; -use crate::symbol::{Symbol, sym}; -use crate::tokenstream::TokenTree; - -use errors::{Applicability, DiagnosticBuilder, Handler}; -use rustc_data_structures::fx::FxHashMap; -use rustc_target::spec::abi::Abi; -use syntax_pos::{Span, DUMMY_SP, MultiSpan}; -use log::debug; -use lazy_static::lazy_static; - -use std::env; - -macro_rules! set { - ($field: ident) => {{ - fn f(features: &mut Features, _: Span) { - features.$field = true; - } - f as fn(&mut Features, Span) - }} -} - -macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr, $edition: expr),)+) => { - /// Represents active features that are currently being implemented or - /// currently being considered for addition/removal. - const ACTIVE_FEATURES: - &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = - &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; - - /// A set of features to be used by later passes. - #[derive(Clone)] - pub struct Features { - /// `#![feature]` attrs for language features, for error reporting - pub declared_lang_features: Vec<(Symbol, Span, Option)>, - /// `#![feature]` attrs for non-language (library) features - pub declared_lib_features: Vec<(Symbol, Span)>, - $(pub $feature: bool),+ - } - - impl Features { - pub fn new() -> Features { - Features { - declared_lang_features: Vec::new(), - declared_lib_features: Vec::new(), - $($feature: false),+ - } - } - - pub fn walk_feature_fields(&self, mut f: F) - where F: FnMut(&str, bool) - { - $(f(stringify!($feature), self.$feature);)+ - } - } - }; - - ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { - /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, $reason)),+ - ]; - }; - - ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - }; - - ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { - /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ - $((sym::$feature, $ver, $issue, None)),+ - ]; - } -} - -// If you change this, please modify `src/doc/unstable-book` as well. -// -// Don't ever remove anything from this list; set them to 'Removed'. -// -// The version numbers here correspond to the version in which the current status -// was set. This is most important for knowing when a particular feature became -// stable (active). -// -// Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is inforced with tidy. -// -// N.B., `tools/tidy/src/features.rs` parses this information directly out of the -// source, so take care when modifying it. - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: internal feature gates - // ------------------------------------------------------------------------- - - // no-tracking-issue-start - - // Allows using compiler's own crates. - (active, rustc_private, "1.0.0", Some(27812), None), - - // Allows using the `rust-intrinsic`'s "ABI". - (active, intrinsics, "1.0.0", None, None), - - // Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. - (active, lang_items, "1.0.0", None, None), - - // Allows using the `#[stable]` and `#[unstable]` attributes. - (active, staged_api, "1.0.0", None, None), - - // Allows using `#[allow_internal_unstable]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unstable, "1.0.0", None, None), - - // Allows using `#[allow_internal_unsafe]`. This is an - // attribute on `macro_rules!` and can't use the attribute handling - // below (it has to be checked before expansion possibly makes - // macros disappear). - (active, allow_internal_unsafe, "1.0.0", None, None), - - // Allows using the macros: - // + `__diagnostic_used` - // + `__register_diagnostic` - // +`__build_diagnostic_array` - (active, rustc_diagnostic_macros, "1.0.0", None, None), - - // Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which - // lets a function to be `const` when opted into with `#![feature(foo)]`. - (active, rustc_const_unstable, "1.0.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[link_name="llvm.*"]`. - (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), - - // Allows using `rustc_*` attributes (RFC 572). - (active, rustc_attrs, "1.0.0", Some(29642), None), - - // Allows using `#[on_unimplemented(..)]` on traits. - (active, on_unimplemented, "1.0.0", Some(29628), None), - - // Allows using the `box $expr` syntax. - (active, box_syntax, "1.0.0", Some(49733), None), - - // Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. - (active, main, "1.0.0", Some(29634), None), - - // Allows using `#[start]` on a function indicating that it is the program entrypoint. - (active, start, "1.0.0", Some(29633), None), - - // Allows using the `#[fundamental]` attribute. - (active, fundamental, "1.0.0", Some(29635), None), - - // Allows using the `rust-call` ABI. - (active, unboxed_closures, "1.0.0", Some(29625), None), - - // Allows using the `#[linkage = ".."]` attribute. - (active, linkage, "1.0.0", Some(29603), None), - - // Allows features specific to OIBIT (auto traits). - (active, optin_builtin_traits, "1.0.0", Some(13231), None), - - // Allows using `box` in patterns (RFC 469). - (active, box_patterns, "1.0.0", Some(29641), None), - - // no-tracking-issue-start - - // Allows using `#[prelude_import]` on glob `use` items. - (active, prelude_import, "1.2.0", None, None), - - // no-tracking-issue-end - - // no-tracking-issue-start - - // Allows using `#[omit_gdb_pretty_printer_section]`. - (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), - - // Allows using the `vectorcall` ABI. - (active, abi_vectorcall, "1.7.0", None, None), - - // no-tracking-issue-end - - // Allows using `#[structural_match]` which indicates that a type is structurally matchable. - (active, structural_match, "1.8.0", Some(31434), None), - - // Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), - - // Allows using the `#![panic_runtime]` attribute. - (active, panic_runtime, "1.10.0", Some(32837), None), - - // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. - (active, needs_panic_runtime, "1.10.0", Some(32837), None), - - // no-tracking-issue-start - - // Allows identifying the `compiler_builtins` crate. - (active, compiler_builtins, "1.13.0", None, None), - - // Allows using the `unadjusted` ABI; perma-unstable. - (active, abi_unadjusted, "1.16.0", None, None), - - // Allows identifying crates that contain sanitizer runtimes. - (active, sanitizer_runtime, "1.17.0", None, None), - - // Used to identify crates that contain the profiler runtime. - (active, profiler_runtime, "1.18.0", None, None), - - // Allows using the `thiscall` ABI. - (active, abi_thiscall, "1.19.0", None, None), - - // Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. - (active, allocator_internals, "1.20.0", None, None), - - // no-tracking-issue-end - - // Added for testing E0705; perma-unstable. - (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), - - // ------------------------------------------------------------------------- - // feature-group-end: internal feature gates - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // FIXME: Document these and merge with the list below. - - // Unstable `#[target_feature]` directives. - (active, arm_target_feature, "1.27.0", Some(44839), None), - (active, aarch64_target_feature, "1.27.0", Some(44839), None), - (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), - (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), - (active, sse4a_target_feature, "1.27.0", Some(44839), None), - (active, tbm_target_feature, "1.27.0", Some(44839), None), - (active, wasm_target_feature, "1.30.0", Some(44839), None), - (active, adx_target_feature, "1.32.0", Some(44839), None), - (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), - (active, movbe_target_feature, "1.34.0", Some(44839), None), - (active, rtm_target_feature, "1.35.0", Some(44839), None), - (active, f16c_target_feature, "1.36.0", Some(44839), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates (target features) - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: actual feature gates - // ------------------------------------------------------------------------- - - // Allows using the `#[link_args]` attribute. - (active, link_args, "1.0.0", Some(29596), None), - - // Allows defining identifiers beyond ASCII. - (active, non_ascii_idents, "1.0.0", Some(55467), None), - - // Allows using `#[plugin_registrar]` on functions. - (active, plugin_registrar, "1.0.0", Some(29597), None), - - // Allows using `#![plugin(myplugin)]`. - (active, plugin, "1.0.0", Some(29597), None), - - // Allows using `#[thread_local]` on `static` items. - (active, thread_local, "1.0.0", Some(29594), None), - - // Allows the use of SIMD types in functions declared in `extern` blocks. - (active, simd_ffi, "1.0.0", Some(27731), None), - - // Allows using custom attributes (RFC 572). - (active, custom_attribute, "1.0.0", Some(29642), None), - - // Allows using non lexical lifetimes (RFC 2094). - (active, nll, "1.0.0", Some(43234), None), - - // Allows using slice patterns. - (active, slice_patterns, "1.0.0", Some(62254), None), - - // Allows the definition of `const` functions with some advanced features. - (active, const_fn, "1.2.0", Some(57563), None), - - // Allows associated type defaults. - (active, associated_type_defaults, "1.2.0", Some(29661), None), - - // Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), - - // Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), - - // Allows `repr(simd)` and importing the various simd intrinsics. - (active, repr_simd, "1.4.0", Some(27731), None), - - // Allows `extern "platform-intrinsic" { ... }`. - (active, platform_intrinsics, "1.4.0", Some(27731), None), - - // Allows `#[unwind(..)]`. - // - // Permits specifying whether a function should permit unwinding or abort on unwind. - (active, unwind_attributes, "1.4.0", Some(58760), None), - - // Allows `#[no_debug]`. - (active, no_debug, "1.5.0", Some(29721), None), - - // Allows attributes on expressions and non-item statements. - (active, stmt_expr_attributes, "1.6.0", Some(15701), None), - - // Allows the use of type ascription in expressions. - (active, type_ascription, "1.6.0", Some(23416), None), - - // Allows `cfg(target_thread_local)`. - (active, cfg_target_thread_local, "1.7.0", Some(29594), None), - - // Allows specialization of implementations (RFC 1210). - (active, specialization, "1.7.0", Some(31844), None), - - // Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), - - // Allows `cfg(target_has_atomic = "...")`. - (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), - - // Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), - - // Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), - - // Allows exhaustive pattern matching on types that contain uninhabited types. - (active, exhaustive_patterns, "1.13.0", Some(51085), None), - - // Allows untagged unions `union U { ... }`. - (active, untagged_unions, "1.13.0", Some(32836), None), - - // Allows `#[link(..., cfg(..))]`. - (active, link_cfg, "1.14.0", Some(37406), None), - - // Allows `extern "ptx-*" fn()`. - (active, abi_ptx, "1.15.0", Some(38788), None), - - // Allows the `#[repr(i128)]` attribute for enums. - (active, repr128, "1.16.0", Some(35118), None), - - // Allows `#[link(kind="static-nobundle"...)]`. - (active, static_nobundle, "1.16.0", Some(37403), None), - - // Allows `extern "msp430-interrupt" fn()`. - (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), - - // Allows declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), - - // Allows `extern "x86-interrupt" fn()`. - (active, abi_x86_interrupt, "1.17.0", Some(40180), None), - - // Allows overlapping impls of marker traits. - (active, overlapping_marker_traits, "1.18.0", Some(29864), None), - - // Allows a test to fail without failing the whole suite. - (active, allow_fail, "1.19.0", Some(46488), None), - - // Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), - - // Allows defining generators. - (active, generators, "1.21.0", Some(43122), None), - - // Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), - - // Allows `#[doc(masked)]`. - (active, doc_masked, "1.21.0", Some(44027), None), - - // Allows `#[doc(spotlight)]`. - (active, doc_spotlight, "1.22.0", Some(45040), None), - - // Allows `#[doc(include = "some-file")]`. - (active, external_doc, "1.22.0", Some(44732), None), - - // Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). - (active, non_exhaustive, "1.22.0", Some(44109), None), - - // Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (active, crate_visibility_modifier, "1.23.0", Some(53120), None), - - // Allows defining `extern type`s. - (active, extern_types, "1.23.0", Some(43467), None), - - // Allows trait methods with arbitrary self types. - (active, arbitrary_self_types, "1.23.0", Some(44874), None), - - // Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (active, in_band_lifetimes, "1.23.0", Some(44524), None), - - // Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), - - // Allows defining `trait X = A + B;` alias items. - (active, trait_alias, "1.24.0", Some(41517), None), - - // Allows infering `'static` outlives requirements (RFC 2093). - (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), - - // Allows macro invocations in `extern {}` blocks. - (active, macros_in_extern, "1.27.0", Some(49476), None), - - // Allows accessing fields of unions inside `const` functions. - (active, const_fn_union, "1.27.0", Some(51909), None), - - // Allows casting raw pointers to `usize` during const eval. - (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), - - // Allows dereferencing raw pointers during const eval. - (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - - // Allows comparing raw pointers during const eval. - (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), - - // Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - - // Allows inconsistent bounds in where clauses. - (active, trivial_bounds, "1.28.0", Some(48214), None), - - // Allows `'a: { break 'a; }`. - (active, label_break_value, "1.28.0", Some(48594), None), - - // Allows using `#[doc(keyword = "...")]`. - (active, doc_keyword, "1.28.0", Some(51315), None), - - // Allows reinterpretation of the bits of a value of one type as another type during const eval. - (active, const_transmute, "1.29.0", Some(53605), None), - - // Allows using `try {...}` expressions. - (active, try_blocks, "1.29.0", Some(31436), None), - - // Allows defining an `#[alloc_error_handler]`. - (active, alloc_error_handler, "1.29.0", Some(51540), None), - - // Allows using the `amdgpu-kernel` ABI. - (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - - // Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), - - // Allows `#[marker]` on certain traits allowing overlapping implementations. - (active, marker_trait_attr, "1.30.0", Some(29864), None), - - // Allows macro invocations on modules expressions and statements and - // procedural macros to expand to non-items. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - - // Allows unsized rvalues at arguments and parameters. - (active, unsized_locals, "1.30.0", Some(48055), None), - - // Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. - (active, custom_test_frameworks, "1.30.0", Some(50297), None), - - // Allows non-builtin attributes in inner attribute position. - (active, custom_inner_attributes, "1.30.0", Some(54726), None), - - // Allows mixing bind-by-move in patterns and references to those identifiers in guards. - (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), - - // Allows `impl Trait` in bindings (`let`, `const`, `static`). - (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), - - // Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (active, lint_reasons, "1.31.0", Some(54503), None), - - // Allows exhaustive integer pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), - - // Allows relaxing the coherence rules such that - // `impl ForeignTrait for ForeignType is permitted. - (active, re_rebalance_coherence, "1.32.0", Some(55437), None), - - // Allows using `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), - - // Allows const generic types (e.g. `struct Foo(...);`). - (active, const_generics, "1.34.0", Some(44580), None), - - // Allows using `#[optimize(X)]`. - (active, optimize_attribute, "1.34.0", Some(54882), None), - - // Allows using C-variadics. - (active, c_variadic, "1.34.0", Some(44930), None), - - // Allows the user of associated type bounds. - (active, associated_type_bounds, "1.34.0", Some(52662), None), - - // Attributes on formal function params. - (active, param_attrs, "1.36.0", Some(60406), None), - - // Allows calling constructor functions in `const fn`. - (active, const_constructor, "1.37.0", Some(61456), None), - - // Allows `if/while p && let q = r && ...` chains. - (active, let_chains, "1.37.0", Some(53667), None), - - // Allows #[repr(transparent)] on enums (RFC 2645). - (active, transparent_enums, "1.37.0", Some(60405), None), - - // Allows #[repr(transparent)] on unions (RFC 2645). - (active, transparent_unions, "1.37.0", Some(60405), None), - - // Allows explicit discriminants on non-unit enum variants. - (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - - // Allows `impl Trait` with multiple unrelated lifetimes. - (active, member_constraints, "1.37.0", Some(61977), None), - - // Allows `async || body` closures. - (active, async_closure, "1.37.0", Some(62290), None), - - // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests - (active, cfg_doctest, "1.37.0", Some(62210), None), - - // Allows `[x; N]` where `x` is a constant (RFC 2203). - (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), - - // Allows `impl Trait` to be used inside type aliases (RFC 2515). - (active, type_alias_impl_trait, "1.38.0", Some(63063), None), - - // Allows the use of or-patterns, e.g. `0 | 1`. - (active, or_patterns, "1.38.0", Some(54883), None), - - // ------------------------------------------------------------------------- - // feature-group-end: actual feature gates - // ------------------------------------------------------------------------- -); - -/// Some features are known to be incomplete and using them is likely to have -/// unanticipated results, such as compiler crashes. We warn the user about these -/// to alert them. -pub const INCOMPLETE_FEATURES: &[Symbol] = &[ - sym::impl_trait_in_bindings, - sym::generic_associated_types, - sym::const_generics, - sym::or_patterns, - sym::let_chains, -]; - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: removed features - // ------------------------------------------------------------------------- - - (removed, import_shadowing, "1.0.0", None, None, None), - (removed, managed_boxes, "1.0.0", None, None, None), - // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 - (removed, negate_unsigned, "1.0.0", Some(29645), None, None), - (removed, reflect, "1.0.0", Some(27749), None, None), - // A way to temporarily opt out of opt in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None, None), - (removed, quad_precision_float, "1.0.0", None, None, None), - (removed, struct_inherit, "1.0.0", None, None, None), - (removed, test_removed_feature, "1.0.0", None, None, None), - (removed, visible_private_types, "1.0.0", None, None, None), - (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), - // Allows using items which are missing stability attributes - (removed, unmarked_api, "1.0.0", None, None, None), - (removed, allocator, "1.0.0", None, None, None), - (removed, simd, "1.0.0", Some(27731), None, - Some("removed in favor of `#[repr(simd)]`")), - (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, - Some("merged into `#![feature(slice_patterns)]`")), - (removed, macro_reexport, "1.0.0", Some(29638), None, - Some("subsumed by `pub use`")), - (removed, pushpop_unsafe, "1.2.0", None, None, None), - (removed, needs_allocator, "1.4.0", Some(27389), None, - Some("subsumed by `#![feature(allocator_internals)]`")), - (removed, proc_macro_mod, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_expr, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_non_items, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, proc_macro_gen, "1.27.0", Some(54727), None, - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), - (removed, panic_implementation, "1.28.0", Some(44489), None, - Some("subsumed by `#[panic_handler]`")), - // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.32.0", Some(29644), None, - Some("subsumed by `#[proc_macro_derive]`")), - // Paths of the form: `extern::foo::bar` - (removed, extern_in_paths, "1.33.0", Some(55600), None, - Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.33.0", Some(29601), None, None), - // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). - (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), - (removed, await_macro, "1.38.0", Some(50547), None, - Some("subsumed by `.await` syntax")), - // Allows defining `existential type`s. - (removed, existential_type, "1.38.0", Some(63063), None, - Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), - - // ------------------------------------------------------------------------- - // feature-group-end: removed features - // ------------------------------------------------------------------------- -); - -declare_features! ( - (stable_removed, no_stack_check, "1.0.0", None, None), -); - -declare_features! ( - // ------------------------------------------------------------------------- - // feature-group-start: for testing purposes - // ------------------------------------------------------------------------- - - // A temporary feature gate used to enable parser extensions needed - // to bootstrap fix for #5723. - (accepted, issue_5723_bootstrap, "1.0.0", None, None), - // These are used to test this portion of the compiler, - // they don't actually mean anything. - (accepted, test_accepted_feature, "1.0.0", None, None), - - // ------------------------------------------------------------------------- - // feature-group-end: for testing purposes - // ------------------------------------------------------------------------- - - // ------------------------------------------------------------------------- - // feature-group-start: accepted features - // ------------------------------------------------------------------------- - - // Allows using associated `type`s in `trait`s. - (accepted, associated_types, "1.0.0", None, None), - // Allows using assigning a default type to type parameters in algebraic data type definitions. - (accepted, default_type_params, "1.0.0", None, None), - // FIXME: explain `globs`. - (accepted, globs, "1.0.0", None, None), - // Allows `macro_rules!` items. - (accepted, macro_rules, "1.0.0", None, None), - // Allows use of `&foo[a..b]` as a slicing syntax. - (accepted, slicing_syntax, "1.0.0", None, None), - // Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). - (accepted, struct_variant, "1.0.0", None, None), - // Allows indexing tuples. - (accepted, tuple_indexing, "1.0.0", None, None), - // Allows the use of `if let` expressions. - (accepted, if_let, "1.0.0", None, None), - // Allows the use of `while let` expressions. - (accepted, while_let, "1.0.0", None, None), - // Allows using `#![no_std]`. - (accepted, no_std, "1.6.0", None, None), - // Allows overloading augmented assignment operations like `a += b`. - (accepted, augmented_assignments, "1.8.0", Some(28235), None), - // Allows empty structs and enum variants with braces. - (accepted, braced_empty_structs, "1.8.0", Some(29720), None), - // Allows `#[deprecated]` attribute. - (accepted, deprecated, "1.9.0", Some(29935), None), - // Allows macros to appear in the type position. - (accepted, type_macros, "1.13.0", Some(27245), None), - // Allows use of the postfix `?` operator in expressions. - (accepted, question_mark, "1.13.0", Some(31436), None), - // Allows `..` in tuple (struct) patterns. - (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), - // Allows some increased flexibility in the name resolution rules, - // especially around globs and shadowing (RFC 1560). - (accepted, item_like_imports, "1.15.0", Some(35120), None), - // Allows using `Self` and associated types in struct expressions and patterns. - (accepted, more_struct_aliases, "1.16.0", Some(37544), None), - // Allows elision of `'static` lifetimes in `static`s and `const`s. - (accepted, static_in_const, "1.17.0", Some(35897), None), - // Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. - (accepted, field_init_shorthand, "1.17.0", Some(37340), None), - // Allows the definition recursive static items. - (accepted, static_recursion, "1.17.0", Some(29719), None), - // Allows `pub(restricted)` visibilities (RFC 1422). - (accepted, pub_restricted, "1.18.0", Some(32409), None), - // Allows `#![windows_subsystem]`. - (accepted, windows_subsystem, "1.18.0", Some(37499), None), - // Allows `break {expr}` with a value inside `loop`s. - (accepted, loop_break_value, "1.19.0", Some(37339), None), - // Allows numeric fields in struct expressions and patterns. - (accepted, relaxed_adts, "1.19.0", Some(35626), None), - // Allows coercing non capturing closures to function pointers. - (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), - // Allows attributes on struct literal fields. - (accepted, struct_field_attributes, "1.20.0", Some(38814), None), - // Allows the definition of associated constants in `trait` or `impl` blocks. - (accepted, associated_consts, "1.20.0", Some(29646), None), - // Allows usage of the `compile_error!` macro. - (accepted, compile_error, "1.20.0", Some(40872), None), - // Allows code like `let x: &'static u32 = &42` to work (RFC 1414). - (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), - // Allows `Drop` types in constants (RFC 1440). - (accepted, drop_types_in_const, "1.22.0", Some(33156), None), - // Allows the sysV64 ABI to be specified on all platforms - // instead of just the platforms on which it is the C ABI. - (accepted, abi_sysv64, "1.24.0", Some(36167), None), - // Allows `repr(align(16))` struct attribute (RFC 1358). - (accepted, repr_align, "1.25.0", Some(33626), None), - // Allows '|' at beginning of match arms (RFC 1925). - (accepted, match_beginning_vert, "1.25.0", Some(44101), None), - // Allows nested groups in `use` items (RFC 2128). - (accepted, use_nested_groups, "1.25.0", Some(44494), None), - // Allows indexing into constant arrays. - (accepted, const_indexing, "1.26.0", Some(29947), None), - // Allows using `a..=b` and `..=b` as inclusive range syntaxes. - (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), - // Allows `..=` in patterns (RFC 1192). - (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), - // Allows `fn main()` with return types which implements `Termination` (RFC 1937). - (accepted, termination_trait, "1.26.0", Some(43301), None), - // Allows implementing `Clone` for closures where possible (RFC 2132). - (accepted, clone_closures, "1.26.0", Some(44490), None), - // Allows implementing `Copy` for closures where possible (RFC 2132). - (accepted, copy_closures, "1.26.0", Some(44490), None), - // Allows `impl Trait` in function arguments. - (accepted, universal_impl_trait, "1.26.0", Some(34511), None), - // Allows `impl Trait` in function return types. - (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), - // Allows using the `u128` and `i128` types. - (accepted, i128_type, "1.26.0", Some(35118), None), - // Allows default match binding modes (RFC 2005). - (accepted, match_default_bindings, "1.26.0", Some(42640), None), - // Allows `'_` placeholder lifetimes. - (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), - // Allows attributes on lifetime/type formal parameters in generics (RFC 1327). - (accepted, generic_param_attrs, "1.27.0", Some(48848), None), - // Allows `cfg(target_feature = "...")`. - (accepted, cfg_target_feature, "1.27.0", Some(29717), None), - // Allows `#[target_feature(...)]`. - (accepted, target_feature, "1.27.0", None, None), - // Allows using `dyn Trait` as a syntax for trait objects. - (accepted, dyn_trait, "1.27.0", Some(44662), None), - // Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). - (accepted, fn_must_use, "1.27.0", Some(43302), None), - // Allows use of the `:lifetime` macro fragment specifier. - (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), - // Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). - (accepted, termination_trait_test, "1.27.0", Some(48854), None), - // Allows the `#[global_allocator]` attribute. - (accepted, global_allocator, "1.28.0", Some(27389), None), - // Allows `#[repr(transparent)]` attribute on newtype structs. - (accepted, repr_transparent, "1.28.0", Some(43036), None), - // Allows procedural macros in `proc-macro` crates. - (accepted, proc_macro, "1.29.0", Some(38356), None), - // Allows `foo.rs` as an alternative to `foo/mod.rs`. - (accepted, non_modrs_mods, "1.30.0", Some(44660), None), - // Allows use of the `:vis` macro fragment specifier - (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), - // Allows importing and reexporting macros with `use`, - // enables macro modularization in general. - (accepted, use_extern_macros, "1.30.0", Some(35896), None), - // Allows keywords to be escaped for use as identifiers. - (accepted, raw_identifiers, "1.30.0", Some(48589), None), - // Allows attributes scoped to tools. - (accepted, tool_attributes, "1.30.0", Some(44690), None), - // Allows multi-segment paths in attributes and derives. - (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), - // Allows all literals in attribute lists and values of key-value pairs. - (accepted, attr_literals, "1.30.0", Some(34981), None), - // Allows inferring outlives requirements (RFC 2093). - (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), - // Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. - // This defines the behavior of panics. - (accepted, panic_handler, "1.30.0", Some(44489), None), - // Allows `#[used]` to preserve symbols (see llvm.used). - (accepted, used, "1.30.0", Some(40289), None), - // Allows `crate` in paths. - (accepted, crate_in_paths, "1.30.0", Some(45477), None), - // Allows resolving absolute paths as paths from other crates. - (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), - // Allows access to crate names passed via `--extern` through prelude. - (accepted, extern_prelude, "1.30.0", Some(44660), None), - // Allows parentheses in patterns. - (accepted, pattern_parentheses, "1.31.0", Some(51087), None), - // Allows the definition of `const fn` functions. - (accepted, min_const_fn, "1.31.0", Some(53555), None), - // Allows scoped lints. - (accepted, tool_lints, "1.31.0", Some(44690), None), - // Allows lifetime elision in `impl` headers. For example: - // + `impl Iterator for &mut Iterator` - // + `impl Debug for Foo<'_>` - (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), - // Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. - (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), - // Allows use of the `:literal` macro fragment specifier (RFC 1576). - (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), - // Allows use of `?` as the Kleene "at most one" operator in macros. - (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), - // Allows `Self` struct constructor (RFC 2302). - (accepted, self_struct_ctor, "1.32.0", Some(51994), None), - // Allows `Self` in type definitions (RFC 2300). - (accepted, self_in_typedefs, "1.32.0", Some(49303), None), - // Allows `use x::y;` to search `x` in the current scope. - (accepted, uniform_paths, "1.32.0", Some(53130), None), - // Allows integer match exhaustiveness checking (RFC 2591). - (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), - // Allows `use path as _;` and `extern crate c as _;`. - (accepted, underscore_imports, "1.33.0", Some(48216), None), - // Allows `#[repr(packed(N))]` attribute on structs. - (accepted, repr_packed, "1.33.0", Some(33158), None), - // Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). - (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), - // Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. - (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), - // Allows let bindings, assignments and destructuring in `const` functions and constants. - // As long as control flow is not implemented in const eval, `&&` and `||` may not be used - // at the same time as let bindings. - (accepted, const_let, "1.33.0", Some(48821), None), - // Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. - (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), - // Allows top level or-patterns (`p | q`) in `if let` and `while let`. - (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), - // Allows `cfg(target_vendor = "...")`. - (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), - // Allows `extern crate self as foo;`. - // This puts local crate root into extern prelude under name `foo`. - (accepted, extern_crate_self, "1.34.0", Some(56409), None), - // Allows arbitrary delimited token streams in non-macro attributes. - (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), - // Allows paths to enum variants on type aliases including `Self`. - (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), - // Allows using `#[repr(align(X))]` on enums with equivalent semantics - // to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. - (accepted, repr_align_enum, "1.37.0", Some(57996), None), - // Allows `const _: TYPE = VALUE`. - (accepted, underscore_const_names, "1.37.0", Some(54912), None), - // Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. - (accepted, async_await, "1.38.0", Some(50547), None), - - // ------------------------------------------------------------------------- - // feature-group-end: accepted features - // ------------------------------------------------------------------------- -); - -// If you change this, please modify `src/doc/unstable-book` as well. You must -// move that documentation into the relevant place in the other docs, and -// remove the chapter on the flag. - -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum AttributeType { - /// Normal, builtin attribute that is consumed - /// by the compiler before the unused_attribute check - Normal, - - /// Builtin attribute that may not be consumed by the compiler - /// before the unused_attribute check. These attributes - /// will be ignored by the unused_attribute lint - Whitelisted, - - /// Builtin attribute that is only allowed at the crate level - CrateLevel, -} - -pub enum AttributeGate { - /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), - - /// Ungated attribute, can be used on all release channels - Ungated, -} - -/// A convenience macro for constructing attribute templates. -/// E.g., `template!(Word, List: "description")` means that the attribute -/// supports forms `#[attr]` and `#[attr(description)]`. -macro_rules! template { - (Word) => { template!(@ true, None, None) }; - (List: $descr: expr) => { template!(@ false, Some($descr), None) }; - (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; - (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; - (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; - (List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ false, Some($descr1), Some($descr2)) - }; - (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ true, Some($descr1), Some($descr2)) - }; - (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { - word: $word, list: $list, name_value_str: $name_value_str - } }; -} - -impl AttributeGate { - fn is_deprecated(&self) -> bool { - match *self { - Gated(Stability::Deprecated(_, _), ..) => true, - _ => false, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute" - Deprecated(&'static str, Option<&'static str>), -} - -// fn() is not Debug -impl std::fmt::Debug for AttributeGate { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Gated(ref stab, name, expl, _) => - write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), - Ungated => write!(fmt, "Ungated") - } - } -} - -macro_rules! cfg_fn { - ($field: ident) => {{ - fn f(features: &Features) -> bool { - features.$field - } - f as fn(&Features) -> bool - }} -} - -pub fn deprecated_attributes() -> Vec<&'static (Symbol, AttributeType, - AttributeTemplate, AttributeGate)> { - BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() -} - -pub fn is_builtin_attr_name(name: ast::Name) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() -} - -pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() -} - -/// Attributes that have a special meaning to rustc or rustdoc -pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ - // Normal attributes - - ( - sym::warn, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::allow, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::forbid, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - ( - sym::deny, - Normal, - template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), - Ungated - ), - - (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), - (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), - (sym::plugin_registrar, Normal, template!(Word), Ungated), - - (sym::cfg, Normal, template!(List: "predicate"), Ungated), - (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - (sym::main, Normal, template!(Word), Ungated), - (sym::start, Normal, template!(Word), Ungated), - (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), - (sym::path, Normal, template!(NameValueStr: "file"), Ungated), - (sym::automatically_derived, Normal, template!(Word), Ungated), - (sym::no_mangle, Whitelisted, template!(Word), Ungated), - (sym::no_link, Normal, template!(Word), Ungated), - (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), - ( - sym::should_panic, - Normal, - template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), - Ungated - ), - (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), - (sym::no_implicit_prelude, Normal, template!(Word), Ungated), - (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), - (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - sym::link_args, - "the `link_args` attribute is experimental and not \ - portable across platforms, it is recommended to \ - use `#[link(name = \"foo\")] instead", - cfg_fn!(link_args))), - (sym::macro_escape, Normal, template!(Word), Ungated), - - // RFC #1445. - (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::structural_match, - "the semantics of constant patterns is \ - not yet settled", - cfg_fn!(structural_match))), - - // RFC #2008 - (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::non_exhaustive, - "non exhaustive is an experimental feature", - cfg_fn!(non_exhaustive))), - - // RFC #1268 - (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::marker_trait_attr, - "marker traits is an experimental feature", - cfg_fn!(marker_trait_attr))), - - (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - sym::plugin, - "compiler plugins are experimental \ - and possibly buggy", - cfg_fn!(plugin))), - - (sym::no_std, CrateLevel, template!(Word), Ungated), - (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, - sym::no_core, - "no_core is experimental", - cfg_fn!(no_core))), - (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - sym::lang_items, - "language items are subject to change", - cfg_fn!(lang_items))), - (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), - Gated(Stability::Unstable, - sym::linkage, - "the `linkage` attribute is experimental \ - and not portable across platforms", - cfg_fn!(linkage))), - (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::thread_local, - "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors", - cfg_fn!(thread_local))), - - (sym::rustc_on_unimplemented, Whitelisted, template!(List: - r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, - NameValueStr: "message"), - Gated(Stability::Unstable, - sym::on_unimplemented, - "the `#[rustc_on_unimplemented]` attribute \ - is an experimental feature", - cfg_fn!(on_unimplemented))), - (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), - Gated(Stability::Unstable, - sym::rustc_const_unstable, - "the `#[rustc_const_unstable]` attribute \ - is an internal feature", - cfg_fn!(rustc_const_unstable))), - (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[default_lib_allocator]` \ - attribute is an experimental feature", - cfg_fn!(allocator_internals))), - (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, - sym::allocator_internals, - "the `#[needs_allocator]` \ - attribute is an experimental \ - feature", - cfg_fn!(allocator_internals))), - (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::panic_runtime, - "the `#[panic_runtime]` attribute is \ - an experimental feature", - cfg_fn!(panic_runtime))), - (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::needs_panic_runtime, - "the `#[needs_panic_runtime]` \ - attribute is an experimental \ - feature", - cfg_fn!(needs_panic_runtime))), - (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_outlives]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_variance]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_start]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_layout_scalar_valid_range_end]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_nonnull_optimization_guaranteed]` attribute \ - is just used to enable niche optimizations in libcore \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_regions]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_error]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_if_this_changed]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dirty]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", - /*opt*/ except = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_clean]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_partition_reused, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs) - ) - ), - ( - sym::rustc_partition_codegened, - Whitelisted, - template!(List: r#"cfg = "...", module = "...""#), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", - kind = "...""#), - Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal rustc attributes will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_mir]` attribute \ - is just used for rustc unit tests \ - and will never be stable", - cfg_fn!(rustc_attrs))), - ( - sym::rustc_inherit_overflow_checks, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_inherit_overflow_checks]` \ - attribute is just used to control \ - overflow checking behavior of several \ - libcore functions that are inlined \ - across crates and will never be stable", - cfg_fn!(rustc_attrs), - ) - ), - - (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_dump_env_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_dump_env_program_clauses]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_object_lifetime_default, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_object_lifetime_default]` \ - attribute is just used for rustc unit \ - tests and will never be stable", - cfg_fn!(rustc_attrs))), - (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "the `#[rustc_test_marker]` attribute \ - is used internally to track tests", - cfg_fn!(rustc_attrs))), - (sym::rustc_macro_transparency, Whitelisted, template!(NameValueStr: - "transparent|semitransparent|opaque"), - Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally for testing macro hygiene", - cfg_fn!(rustc_attrs))), - (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::compiler_builtins, - "the `#[compiler_builtins]` attribute is used to \ - identify the `compiler_builtins` crate which \ - contains compiler-rt intrinsics and will never be \ - stable", - cfg_fn!(compiler_builtins))), - (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::sanitizer_runtime, - "the `#[sanitizer_runtime]` attribute is used to \ - identify crates that contain the runtime of a \ - sanitizer and will never be stable", - cfg_fn!(sanitizer_runtime))), - (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::profiler_runtime, - "the `#[profiler_runtime]` attribute is used to \ - identify the `profiler_builtins` crate which \ - contains the profiler runtime and will never be \ - stable", - cfg_fn!(profiler_runtime))), - - (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), - Gated(Stability::Unstable, - sym::allow_internal_unstable, - EXPLAIN_ALLOW_INTERNAL_UNSTABLE, - cfg_fn!(allow_internal_unstable))), - - (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_internal_unsafe, - EXPLAIN_ALLOW_INTERNAL_UNSAFE, - cfg_fn!(allow_internal_unsafe))), - - (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::fundamental, - "the `#[fundamental]` attribute \ - is an experimental feature", - cfg_fn!(fundamental))), - - (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ - /*opt*/ attributes(name1, name2, ...)"), - Ungated), - - (sym::rustc_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allocator_nounwind, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_builtin_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_promotable, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_allow_const_fn_ptr, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "internal implementation detail", - cfg_fn!(rustc_attrs))), - - (sym::rustc_dummy, Normal, template!(Word /* doesn't matter*/), Gated(Stability::Unstable, - sym::rustc_attrs, - "used by the test suite", - cfg_fn!(rustc_attrs))), - - // FIXME: #14408 whitelist docs since rustdoc looks at them - ( - sym::doc, - Whitelisted, - template!(List: "hidden|inline|...", NameValueStr: "string"), - Ungated - ), - - // FIXME: #14406 these are processed in codegen, which happens after the - // lint pass - (sym::cold, Whitelisted, template!(Word), Ungated), - (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::naked_functions, - "the `#[naked]` attribute \ - is an experimental feature", - cfg_fn!(naked_functions))), - (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::ffi_returns_twice, - "the `#[ffi_returns_twice]` attribute \ - is an experimental feature", - cfg_fn!(ffi_returns_twice))), - (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), - (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), - (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...""#), Ungated), - (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), - (sym::no_builtins, Whitelisted, template!(Word), Ungated), - (sym::no_debug, Whitelisted, template!(Word), Gated( - Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - sym::no_debug, - "the `#[no_debug]` attribute was an experimental feature that has been \ - deprecated due to lack of demand", - cfg_fn!(no_debug))), - ( - sym::omit_gdb_pretty_printer_section, - Whitelisted, - template!(Word), - Gated( - Stability::Unstable, - sym::omit_gdb_pretty_printer_section, - "the `#[omit_gdb_pretty_printer_section]` \ - attribute is just used for the Rust test \ - suite", - cfg_fn!(omit_gdb_pretty_printer_section) - ) - ), - (sym::may_dangle, - Normal, - template!(Word), - Gated(Stability::Unstable, - sym::dropck_eyepatch, - "`may_dangle` has unstable semantics and may be removed in the future", - cfg_fn!(dropck_eyepatch))), - (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, - sym::unwind_attributes, - "`#[unwind]` is experimental", - cfg_fn!(unwind_attributes))), - (sym::used, Whitelisted, template!(Word), Ungated), - - // used in resolve - (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::prelude_import, - "`#[prelude_import]` is for use by rustc only", - cfg_fn!(prelude_import))), - - // FIXME: #14407 these are only looked at on-demand so we can't - // guarantee they'll have already been checked - ( - sym::rustc_deprecated, - Whitelisted, - template!(List: r#"since = "version", reason = "...""#), - Ungated - ), - (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), - ( - sym::stable, - Whitelisted, - template!(List: r#"feature = "name", since = "version""#), - Ungated - ), - ( - sym::unstable, - Whitelisted, - template!(List: r#"feature = "name", reason = "...", issue = "N""#), - Ungated - ), - (sym::deprecated, - Normal, - template!( - Word, - List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, - NameValueStr: "reason" - ), - Ungated - ), - - (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, - sym::unboxed_closures, - "unboxed_closures are still evolving", - cfg_fn!(unboxed_closures))), - - (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), - - (sym::proc_macro_attribute, Normal, template!(Word), Ungated), - (sym::proc_macro, Normal, template!(Word), Ungated), - - (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "used internally by rustc", - cfg_fn!(rustc_attrs))), - - (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, - sym::allow_fail, - "allow_fail attribute is currently unstable", - cfg_fn!(allow_fail))), - - (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - // whitelists "identity-like" conversion methods to suggest on type mismatch - (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, - sym::rustc_attrs, - "this is an internal attribute that will \ - never be stable", - cfg_fn!(rustc_attrs))), - - ( - sym::rustc_args_required_const, - Whitelisted, - template!(List: "N"), - Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", - cfg_fn!(rustc_attrs)) - ), - // RFC 2070 - (sym::panic_handler, Normal, template!(Word), Ungated), - - (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, - sym::alloc_error_handler, - "`#[alloc_error_handler]` is an unstable feature", - cfg_fn!(alloc_error_handler))), - - // RFC 2412 - (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - sym::optimize_attribute, - "`#[optimize]` attribute is an unstable feature", - cfg_fn!(optimize_attribute))), - - // Crate level attributes - (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), - (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), - (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), - (sym::no_start, CrateLevel, template!(Word), Ungated), - (sym::no_main, CrateLevel, template!(Word), Ungated), - (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - sym::custom_test_frameworks, - "custom test frameworks are an unstable feature", - cfg_fn!(custom_test_frameworks))), -]; - -pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); - -lazy_static! { - pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { - let mut map = FxHashMap::default(); - for attr in BUILTIN_ATTRIBUTES.iter() { - if map.insert(attr.0, attr).is_some() { - panic!("duplicate builtin attribute `{}`", attr.0); - } - } - map - }; -} - -// cfg(...)'s that are feature gated -const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ - // (name in cfg, feature, function to check if the feature is enabled) - (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), - (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), - (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), - (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), -]; - -#[derive(Debug)] -pub struct GatedCfg { - span: Span, - index: usize, -} - -impl GatedCfg { - pub fn gate(cfg: &ast::MetaItem) -> Option { - GATED_CFGS.iter() - .position(|info| cfg.check_name(info.0)) - .map(|idx| { - GatedCfg { - span: cfg.span, - index: idx - } - }) - } - - pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { - let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !self.span.allows_unstable(feature) { - let explain = format!("`cfg({})` is experimental and subject to change", cfg); - emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); - } - } -} - -struct Context<'a> { - features: &'a Features, - parse_sess: &'a ParseSess, - plugin_attributes: &'a [(Symbol, AttributeType)], -} - -macro_rules! gate_feature_fn { - ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ - let (cx, has_feature, span, - name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); - let has_feature: bool = has_feature(&$cx.features); - debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !span.allows_unstable($name) { - leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) - .emit(); - } - }} -} - -macro_rules! gate_feature { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, GateStrength::Hard) - }; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { - gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - sym::$feature, $explain, $level) - }; -} - -impl<'a> Context<'a> { - fn check_attribute( - &self, - attr: &ast::Attribute, - attr_info: Option<&BuiltinAttribute>, - is_macro: bool - ) { - debug!("check_attribute(attr = {:?})", attr); - if let Some(&(name, ty, _template, ref gateage)) = attr_info { - if let Gated(_, name, desc, ref has_feature) = *gateage { - if !attr.span.allows_unstable(name) { - gate_feature_fn!( - self, has_feature, attr.span, name, desc, GateStrength::Hard - ); - } - } else if name == sym::doc { - if let Some(content) = attr.meta_item_list() { - if content.iter().any(|c| c.check_name(sym::include)) { - gate_feature!(self, external_doc, attr.span, - "`#[doc(include = \"...\")]` is experimental" - ); - } - } - } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); - return; - } else { - for segment in &attr.path.segments { - if segment.ident.as_str().starts_with("rustc") { - let msg = "attributes starting with `rustc` are \ - reserved for use by the `rustc` compiler"; - gate_feature!(self, rustc_attrs, segment.ident.span, msg); - } - } - } - for &(n, ty) in self.plugin_attributes { - if attr.path == n { - // Plugins can't gate attributes, so we don't check for it - // unlike the code above; we only use this loop to - // short-circuit to avoid the checks below. - debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); - return; - } - } - if !is_macro && !attr::is_known(attr) { - // Only run the custom attribute lint during regular feature gate - // checking. Macro gating runs before the plugin attributes are - // registered, so we skip this in that case. - let msg = format!("the attribute `{}` is currently unknown to the compiler and \ - may have meaning added to it in the future", attr.path); - gate_feature!(self, custom_attribute, attr.span, &msg); - } - } -} - -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { - let cx = Context { features, parse_sess, plugin_attributes: &[] }; - cx.check_attribute( - attr, - attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), - true - ); -} - -fn find_lang_feature_issue(feature: Symbol) -> Option { - if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { - let issue = info.2; - // FIXME (#28244): enforce that active features have issue numbers - // assert!(issue.is_some()) - issue - } else { - // search in Accepted, Removed, or Stable Removed features - let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) - .find(|t| t.0 == feature); - match found { - Some(&(_, _, issue, _)) => issue, - None => panic!("Feature `{}` is not declared anywhere", feature), - } - } -} - -pub enum GateIssue { - Language, - Library(Option) -} - -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum GateStrength { - /// A hard error. (Most feature gates should use this.) - Hard, - /// Only a warning. (Use this only as backwards-compatibility demands.) - Soft, -} - -pub fn emit_feature_err( - sess: &ParseSess, - feature: Symbol, - span: Span, - issue: GateIssue, - explain: &str, -) { - feature_err(sess, feature, span, issue, explain).emit(); -} - -pub fn feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, -) -> DiagnosticBuilder<'a> { - leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) -} - -fn leveled_feature_err<'a, S: Into>( - sess: &'a ParseSess, - feature: Symbol, - span: S, - issue: GateIssue, - explain: &str, - level: GateStrength, -) -> DiagnosticBuilder<'a> { - let diag = &sess.span_diagnostic; - - let issue = match issue { - GateIssue::Language => find_lang_feature_issue(feature), - GateIssue::Library(lib) => lib, - }; - - let mut err = match level { - GateStrength::Hard => { - diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) - } - GateStrength::Soft => diag.struct_span_warn(span, explain), - }; - - match issue { - None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility - Some(n) => { - err.note(&format!( - "for more information, see https://github.com/rust-lang/rust/issues/{}", - n, - )); - } - } - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); - } - - // If we're on stable and only emitting a "soft" warning, add a note to - // clarify that the feature isn't "on" (rather than being on but - // warning-worthy). - if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { - err.help("a nightly build of the compiler is required to enable this feature"); - } - - err - -} - -const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead"; - -pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental"; - -pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = - "allow_internal_unstable side-steps feature gating and stability checks"; -pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = - "allow_internal_unsafe side-steps the unsafe_code lint"; - -pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = - "unsized tuple coercion is not stable enough for use and is subject to change"; - -struct PostExpansionVisitor<'a> { - context: &'a Context<'a>, - builtin_attributes: &'static FxHashMap, -} - -macro_rules! gate_feature_post { - ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain) - } - }}; - ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ - let (cx, span) = ($cx, $span); - if !span.allows_unstable(sym::$feature) { - gate_feature!(cx.context, $feature, span, $explain, $level) - } - }} -} - -impl<'a> PostExpansionVisitor<'a> { - fn check_abi(&self, abi: Abi, span: Span) { - match abi { - Abi::RustIntrinsic => { - gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"); - }, - Abi::PlatformIntrinsic => { - gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy"); - }, - Abi::Vectorcall => { - gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change"); - }, - Abi::Thiscall => { - gate_feature_post!(&self, abi_thiscall, span, - "thiscall is experimental and subject to change"); - }, - Abi::RustCall => { - gate_feature_post!(&self, unboxed_closures, span, - "rust-call ABI is subject to change"); - }, - Abi::PtxKernel => { - gate_feature_post!(&self, abi_ptx, span, - "PTX ABIs are experimental and subject to change"); - }, - Abi::Unadjusted => { - gate_feature_post!(&self, abi_unadjusted, span, - "unadjusted ABI is an implementation detail and perma-unstable"); - }, - Abi::Msp430Interrupt => { - gate_feature_post!(&self, abi_msp430_interrupt, span, - "msp430-interrupt ABI is experimental and subject to change"); - }, - Abi::X86Interrupt => { - gate_feature_post!(&self, abi_x86_interrupt, span, - "x86-interrupt ABI is experimental and subject to change"); - }, - Abi::AmdGpuKernel => { - gate_feature_post!(&self, abi_amdgpu_kernel, span, - "amdgpu-kernel ABI is experimental and subject to change"); - }, - // Stable - Abi::Cdecl | - Abi::Stdcall | - Abi::Fastcall | - Abi::Aapcs | - Abi::Win64 | - Abi::SysV64 | - Abi::Rust | - Abi::C | - Abi::System => {} - } - } -} - -impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { - fn visit_attribute(&mut self, attr: &ast::Attribute) { - let attr_info = attr.ident().and_then(|ident| { - self.builtin_attributes.get(&ident.name).map(|a| *a) - }); - - // Check for gated attributes. - self.context.check_attribute(attr, attr_info, false); - - if attr.check_name(sym::doc) { - if let Some(content) = attr.meta_item_list() { - if content.len() == 1 && content[0].check_name(sym::cfg) { - gate_feature_post!(&self, doc_cfg, attr.span, - "`#[doc(cfg(...))]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::masked)) { - gate_feature_post!(&self, doc_masked, attr.span, - "`#[doc(masked)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::spotlight)) { - gate_feature_post!(&self, doc_spotlight, attr.span, - "`#[doc(spotlight)]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::alias)) { - gate_feature_post!(&self, doc_alias, attr.span, - "`#[doc(alias = \"...\")]` is experimental" - ); - } else if content.iter().any(|c| c.check_name(sym::keyword)) { - gate_feature_post!(&self, doc_keyword, attr.span, - "`#[doc(keyword = \"...\")]` is experimental" - ); - } - } - } - - match attr_info { - // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some(&(name, _, template, _)) if name != sym::rustc_dummy => - check_builtin_attribute(self.context.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); - } - } - } - } - - fn visit_name(&mut self, sp: Span, name: ast::Name) { - if !name.as_str().is_ascii() { - gate_feature_post!( - &self, - non_ascii_idents, - self.context.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported" - ); - } - } - - fn visit_item(&mut self, i: &'a ast::Item) { - match i.node { - ast::ItemKind::ForeignMod(ref foreign_module) => { - self.check_abi(foreign_module.abi, i.span); - } - - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { - gate_feature_post!(&self, plugin_registrar, i.span, - "compiler plugins are experimental and possibly buggy"); - } - if attr::contains_name(&i.attrs[..], sym::start) { - gate_feature_post!(&self, start, i.span, - "a `#[start]` function is an experimental \ - feature whose signature may change \ - over time"); - } - if attr::contains_name(&i.attrs[..], sym::main) { - gate_feature_post!(&self, main, i.span, - "declaration of a non-standard `#[main]` \ - function may change over time, for now \ - a top-level `fn main()` is required"); - } - } - - ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(sym::simd) { - gate_feature_post!(&self, repr_simd, attr.span, - "SIMD types are experimental and possibly buggy"); - } - } - } - } - - ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { - for variant in variants { - match (&variant.data, &variant.disr_expr) { - (ast::VariantData::Unit(..), _) => {}, - (_, Some(disr_expr)) => - gate_feature_post!( - &self, - arbitrary_enum_discriminant, - disr_expr.value.span, - "discriminants on non-unit variants are experimental"), - _ => {}, - } - } - - let has_feature = self.context.features.arbitrary_enum_discriminant; - if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { - Parser::maybe_report_invalid_custom_discriminants( - self.context.parse_sess, - &variants, - ); - } - } - - ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { - if polarity == ast::ImplPolarity::Negative { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "negative trait bounds are not yet fully implemented; \ - use marker types for now"); - } - - if let ast::Defaultness::Default = defaultness { - gate_feature_post!(&self, specialization, - i.span, - "specialization is unstable"); - } - } - - ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { - gate_feature_post!(&self, optin_builtin_traits, - i.span, - "auto traits are experimental and possibly buggy"); - } - - ast::ItemKind::TraitAlias(..) => { - gate_feature_post!( - &self, - trait_alias, - i.span, - "trait aliases are experimental" - ); - } - - ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { - let msg = "`macro` is experimental"; - gate_feature_post!(&self, decl_macro, i.span, msg); - } - - ast::ItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - i.span, - "`impl Trait` in type aliases is unstable" - ); - } - - _ => {} - } - - visit::walk_item(self, i); - } - - fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { - match i.node { - ast::ForeignItemKind::Fn(..) | - ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); - let links_to_llvm = match link_name { - Some(val) => val.as_str().starts_with("llvm."), - _ => false - }; - if links_to_llvm { - gate_feature_post!(&self, link_llvm_intrinsics, i.span, - "linking to LLVM intrinsics is experimental"); - } - } - ast::ForeignItemKind::Ty => { - gate_feature_post!(&self, extern_types, i.span, - "extern types are experimental"); - } - ast::ForeignItemKind::Macro(..) => {} - } - - visit::walk_foreign_item(self, i) - } - - fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyKind::BareFn(ref bare_fn_ty) => { - self.check_abi(bare_fn_ty.abi, ty.span); - } - ast::TyKind::Never => { - gate_feature_post!(&self, never_type, ty.span, - "The `!` type is experimental"); - } - _ => {} - } - visit::walk_ty(self, ty) - } - - fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { - if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { - if let ast::TyKind::Never = output_ty.node { - // Do nothing. - } else { - self.visit_ty(output_ty) - } - } - } - - fn visit_expr(&mut self, e: &'a ast::Expr) { - match e.node { - ast::ExprKind::Box(_) => { - gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); - } - ast::ExprKind::Type(..) => { - // To avoid noise about type ascription in common syntax errors, only emit if it - // is the *only* error. - if self.context.parse_sess.span_diagnostic.err_count() == 0 { - gate_feature_post!(&self, type_ascription, e.span, - "type ascription is experimental"); - } - } - ast::ExprKind::TryBlock(_) => { - gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); - } - ast::ExprKind::Block(_, opt_label) => { - if let Some(label) = opt_label { - gate_feature_post!(&self, label_break_value, label.ident.span, - "labels on blocks are unstable"); - } - } - _ => {} - } - visit::walk_expr(self, e) - } - - fn visit_arm(&mut self, arm: &'a ast::Arm) { - visit::walk_arm(self, arm) - } - - fn visit_pat(&mut self, pattern: &'a ast::Pat) { - match &pattern.node { - PatKind::Slice(pats) => { - for pat in &*pats { - let span = pat.span; - let inner_pat = match &pat.node { - PatKind::Ident(.., Some(pat)) => pat, - _ => pat, - }; - if inner_pat.is_rest() { - gate_feature_post!( - &self, - slice_patterns, - span, - "subslice patterns are unstable" - ); - } - } - } - PatKind::Box(..) => { - gate_feature_post!(&self, box_patterns, - pattern.span, - "box pattern syntax is experimental"); - } - PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { - gate_feature_post!(&self, exclusive_range_pattern, pattern.span, - "exclusive range pattern syntax is experimental"); - } - _ => {} - } - visit::walk_pat(self, pattern) - } - - fn visit_fn(&mut self, - fn_kind: FnKind<'a>, - fn_decl: &'a ast::FnDecl, - span: Span, - _node_id: NodeId) { - if let Some(header) = fn_kind.header() { - // Stability of const fn methods are covered in - // `visit_trait_item` and `visit_impl_item` below; this is - // because default methods don't pass through this point. - self.check_abi(header.abi, span); - } - - if fn_decl.c_variadic { - gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); - } - - visit::walk_fn(self, fn_kind, fn_decl, span) - } - - fn visit_generic_param(&mut self, param: &'a GenericParam) { - match param.kind { - GenericParamKind::Const { .. } => - gate_feature_post!(&self, const_generics, param.ident.span, - "const generics are unstable"), - _ => {} - } - visit::walk_generic_param(self, param) - } - - fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { - match constraint.kind { - AssocTyConstraintKind::Bound { .. } => - gate_feature_post!(&self, associated_type_bounds, constraint.span, - "associated type bounds are unstable"), - _ => {} - } - visit::walk_assoc_ty_constraint(self, constraint) - } - - fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { - match ti.node { - ast::TraitItemKind::Method(ref sig, ref block) => { - if block.is_none() { - self.check_abi(sig.header.abi, ti.span); - } - if sig.decl.c_variadic { - gate_feature_post!(&self, c_variadic, ti.span, - "C-variadic functions are unstable"); - } - if sig.header.constness.node == ast::Constness::Const { - gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); - } - } - ast::TraitItemKind::Type(_, ref default) => { - // We use three if statements instead of something like match guards so that all - // of these errors can be emitted if all cases apply. - if default.is_some() { - gate_feature_post!(&self, associated_type_defaults, ti.span, - "associated type defaults are unstable"); - } - if !ti.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "generic associated types are unstable"); - } - if !ti.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ti.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_trait_item(self, ti) - } - - fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { - if ii.defaultness == ast::Defaultness::Default { - gate_feature_post!(&self, specialization, - ii.span, - "specialization is unstable"); - } - - match ii.node { - ast::ImplItemKind::Method(..) => {} - ast::ImplItemKind::OpaqueTy(..) => { - gate_feature_post!( - &self, - type_alias_impl_trait, - ii.span, - "`impl Trait` in type aliases is unstable" - ); - } - ast::ImplItemKind::TyAlias(_) => { - if !ii.generics.params.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "generic associated types are unstable"); - } - if !ii.generics.where_clause.predicates.is_empty() { - gate_feature_post!(&self, generic_associated_types, ii.span, - "where clauses on associated types are unstable"); - } - } - _ => {} - } - visit::walk_impl_item(self, ii) - } - - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { - gate_feature_post!(&self, crate_visibility_modifier, vis.span, - "`crate` visibility modifier is experimental"); - } - visit::walk_vis(self, vis) - } -} - -pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], - crate_edition: Edition, allow_features: &Option>) -> Features { - fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { - let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); - if let Some(reason) = reason { - err.span_note(span, reason); - } else { - err.span_label(span, "feature has been removed"); - } - err.emit(); - } - - let mut features = Features::new(); - let mut edition_enabled_features = FxHashMap::default(); - - for &edition in ALL_EDITIONS { - if edition <= crate_edition { - // The `crate_edition` implies its respective umbrella feature-gate - // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(edition.feature_name(), edition); - } - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= crate_edition { - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, crate_edition); - } - } - } - - // Process the edition umbrella feature-gates first, to ensure - // `edition_enabled_features` is completed before it's queried. - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - for mi in list { - if !mi.is_word() { - continue; - } - - let name = mi.name_or_empty(); - - if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) { - if *edition <= crate_edition { - continue; - } - - for &(name, .., f_edition, set) in ACTIVE_FEATURES { - if let Some(f_edition) = f_edition { - if f_edition <= *edition { - // FIXME(Manishearth) there is currently no way to set - // lib features by edition - set(&mut features, DUMMY_SP); - edition_enabled_features.insert(name, *edition); - } - } - } - } - } - } - - for attr in krate_attrs { - if !attr.check_name(sym::feature) { - continue - } - - let list = match attr.meta_item_list() { - Some(list) => list, - None => continue, - }; - - let bad_input = |span| { - struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") - }; - - for mi in list { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - bad_input(mi.span()).span_suggestion( - mi.span(), - "expected just one word", - format!("{}", ident.name), - Applicability::MaybeIncorrect, - ).emit(); - continue - } - None => { - bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); - continue - } - }; - - if let Some(edition) = edition_enabled_features.get(&name) { - struct_span_warn!( - span_handler, - mi.span(), - E0705, - "the feature `{}` is included in the Rust {} edition", - name, - edition, - ).emit(); - continue; - } - - if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { - // Handled in the separate loop above. - continue; - } - - let removed = REMOVED_FEATURES.iter().find(|f| name == f.0); - let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0); - if let Some((.., reason)) = removed.or(stable_removed) { - feature_removed(span_handler, mi.span(), *reason); - continue; - } - - if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) { - let since = Some(Symbol::intern(since)); - features.declared_lang_features.push((name, mi.span(), since)); - continue; - } - - if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|f| *f == name.as_str()).is_none() { - span_err!(span_handler, mi.span(), E0725, - "the feature `{}` is not in the list of allowed features", - name); - continue; - } - } - - if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) { - set(&mut features, mi.span()); - features.declared_lang_features.push((name, mi.span(), None)); - continue; - } - - features.declared_lib_features.push((name, mi.span())); - } - } - - features -} - -pub fn check_crate(krate: &ast::Crate, - sess: &ParseSess, - features: &Features, - plugin_attributes: &[(Symbol, AttributeType)], - unstable: UnstableFeatures) { - maybe_stage_features(&sess.span_diagnostic, krate, unstable); - let ctx = Context { - features, - parse_sess: sess, - plugin_attributes, - }; - - macro_rules! gate_all { - ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*sess.$spans.borrow() { gate_feature!(&ctx, $gate, *span, $msg); } - } - } - - gate_all!(param_attr_spans, param_attrs, "attributes on function parameters are unstable"); - gate_all!(let_chains_spans, let_chains, "`let` expressions in this position are experimental"); - gate_all!(async_closure_spans, async_closure, "async closures are unstable"); - gate_all!(yield_spans, generators, "yield syntax is experimental"); - gate_all!(or_pattern_spans, or_patterns, "or-patterns syntax is experimental"); - - let visitor = &mut PostExpansionVisitor { - context: &ctx, - builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, - }; - visit::walk_crate(visitor, krate); -} - -#[derive(Clone, Copy, Hash)] -pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on beta/stable channels. - Disallow, - /// Allow features to be activated, as on nightly. - Allow, - /// Errors are bypassed for bootstrapping. This is required any time - /// during the build that feature-related lints are set to warn or above - /// because the build turns on warnings-as-errors and uses lots of unstable - /// features. As a result, this is always required for building Rust itself. - Cheat -} - -impl UnstableFeatures { - pub fn from_environment() -> UnstableFeatures { - // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); - // Whether we should enable unstable features for bootstrapping - let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - match (disable_unstable_features, bootstrap) { - (_, true) => UnstableFeatures::Cheat, - (true, _) => UnstableFeatures::Disallow, - (false, _) => UnstableFeatures::Allow - } - } - - pub fn is_nightly_build(&self) -> bool { - match *self { - UnstableFeatures::Allow | UnstableFeatures::Cheat => true, - _ => false, - } - } -} - -fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, - unstable: UnstableFeatures) { - let allow_features = match unstable { - UnstableFeatures::Allow => true, - UnstableFeatures::Disallow => false, - UnstableFeatures::Cheat => true - }; - if !allow_features { - for attr in &krate.attrs { - if attr.check_name(sym::feature) { - let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); - span_err!(span_handler, attr.span, E0554, - "`#![feature]` may not be used on the {} release channel", - release_channel); - } - } - } -} diff --git a/src/libsyntax/feature_gate/accepted.rs b/src/libsyntax/feature_gate/accepted.rs new file mode 100644 index 0000000000000..6c0b271c6c5e9 --- /dev/null +++ b/src/libsyntax/feature_gate/accepted.rs @@ -0,0 +1,248 @@ +//! List of the accepted feature gates. + +use crate::symbol::sym; +use super::{State, Feature}; + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { + /// Those language feature has since been Accepted (it was once Active) + pub const ACCEPTED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Accepted, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + } +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: for testing purposes + // ------------------------------------------------------------------------- + + /// A temporary feature gate used to enable parser extensions needed + /// to bootstrap fix for #5723. + (accepted, issue_5723_bootstrap, "1.0.0", None, None), + /// These are used to test this portion of the compiler, + /// they don't actually mean anything. + (accepted, test_accepted_feature, "1.0.0", None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: for testing purposes + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: accepted features + // ------------------------------------------------------------------------- + + /// Allows using associated `type`s in `trait`s. + (accepted, associated_types, "1.0.0", None, None), + /// Allows using assigning a default type to type parameters in algebraic data type definitions. + (accepted, default_type_params, "1.0.0", None, None), + // FIXME: explain `globs`. + (accepted, globs, "1.0.0", None, None), + /// Allows `macro_rules!` items. + (accepted, macro_rules, "1.0.0", None, None), + /// Allows use of `&foo[a..b]` as a slicing syntax. + (accepted, slicing_syntax, "1.0.0", None, None), + /// Allows struct variants `Foo { baz: u8, .. }` in enums (RFC 418). + (accepted, struct_variant, "1.0.0", None, None), + /// Allows indexing tuples. + (accepted, tuple_indexing, "1.0.0", None, None), + /// Allows the use of `if let` expressions. + (accepted, if_let, "1.0.0", None, None), + /// Allows the use of `while let` expressions. + (accepted, while_let, "1.0.0", None, None), + /// Allows using `#![no_std]`. + (accepted, no_std, "1.6.0", None, None), + /// Allows overloading augmented assignment operations like `a += b`. + (accepted, augmented_assignments, "1.8.0", Some(28235), None), + /// Allows empty structs and enum variants with braces. + (accepted, braced_empty_structs, "1.8.0", Some(29720), None), + /// Allows `#[deprecated]` attribute. + (accepted, deprecated, "1.9.0", Some(29935), None), + /// Allows macros to appear in the type position. + (accepted, type_macros, "1.13.0", Some(27245), None), + /// Allows use of the postfix `?` operator in expressions. + (accepted, question_mark, "1.13.0", Some(31436), None), + /// Allows `..` in tuple (struct) patterns. + (accepted, dotdot_in_tuple_patterns, "1.14.0", Some(33627), None), + /// Allows some increased flexibility in the name resolution rules, + /// especially around globs and shadowing (RFC 1560). + (accepted, item_like_imports, "1.15.0", Some(35120), None), + /// Allows using `Self` and associated types in struct expressions and patterns. + (accepted, more_struct_aliases, "1.16.0", Some(37544), None), + /// Allows elision of `'static` lifetimes in `static`s and `const`s. + (accepted, static_in_const, "1.17.0", Some(35897), None), + /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions. + (accepted, field_init_shorthand, "1.17.0", Some(37340), None), + /// Allows the definition recursive static items. + (accepted, static_recursion, "1.17.0", Some(29719), None), + /// Allows `pub(restricted)` visibilities (RFC 1422). + (accepted, pub_restricted, "1.18.0", Some(32409), None), + /// Allows `#![windows_subsystem]`. + (accepted, windows_subsystem, "1.18.0", Some(37499), None), + /// Allows `break {expr}` with a value inside `loop`s. + (accepted, loop_break_value, "1.19.0", Some(37339), None), + /// Allows numeric fields in struct expressions and patterns. + (accepted, relaxed_adts, "1.19.0", Some(35626), None), + /// Allows coercing non capturing closures to function pointers. + (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), + /// Allows attributes on struct literal fields. + (accepted, struct_field_attributes, "1.20.0", Some(38814), None), + /// Allows the definition of associated constants in `trait` or `impl` blocks. + (accepted, associated_consts, "1.20.0", Some(29646), None), + /// Allows usage of the `compile_error!` macro. + (accepted, compile_error, "1.20.0", Some(40872), None), + /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). + (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), + /// Allows `Drop` types in constants (RFC 1440). + (accepted, drop_types_in_const, "1.22.0", Some(33156), None), + /// Allows the sysV64 ABI to be specified on all platforms + /// instead of just the platforms on which it is the C ABI. + (accepted, abi_sysv64, "1.24.0", Some(36167), None), + /// Allows `repr(align(16))` struct attribute (RFC 1358). + (accepted, repr_align, "1.25.0", Some(33626), None), + /// Allows '|' at beginning of match arms (RFC 1925). + (accepted, match_beginning_vert, "1.25.0", Some(44101), None), + /// Allows nested groups in `use` items (RFC 2128). + (accepted, use_nested_groups, "1.25.0", Some(44494), None), + /// Allows indexing into constant arrays. + (accepted, const_indexing, "1.26.0", Some(29947), None), + /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. + (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), + /// Allows `..=` in patterns (RFC 1192). + (accepted, dotdoteq_in_patterns, "1.26.0", Some(28237), None), + /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). + (accepted, termination_trait, "1.26.0", Some(43301), None), + /// Allows implementing `Clone` for closures where possible (RFC 2132). + (accepted, clone_closures, "1.26.0", Some(44490), None), + /// Allows implementing `Copy` for closures where possible (RFC 2132). + (accepted, copy_closures, "1.26.0", Some(44490), None), + /// Allows `impl Trait` in function arguments. + (accepted, universal_impl_trait, "1.26.0", Some(34511), None), + /// Allows `impl Trait` in function return types. + (accepted, conservative_impl_trait, "1.26.0", Some(34511), None), + /// Allows using the `u128` and `i128` types. + (accepted, i128_type, "1.26.0", Some(35118), None), + /// Allows default match binding modes (RFC 2005). + (accepted, match_default_bindings, "1.26.0", Some(42640), None), + /// Allows `'_` placeholder lifetimes. + (accepted, underscore_lifetimes, "1.26.0", Some(44524), None), + /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). + (accepted, generic_param_attrs, "1.27.0", Some(48848), None), + /// Allows `cfg(target_feature = "...")`. + (accepted, cfg_target_feature, "1.27.0", Some(29717), None), + /// Allows `#[target_feature(...)]`. + (accepted, target_feature, "1.27.0", None, None), + /// Allows using `dyn Trait` as a syntax for trait objects. + (accepted, dyn_trait, "1.27.0", Some(44662), None), + /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940). + (accepted, fn_must_use, "1.27.0", Some(43302), None), + /// Allows use of the `:lifetime` macro fragment specifier. + (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None), + /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). + (accepted, termination_trait_test, "1.27.0", Some(48854), None), + /// Allows the `#[global_allocator]` attribute. + (accepted, global_allocator, "1.28.0", Some(27389), None), + /// Allows `#[repr(transparent)]` attribute on newtype structs. + (accepted, repr_transparent, "1.28.0", Some(43036), None), + /// Allows procedural macros in `proc-macro` crates. + (accepted, proc_macro, "1.29.0", Some(38356), None), + /// Allows `foo.rs` as an alternative to `foo/mod.rs`. + (accepted, non_modrs_mods, "1.30.0", Some(44660), None), + /// Allows use of the `:vis` macro fragment specifier + (accepted, macro_vis_matcher, "1.30.0", Some(41022), None), + /// Allows importing and reexporting macros with `use`, + /// enables macro modularization in general. + (accepted, use_extern_macros, "1.30.0", Some(35896), None), + /// Allows keywords to be escaped for use as identifiers. + (accepted, raw_identifiers, "1.30.0", Some(48589), None), + /// Allows attributes scoped to tools. + (accepted, tool_attributes, "1.30.0", Some(44690), None), + /// Allows multi-segment paths in attributes and derives. + (accepted, proc_macro_path_invoc, "1.30.0", Some(38356), None), + /// Allows all literals in attribute lists and values of key-value pairs. + (accepted, attr_literals, "1.30.0", Some(34981), None), + /// Allows inferring outlives requirements (RFC 2093). + (accepted, infer_outlives_requirements, "1.30.0", Some(44493), None), + /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. + /// This defines the behavior of panics. + (accepted, panic_handler, "1.30.0", Some(44489), None), + /// Allows `#[used]` to preserve symbols (see llvm.used). + (accepted, used, "1.30.0", Some(40289), None), + /// Allows `crate` in paths. + (accepted, crate_in_paths, "1.30.0", Some(45477), None), + /// Allows resolving absolute paths as paths from other crates. + (accepted, extern_absolute_paths, "1.30.0", Some(44660), None), + /// Allows access to crate names passed via `--extern` through prelude. + (accepted, extern_prelude, "1.30.0", Some(44660), None), + /// Allows parentheses in patterns. + (accepted, pattern_parentheses, "1.31.0", Some(51087), None), + /// Allows the definition of `const fn` functions. + (accepted, min_const_fn, "1.31.0", Some(53555), None), + /// Allows scoped lints. + (accepted, tool_lints, "1.31.0", Some(44690), None), + /// Allows lifetime elision in `impl` headers. For example: + /// + `impl Iterator for &mut Iterator` + /// + `impl Debug for Foo<'_>` + (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), + /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. + (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), + /// Allows use of the `:literal` macro fragment specifier (RFC 1576). + (accepted, macro_literal_matcher, "1.32.0", Some(35625), None), + /// Allows use of `?` as the Kleene "at most one" operator in macros. + (accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None), + /// Allows `Self` struct constructor (RFC 2302). + (accepted, self_struct_ctor, "1.32.0", Some(51994), None), + /// Allows `Self` in type definitions (RFC 2300). + (accepted, self_in_typedefs, "1.32.0", Some(49303), None), + /// Allows `use x::y;` to search `x` in the current scope. + (accepted, uniform_paths, "1.32.0", Some(53130), None), + /// Allows integer match exhaustiveness checking (RFC 2591). + (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907), None), + /// Allows `use path as _;` and `extern crate c as _;`. + (accepted, underscore_imports, "1.33.0", Some(48216), None), + /// Allows `#[repr(packed(N))]` attribute on structs. + (accepted, repr_packed, "1.33.0", Some(33158), None), + /// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086). + (accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None), + /// Allows calling `const unsafe fn` inside `unsafe` blocks in `const fn` functions. + (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), + /// Allows let bindings, assignments and destructuring in `const` functions and constants. + /// As long as control flow is not implemented in const eval, `&&` and `||` may not be used + /// at the same time as let bindings. + (accepted, const_let, "1.33.0", Some(48821), None), + /// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`. + (accepted, cfg_attr_multi, "1.33.0", Some(54881), None), + /// Allows top level or-patterns (`p | q`) in `if let` and `while let`. + (accepted, if_while_or_patterns, "1.33.0", Some(48215), None), + /// Allows `cfg(target_vendor = "...")`. + (accepted, cfg_target_vendor, "1.33.0", Some(29718), None), + /// Allows `extern crate self as foo;`. + /// This puts local crate root into extern prelude under name `foo`. + (accepted, extern_crate_self, "1.34.0", Some(56409), None), + /// Allows arbitrary delimited token streams in non-macro attributes. + (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), + /// Allows paths to enum variants on type aliases including `Self`. + (accepted, type_alias_enum_variants, "1.37.0", Some(49683), None), + /// Allows using `#[repr(align(X))]` on enums with equivalent semantics + /// to wrapping an enum in a wrapper struct with `#[repr(align(X))]`. + (accepted, repr_align_enum, "1.37.0", Some(57996), None), + /// Allows `const _: TYPE = VALUE`. + (accepted, underscore_const_names, "1.37.0", Some(54912), None), + /// Allows free and inherent `async fn`s, `async` blocks, and `.await` expressions. + (accepted, async_await, "1.39.0", Some(50547), None), + + // ------------------------------------------------------------------------- + // feature-group-end: accepted features + // ------------------------------------------------------------------------- +); diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs new file mode 100644 index 0000000000000..c947b09fdcb57 --- /dev/null +++ b/src/libsyntax/feature_gate/active.rs @@ -0,0 +1,549 @@ +//! List of the active feature gates. + +use crate::edition::Edition; +use crate::symbol::{Symbol, sym}; +use syntax_pos::Span; +use super::{State, Feature}; + +macro_rules! set { + ($field: ident) => {{ + fn f(features: &mut Features, _: Span) { + features.$field = true; + } + f as fn(&mut Features, Span) + }} +} + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (active, $feature:ident, $ver:expr, $issue:expr, $edition:expr), + )+) => { + /// Represents active features that are currently being implemented or + /// currently being considered for addition/removal. + pub const ACTIVE_FEATURES: + &[Feature] = + &[$( + // (sym::$feature, $ver, $issue, $edition, set!($feature)) + Feature { + state: State::Active { set: set!($feature) }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: $edition, + description: concat!($($doc,)*), + } + ),+]; + + /// A set of features to be used by later passes. + #[derive(Clone)] + pub struct Features { + /// `#![feature]` attrs for language features, for error reporting + pub declared_lang_features: Vec<(Symbol, Span, Option)>, + /// `#![feature]` attrs for non-language (library) features + pub declared_lib_features: Vec<(Symbol, Span)>, + $( + $(#[doc = $doc])* + pub $feature: bool + ),+ + } + + impl Features { + pub fn new() -> Features { + Features { + declared_lang_features: Vec::new(), + declared_lib_features: Vec::new(), + $($feature: false),+ + } + } + + pub fn walk_feature_fields(&self, mut f: F) + where F: FnMut(&str, bool) + { + $(f(stringify!($feature), self.$feature);)+ + } + } + }; +} + +impl Feature { + /// Set this feature in `Features`. Panics if called on a non-active feature. + pub fn set(&self, features: &mut Features, span: Span) { + match self.state { + State::Active { set } => set(features, span), + _ => panic!("Called `set` on feature `{}` which is not `active`", self.name) + } + } +} + +// If you change this, please modify `src/doc/unstable-book` as well. +// +// Don't ever remove anything from this list; move them to `removed.rs`. +// +// The version numbers here correspond to the version in which the current status +// was set. This is most important for knowing when a particular feature became +// stable (active). +// +// Note that the features are grouped into internal/user-facing and then +// sorted by version inside those groups. This is enforced with tidy. +// +// N.B., `tools/tidy/src/features.rs` parses this information directly out of the +// source, so take care when modifying it. + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: internal feature gates + // ------------------------------------------------------------------------- + + // no-tracking-issue-start + + /// Allows using compiler's own crates. + (active, rustc_private, "1.0.0", Some(27812), None), + + /// Allows using the `rust-intrinsic`'s "ABI". + (active, intrinsics, "1.0.0", None, None), + + /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. + (active, lang_items, "1.0.0", None, None), + + /// Allows using the `#[stable]` and `#[unstable]` attributes. + (active, staged_api, "1.0.0", None, None), + + /// Allows using `#[allow_internal_unstable]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). + (active, allow_internal_unstable, "1.0.0", None, None), + + /// Allows using `#[allow_internal_unsafe]`. This is an + /// attribute on `macro_rules!` and can't use the attribute handling + /// below (it has to be checked before expansion possibly makes + /// macros disappear). + (active, allow_internal_unsafe, "1.0.0", None, None), + + /// Allows using the macros: + /// + `__diagnostic_used` + /// + `__register_diagnostic` + /// +`__build_diagnostic_array` + (active, rustc_diagnostic_macros, "1.0.0", None, None), + + /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which + /// lets a function to be `const` when opted into with `#![feature(foo)]`. + (active, rustc_const_unstable, "1.0.0", None, None), + + /// no-tracking-issue-end + + /// Allows using `#[link_name="llvm.*"]`. + (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), + + /// Allows using `rustc_*` attributes (RFC 572). + (active, rustc_attrs, "1.0.0", Some(29642), None), + + /// Allows using `#[on_unimplemented(..)]` on traits. + (active, on_unimplemented, "1.0.0", Some(29628), None), + + /// Allows using the `box $expr` syntax. + (active, box_syntax, "1.0.0", Some(49733), None), + + /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. + (active, main, "1.0.0", Some(29634), None), + + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. + (active, start, "1.0.0", Some(29633), None), + + /// Allows using the `#[fundamental]` attribute. + (active, fundamental, "1.0.0", Some(29635), None), + + /// Allows using the `rust-call` ABI. + (active, unboxed_closures, "1.0.0", Some(29625), None), + + /// Allows using the `#[linkage = ".."]` attribute. + (active, linkage, "1.0.0", Some(29603), None), + + /// Allows features specific to OIBIT (auto traits). + (active, optin_builtin_traits, "1.0.0", Some(13231), None), + + /// Allows using `box` in patterns (RFC 469). + (active, box_patterns, "1.0.0", Some(29641), None), + + // no-tracking-issue-start + + /// Allows using `#[prelude_import]` on glob `use` items. + (active, prelude_import, "1.2.0", None, None), + + // no-tracking-issue-end + + // no-tracking-issue-start + + /// Allows using `#[omit_gdb_pretty_printer_section]`. + (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), + + /// Allows using the `vectorcall` ABI. + (active, abi_vectorcall, "1.7.0", None, None), + + // no-tracking-issue-end + + /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. + (active, structural_match, "1.8.0", Some(31434), None), + + /// Allows using the `may_dangle` attribute (RFC 1327). + (active, dropck_eyepatch, "1.10.0", Some(34761), None), + + /// Allows using the `#![panic_runtime]` attribute. + (active, panic_runtime, "1.10.0", Some(32837), None), + + /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. + (active, needs_panic_runtime, "1.10.0", Some(32837), None), + + // no-tracking-issue-start + + /// Allows identifying the `compiler_builtins` crate. + (active, compiler_builtins, "1.13.0", None, None), + + /// Allows using the `unadjusted` ABI; perma-unstable. + (active, abi_unadjusted, "1.16.0", None, None), + + /// Allows identifying crates that contain sanitizer runtimes. + (active, sanitizer_runtime, "1.17.0", None, None), + + /// Used to identify crates that contain the profiler runtime. + (active, profiler_runtime, "1.18.0", None, None), + + /// Allows using the `thiscall` ABI. + (active, abi_thiscall, "1.19.0", None, None), + + /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. + (active, allocator_internals, "1.20.0", None, None), + + // no-tracking-issue-end + + /// Added for testing E0705; perma-unstable. + (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), + + // ------------------------------------------------------------------------- + // feature-group-end: internal feature gates + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // FIXME: Document these and merge with the list below. + + // Unstable `#[target_feature]` directives. + (active, arm_target_feature, "1.27.0", Some(44839), None), + (active, aarch64_target_feature, "1.27.0", Some(44839), None), + (active, hexagon_target_feature, "1.27.0", Some(44839), None), + (active, powerpc_target_feature, "1.27.0", Some(44839), None), + (active, mips_target_feature, "1.27.0", Some(44839), None), + (active, avx512_target_feature, "1.27.0", Some(44839), None), + (active, mmx_target_feature, "1.27.0", Some(44839), None), + (active, sse4a_target_feature, "1.27.0", Some(44839), None), + (active, tbm_target_feature, "1.27.0", Some(44839), None), + (active, wasm_target_feature, "1.30.0", Some(44839), None), + (active, adx_target_feature, "1.32.0", Some(44839), None), + (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None), + (active, movbe_target_feature, "1.34.0", Some(44839), None), + (active, rtm_target_feature, "1.35.0", Some(44839), None), + (active, f16c_target_feature, "1.36.0", Some(44839), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates (target features) + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: actual feature gates + // ------------------------------------------------------------------------- + + /// Allows using the `#[link_args]` attribute. + (active, link_args, "1.0.0", Some(29596), None), + + /// Allows defining identifiers beyond ASCII. + (active, non_ascii_idents, "1.0.0", Some(55467), None), + + /// Allows using `#[plugin_registrar]` on functions. + (active, plugin_registrar, "1.0.0", Some(29597), None), + + /// Allows using `#![plugin(myplugin)]`. + (active, plugin, "1.0.0", Some(29597), None), + + /// Allows using `#[thread_local]` on `static` items. + (active, thread_local, "1.0.0", Some(29594), None), + + /// Allows the use of SIMD types in functions declared in `extern` blocks. + (active, simd_ffi, "1.0.0", Some(27731), None), + + /// Allows using custom attributes (RFC 572). + (active, custom_attribute, "1.0.0", Some(29642), None), + + /// Allows using non lexical lifetimes (RFC 2094). + (active, nll, "1.0.0", Some(43234), None), + + /// Allows using slice patterns. + (active, slice_patterns, "1.0.0", Some(62254), None), + + /// Allows the definition of `const` functions with some advanced features. + (active, const_fn, "1.2.0", Some(57563), None), + + /// Allows associated type defaults. + (active, associated_type_defaults, "1.2.0", Some(29661), None), + + /// Allows `#![no_core]`. + (active, no_core, "1.3.0", Some(29639), None), + + /// Allows default type parameters to influence type inference. + (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + + /// Allows `repr(simd)` and importing the various simd intrinsics. + (active, repr_simd, "1.4.0", Some(27731), None), + + /// Allows `extern "platform-intrinsic" { ... }`. + (active, platform_intrinsics, "1.4.0", Some(27731), None), + + /// Allows `#[unwind(..)]`. + /// + /// Permits specifying whether a function should permit unwinding or abort on unwind. + (active, unwind_attributes, "1.4.0", Some(58760), None), + + /// Allows `#[no_debug]`. + (active, no_debug, "1.5.0", Some(29721), None), + + /// Allows attributes on expressions and non-item statements. + (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + + /// Allows the use of type ascription in expressions. + (active, type_ascription, "1.6.0", Some(23416), None), + + /// Allows `cfg(target_thread_local)`. + (active, cfg_target_thread_local, "1.7.0", Some(29594), None), + + /// Allows specialization of implementations (RFC 1210). + (active, specialization, "1.7.0", Some(31844), None), + + /// Allows using `#[naked]` on functions. + (active, naked_functions, "1.9.0", Some(32408), None), + + /// Allows `cfg(target_has_atomic = "...")`. + (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + + /// Allows `X..Y` patterns. + (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + + /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + + /// Allows exhaustive pattern matching on types that contain uninhabited types. + (active, exhaustive_patterns, "1.13.0", Some(51085), None), + + /// Allows untagged unions `union U { ... }`. + (active, untagged_unions, "1.13.0", Some(32836), None), + + /// Allows `#[link(..., cfg(..))]`. + (active, link_cfg, "1.14.0", Some(37406), None), + + /// Allows `extern "ptx-*" fn()`. + (active, abi_ptx, "1.15.0", Some(38788), None), + + /// Allows the `#[repr(i128)]` attribute for enums. + (active, repr128, "1.16.0", Some(35118), None), + + /// Allows `#[link(kind="static-nobundle"...)]`. + (active, static_nobundle, "1.16.0", Some(37403), None), + + /// Allows `extern "msp430-interrupt" fn()`. + (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), + + /// Allows declarative macros 2.0 (`macro`). + (active, decl_macro, "1.17.0", Some(39412), None), + + /// Allows `extern "x86-interrupt" fn()`. + (active, abi_x86_interrupt, "1.17.0", Some(40180), None), + + /// Allows overlapping impls of marker traits. + (active, overlapping_marker_traits, "1.18.0", Some(29864), None), + + /// Allows a test to fail without failing the whole suite. + (active, allow_fail, "1.19.0", Some(46488), None), + + /// Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), + + /// Allows defining generators. + (active, generators, "1.21.0", Some(43122), None), + + /// Allows `#[doc(cfg(...))]`. + (active, doc_cfg, "1.21.0", Some(43781), None), + + /// Allows `#[doc(masked)]`. + (active, doc_masked, "1.21.0", Some(44027), None), + + /// Allows `#[doc(spotlight)]`. + (active, doc_spotlight, "1.22.0", Some(45040), None), + + /// Allows `#[doc(include = "some-file")]`. + (active, external_doc, "1.22.0", Some(44732), None), + + /// Allows future-proofing enums/structs with the `#[non_exhaustive]` attribute (RFC 2008). + (active, non_exhaustive, "1.22.0", Some(44109), None), + + /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. + (active, crate_visibility_modifier, "1.23.0", Some(53120), None), + + /// Allows defining `extern type`s. + (active, extern_types, "1.23.0", Some(43467), None), + + /// Allows trait methods with arbitrary self types. + (active, arbitrary_self_types, "1.23.0", Some(44874), None), + + /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). + (active, in_band_lifetimes, "1.23.0", Some(44524), None), + + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + (active, generic_associated_types, "1.23.0", Some(44265), None), + + /// Allows defining `trait X = A + B;` alias items. + (active, trait_alias, "1.24.0", Some(41517), None), + + /// Allows infering `'static` outlives requirements (RFC 2093). + (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None), + + /// Allows macro invocations in `extern {}` blocks. + (active, macros_in_extern, "1.27.0", Some(49476), None), + + /// Allows accessing fields of unions inside `const` functions. + (active, const_fn_union, "1.27.0", Some(51909), None), + + /// Allows casting raw pointers to `usize` during const eval. + (active, const_raw_ptr_to_usize_cast, "1.27.0", Some(51910), None), + + /// Allows dereferencing raw pointers during const eval. + (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), + + /// Allows comparing raw pointers during const eval. + (active, const_compare_raw_pointers, "1.27.0", Some(53020), None), + + /// Allows `#[doc(alias = "...")]`. + (active, doc_alias, "1.27.0", Some(50146), None), + + /// Allows inconsistent bounds in where clauses. + (active, trivial_bounds, "1.28.0", Some(48214), None), + + /// Allows `'a: { break 'a; }`. + (active, label_break_value, "1.28.0", Some(48594), None), + + /// Allows using `#[doc(keyword = "...")]`. + (active, doc_keyword, "1.28.0", Some(51315), None), + + /// Allows reinterpretation of the bits of a value of one type as another + /// type during const eval. + (active, const_transmute, "1.29.0", Some(53605), None), + + /// Allows using `try {...}` expressions. + (active, try_blocks, "1.29.0", Some(31436), None), + + /// Allows defining an `#[alloc_error_handler]`. + (active, alloc_error_handler, "1.29.0", Some(51540), None), + + /// Allows using the `amdgpu-kernel` ABI. + (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), + + /// Allows panicking during const eval (producing compile-time errors). + (active, const_panic, "1.30.0", Some(51999), None), + + /// Allows `#[marker]` on certain traits allowing overlapping implementations. + (active, marker_trait_attr, "1.30.0", Some(29864), None), + + /// Allows macro invocations on modules expressions and statements and + /// procedural macros to expand to non-items. + (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + + /// Allows unsized rvalues at arguments and parameters. + (active, unsized_locals, "1.30.0", Some(48055), None), + + /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. + (active, custom_test_frameworks, "1.30.0", Some(50297), None), + + /// Allows non-builtin attributes in inner attribute position. + (active, custom_inner_attributes, "1.30.0", Some(54726), None), + + /// Allows mixing bind-by-move in patterns and references to those identifiers in guards. + (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), + + /// Allows `impl Trait` in bindings (`let`, `const`, `static`). + (active, impl_trait_in_bindings, "1.30.0", Some(63065), None), + + /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. + (active, lint_reasons, "1.31.0", Some(54503), None), + + /// Allows exhaustive integer pattern matching on `usize` and `isize`. + (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), + + /// Allows relaxing the coherence rules such that + /// `impl ForeignTrait for ForeignType is permitted. + (active, re_rebalance_coherence, "1.32.0", Some(55437), None), + + /// Allows using `#[ffi_returns_twice]` on foreign functions. + (active, ffi_returns_twice, "1.34.0", Some(58314), None), + + /// Allows const generic types (e.g. `struct Foo(...);`). + (active, const_generics, "1.34.0", Some(44580), None), + + /// Allows using `#[optimize(X)]`. + (active, optimize_attribute, "1.34.0", Some(54882), None), + + /// Allows using C-variadics. + (active, c_variadic, "1.34.0", Some(44930), None), + + /// Allows the user of associated type bounds. + (active, associated_type_bounds, "1.34.0", Some(52662), None), + + /// Attributes on formal function params. + (active, param_attrs, "1.36.0", Some(60406), None), + + /// Allows calling constructor functions in `const fn`. + (active, const_constructor, "1.37.0", Some(61456), None), + + /// Allows `if/while p && let q = r && ...` chains. + (active, let_chains, "1.37.0", Some(53667), None), + + /// Allows #[repr(transparent)] on enums (RFC 2645). + (active, transparent_enums, "1.37.0", Some(60405), None), + + /// Allows #[repr(transparent)] on unions (RFC 2645). + (active, transparent_unions, "1.37.0", Some(60405), None), + + /// Allows explicit discriminants on non-unit enum variants. + (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), + + /// Allows `impl Trait` with multiple unrelated lifetimes. + (active, member_constraints, "1.37.0", Some(61977), None), + + /// Allows `async || body` closures. + (active, async_closure, "1.37.0", Some(62290), None), + + /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests + (active, cfg_doctest, "1.37.0", Some(62210), None), + + /// Allows `[x; N]` where `x` is a constant (RFC 2203). + (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None), + + /// Allows `impl Trait` to be used inside type aliases (RFC 2515). + (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + + /// Allows the use of or-patterns, e.g. `0 | 1`. + (active, or_patterns, "1.38.0", Some(54883), None), + + // ------------------------------------------------------------------------- + // feature-group-end: actual feature gates + // ------------------------------------------------------------------------- +); + +/// Some features are known to be incomplete and using them is likely to have +/// unanticipated results, such as compiler crashes. We warn the user about these +/// to alert them. +pub const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::impl_trait_in_bindings, + sym::generic_associated_types, + sym::const_generics, + sym::or_patterns, + sym::let_chains, +]; diff --git a/src/libsyntax/feature_gate/builtin_attrs.rs b/src/libsyntax/feature_gate/builtin_attrs.rs new file mode 100644 index 0000000000000..ee7ac3b15d955 --- /dev/null +++ b/src/libsyntax/feature_gate/builtin_attrs.rs @@ -0,0 +1,573 @@ +//! Built-in attributes and `cfg` flag gating. + +use AttributeType::*; +use AttributeGate::*; + +use super::check::{emit_feature_err, GateIssue}; +use super::check::{Stability, EXPLAIN_ALLOW_INTERNAL_UNSAFE, EXPLAIN_ALLOW_INTERNAL_UNSTABLE}; +use super::active::Features; + +use crate::ast; +use crate::attr::AttributeTemplate; +use crate::symbol::{Symbol, sym}; +use crate::parse::ParseSess; + +use syntax_pos::Span; +use rustc_data_structures::fx::FxHashMap; +use lazy_static::lazy_static; + +type GateFn = fn(&Features) -> bool; + +macro_rules! cfg_fn { + ($field: ident) => { + (|features| { features.$field }) as GateFn + } +} + +/// `cfg(...)`'s that are feature gated. +const GATED_CFGS: &[(Symbol, Symbol, GateFn)] = &[ + // (name in cfg, feature, function to check if the feature is enabled) + (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), + (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)), +]; + +#[derive(Debug)] +pub struct GatedCfg { + span: Span, + index: usize, +} + +impl GatedCfg { + pub fn gate(cfg: &ast::MetaItem) -> Option { + GATED_CFGS.iter() + .position(|info| cfg.check_name(info.0)) + .map(|idx| { + GatedCfg { + span: cfg.span, + index: idx + } + }) + } + + pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { + let (cfg, feature, has_feature) = GATED_CFGS[self.index]; + if !has_feature(features) && !self.span.allows_unstable(feature) { + let explain = format!("`cfg({})` is experimental and subject to change", cfg); + emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); + } + } +} + +// If you change this, please modify `src/doc/unstable-book` as well. You must +// move that documentation into the relevant place in the other docs, and +// remove the chapter on the flag. + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AttributeType { + /// Normal, builtin attribute that is consumed + /// by the compiler before the unused_attribute check + Normal, + + /// Builtin attribute that may not be consumed by the compiler + /// before the unused_attribute check. These attributes + /// will be ignored by the unused_attribute lint + Whitelisted, + + /// Builtin attribute that is only allowed at the crate level + CrateLevel, +} + +pub enum AttributeGate { + /// Is gated by a given feature gate, reason + /// and function to check if enabled + Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), + + /// Ungated attribute, can be used on all release channels + Ungated, +} + +// fn() is not Debug +impl std::fmt::Debug for AttributeGate { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::Gated(ref stab, name, expl, _) => + write!(fmt, "Gated({:?}, {}, {})", stab, name, expl), + Self::Ungated => write!(fmt, "Ungated") + } + } +} + +impl AttributeGate { + fn is_deprecated(&self) -> bool { + match *self { + Self::Gated(Stability::Deprecated(_, _), ..) => true, + _ => false, + } + } +} + +/// A convenience macro for constructing attribute templates. +/// E.g., `template!(Word, List: "description")` means that the attribute +/// supports forms `#[attr]` and `#[attr(description)]`. +macro_rules! template { + (Word) => { template!(@ true, None, None) }; + (List: $descr: expr) => { template!(@ false, Some($descr), None) }; + (NameValueStr: $descr: expr) => { template!(@ false, None, Some($descr)) }; + (Word, List: $descr: expr) => { template!(@ true, Some($descr), None) }; + (Word, NameValueStr: $descr: expr) => { template!(@ true, None, Some($descr)) }; + (List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ false, Some($descr1), Some($descr2)) + }; + (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { + template!(@ true, Some($descr1), Some($descr2)) + }; + (@ $word: expr, $list: expr, $name_value_str: expr) => { AttributeTemplate { + word: $word, list: $list, name_value_str: $name_value_str + } }; +} + +macro_rules! ungated { + ($attr:ident, $typ:expr, $tpl:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Ungated) + }; +} + +macro_rules! gated { + ($attr:ident, $typ:expr, $tpl:expr, $gate:ident, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate))) + }; + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr))) + }; +} + +macro_rules! rustc_attr { + (TEST, $attr:ident, $typ:expr, $tpl:expr $(,)?) => { + rustc_attr!( + $attr, $typ, $tpl, + concat!("the `#[", stringify!($attr), "]` attribute is just used for rustc unit tests \ + and will never be stable", + ), + ) + }; + ($attr:ident, $typ:expr, $tpl:expr, $msg:expr $(,)?) => { + (sym::$attr, $typ, $tpl, + Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs))) + }; +} + +macro_rules! experimental { + ($attr:ident) => { + concat!("the `#[", stringify!($attr), "]` attribute is an experimental feature") + } +} + +const IMPL_DETAIL: &str = "internal implementation detail"; +const INTERAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; + +pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate); + +/// Attributes that have a special meaning to rustc or rustdoc +pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ + // ========================================================================== + // Stable attributes: + // ========================================================================== + + // Condtional compilation: + ungated!(cfg, Normal, template!(List: "predicate")), + ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ...")), + + // Testing: + ungated!(ignore, Normal, template!(Word, NameValueStr: "reason")), + ungated!( + should_panic, Normal, + template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), + ), + // FIXME(Centril): This can be used on stable but shouldn't. + ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), + + // Macros: + ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), + ungated!(automatically_derived, Normal, template!(Word)), + // FIXME(#14407) + ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), + ungated!(macro_escape, Normal, template!(Word)), // Deprecated synonym for `macro_use`. + ungated!(macro_export, Normal, template!(Word, List: "local_inner_macros")), + ungated!(proc_macro, Normal, template!(Word)), + ungated!( + proc_macro_derive, Normal, + template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"), + ), + ungated!(proc_macro_attribute, Normal, template!(Word)), + + // Lints: + ungated!(warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), + ungated!(must_use, Whitelisted, template!(Word, NameValueStr: "reason")), + // FIXME(#14407) + ungated!( + deprecated, Normal, + template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ), + ), + + // Crate properties: + ungated!(crate_name, CrateLevel, template!(NameValueStr: "name")), + ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|...")), + ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored")), + + // ABI, linking, symbols, and FFI + ungated!( + link, Whitelisted, + template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), + ), + ungated!(link_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_link, Normal, template!(Word)), + ungated!(repr, Normal, template!(List: "C, packed, ...")), + ungated!(export_name, Whitelisted, template!(NameValueStr: "name")), + ungated!(link_section, Whitelisted, template!(NameValueStr: "name")), + ungated!(no_mangle, Whitelisted, template!(Word)), + ungated!(used, Whitelisted, template!(Word)), + + // Limits: + ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), + ungated!(type_length_limit, CrateLevel, template!(NameValueStr: "N")), + + // Entry point: + ungated!(main, Normal, template!(Word)), + ungated!(start, Normal, template!(Word)), + ungated!(no_start, CrateLevel, template!(Word)), + ungated!(no_main, CrateLevel, template!(Word)), + + // Modules, prelude, and resolution: + ungated!(path, Normal, template!(NameValueStr: "file")), + ungated!(no_std, CrateLevel, template!(Word)), + ungated!(no_implicit_prelude, Normal, template!(Word)), + + // Runtime + ungated!(windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console")), + ungated!(panic_handler, Normal, template!(Word)), // RFC 2070 + + // Code generation: + ungated!(inline, Whitelisted, template!(Word, List: "always|never")), + ungated!(cold, Whitelisted, template!(Word)), + ungated!(no_builtins, Whitelisted, template!(Word)), + ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), + + // FIXME: #14408 whitelist docs since rustdoc looks at them + ungated!(doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string")), + + // ========================================================================== + // Unstable attributes: + // ========================================================================== + + // Linking: + gated!(naked, Whitelisted, template!(Word), naked_functions, experimental!(naked)), + gated!( + link_args, Normal, template!(NameValueStr: "args"), + "the `link_args` attribute is experimental and not portable across platforms, \ + it is recommended to use `#[link(name = \"foo\")] instead", + ), + + // Plugins: + ungated!(plugin_registrar, Normal, template!(Word)), + gated!( + plugin, CrateLevel, template!(List: "name|name(args)"), + "compiler plugins are experimental and possibly buggy", + ), + + // Testing: + gated!(allow_fail, Normal, template!(Word), experimental!(allow_fail)), + gated!( + test_runner, CrateLevel, template!(List: "path"), custom_test_frameworks, + "custom test frameworks are an unstable feature", + ), + + // RFC #2008 + gated!(non_exhaustive, Whitelisted, template!(Word), experimental!(non_exhaustive)), + // RFC #1268 + gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), + gated!( + thread_local, Whitelisted, template!(Word), + "`#[thread_local]` is an experimental feature, and does not currently handle destructors", + ), + gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)), + // RFC 2412 + gated!( + optimize, Whitelisted, template!(List: "size|speed"), optimize_attribute, + experimental!(optimize), + ), + + gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)), + + // ========================================================================== + // Internal attributes: Stability, deprecation, and unsafe: + // ========================================================================== + + ungated!(feature, CrateLevel, template!(List: "name1, name1, ...")), + // FIXME(#14407) -- only looked at on-demand so we can't + // guarantee they'll have already been checked. + ungated!( + rustc_deprecated, Whitelisted, + template!(List: r#"since = "version", reason = "...""#) + ), + // FIXME(#14407) + ungated!(stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#)), + // FIXME(#14407) + ungated!( + unstable, Whitelisted, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + ), + gated!( + rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + "the `#[rustc_const_unstable]` attribute is an internal feature", + ), + gated!( + allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + EXPLAIN_ALLOW_INTERNAL_UNSTABLE, + ), + gated!(allow_internal_unsafe, Normal, template!(Word), EXPLAIN_ALLOW_INTERNAL_UNSAFE), + + // ========================================================================== + // Internal attributes: Type system related: + // ========================================================================== + + gated!(fundamental, Whitelisted, template!(Word), experimental!(fundamental)), + gated!( + // RFC #1445. + structural_match, Whitelisted, template!(Word), + "the semantics of constant patterns is not yet settled", + ), + gated!( + may_dangle, Normal, template!(Word), dropck_eyepatch, + "`may_dangle` has unstable semantics and may be removed in the future", + ), + + // ========================================================================== + // Internal attributes: Runtime related: + // ========================================================================== + + rustc_attr!(rustc_allocator, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allocator_nounwind, Whitelisted, template!(Word), IMPL_DETAIL), + gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)), + gated!( + default_lib_allocator, Whitelisted, template!(Word), allocator_internals, + experimental!(default_lib_allocator), + ), + gated!( + needs_allocator, Normal, template!(Word), allocator_internals, + experimental!(needs_allocator), + ), + gated!(panic_runtime, Whitelisted, template!(Word), experimental!(panic_runtime)), + gated!(needs_panic_runtime, Whitelisted, template!(Word), experimental!(needs_panic_runtime)), + gated!( + unwind, Whitelisted, template!(List: "allowed|aborts"), unwind_attributes, + experimental!(unwind), + ), + gated!( + compiler_builtins, Whitelisted, template!(Word), + "the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ + which contains compiler-rt intrinsics and will never be stable", + ), + gated!( + sanitizer_runtime, Whitelisted, template!(Word), + "the `#[sanitizer_runtime]` attribute is used to identify crates that contain the runtime \ + of a sanitizer and will never be stable", + ), + gated!( + profiler_runtime, Whitelisted, template!(Word), + "the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ + which contains the profiler runtime and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Linkage: + // ========================================================================== + + gated!( + linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + "the `linkage` attribute is experimental and not portable across platforms", + ), + rustc_attr!(rustc_std_internal_symbol, Whitelisted, template!(Word), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Macro related: + // ========================================================================== + + rustc_attr!(rustc_builtin_macro, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERAL_UNSTABLE), + rustc_attr!( + rustc_macro_transparency, Whitelisted, + template!(NameValueStr: "transparent|semitransparent|opaque"), + "used internally for testing macro hygiene", + ), + + // ========================================================================== + // Internal attributes, Diagnostics related: + // ========================================================================== + + gated!( + rustc_on_unimplemented, Whitelisted, + template!( + List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, + NameValueStr: "message" + ), + on_unimplemented, + experimental!(rustc_on_unimplemented), + ), + // Whitelists "identity-like" conversion methods to suggest on type mismatch. + rustc_attr!(rustc_conversion_suggestion, Whitelisted, template!(Word), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Const related: + // ========================================================================== + + rustc_attr!(rustc_promotable, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_allow_const_fn_ptr, Whitelisted, template!(Word), IMPL_DETAIL), + rustc_attr!(rustc_args_required_const, Whitelisted, template!(List: "N"), INTERAL_UNSTABLE), + + // ========================================================================== + // Internal attributes, Layout related: + // ========================================================================== + + rustc_attr!( + rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + rustc_attr!( + rustc_nonnull_optimization_guaranteed, Whitelisted, template!(Word), + "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ + niche optimizations in libcore and will never be stable", + ), + + // ========================================================================== + // Internal attributes, Misc: + // ========================================================================== + + gated!( + lang, Normal, template!(NameValueStr: "name"), lang_items, + "language items are subject to change", + ), + ( + sym::rustc_diagnostic_item, + Normal, + template!(NameValueStr: "name"), + Gated( + Stability::Unstable, + sym::rustc_attrs, + "diagnostic items compiler internal support for linting", + cfg_fn!(rustc_attrs), + ), + ), + ( + sym::no_debug, Whitelisted, template!(Word), + Gated( + Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), + sym::no_debug, + "the `#[no_debug]` attribute was an experimental feature that has been \ + deprecated due to lack of demand", + cfg_fn!(no_debug) + ) + ), + gated!( + // Used in resolve: + prelude_import, Whitelisted, template!(Word), + "`#[prelude_import]` is for use by rustc only", + ), + gated!( + rustc_paren_sugar, Normal, template!(Word), unboxed_closures, + "unboxed_closures are still evolving", + ), + rustc_attr!( + rustc_inherit_overflow_checks, Whitelisted, template!(Word), + "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ + overflow checking behavior of several libcore functions that are inlined \ + across crates and will never be stable", + ), + rustc_attr!( + rustc_test_marker, Normal, template!(Word), + "the `#[rustc_test_marker]` attribute is used internally to track tests", + ), + + // ========================================================================== + // Internal attributes, Testing: + // ========================================================================== + + rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), + rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), + rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), + rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), + rustc_attr!(TEST, rustc_error, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_user_substs, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode")), + rustc_attr!(TEST, rustc_then_this_would_need, Whitelisted, template!(List: "DepNode")), + rustc_attr!( + TEST, rustc_dirty, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_clean, Whitelisted, + template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), + ), + rustc_attr!( + TEST, rustc_partition_reused, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + ), + rustc_attr!( + TEST, rustc_partition_codegened, Whitelisted, + template!(List: r#"cfg = "...", module = "...""#), + ), + rustc_attr!( + TEST, rustc_expected_cgu_reuse, Whitelisted, + template!(List: r#"cfg = "...", module = "...", kind = "...""#), + ), + rustc_attr!(TEST, rustc_synthetic, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_symbol_name, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_def_path, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_mir, Whitelisted, template!(List: "arg1, arg2, ...")), + rustc_attr!(TEST, rustc_dump_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dump_env_program_clauses, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_object_lifetime_default, Whitelisted, template!(Word)), + rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), + gated!( + omit_gdb_pretty_printer_section, Whitelisted, template!(Word), + "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", + ), +]; + +pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { + BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect() +} + +pub fn is_builtin_attr_name(name: ast::Name) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() +} + +pub fn is_builtin_attr(attr: &ast::Attribute) -> bool { + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some() +} + +lazy_static! { + pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { + let mut map = FxHashMap::default(); + for attr in BUILTIN_ATTRIBUTES.iter() { + if map.insert(attr.0, attr).is_some() { + panic!("duplicate builtin attribute `{}`", attr.0); + } + } + map + }; +} diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs new file mode 100644 index 0000000000000..f3a9d135125ae --- /dev/null +++ b/src/libsyntax/feature_gate/check.rs @@ -0,0 +1,958 @@ +use super::{active::{ACTIVE_FEATURES, Features}, Feature, State as FeatureState}; +use super::accepted::ACCEPTED_FEATURES; +use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; +use super::builtin_attrs::{AttributeGate, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; + +use crate::ast::{ + self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, + PatKind, RangeEnd, +}; +use crate::attr::{self, check_builtin_attribute}; +use crate::source_map::Spanned; +use crate::edition::{ALL_EDITIONS, Edition}; +use crate::visit::{self, FnKind, Visitor}; +use crate::parse::{token, ParseSess}; +use crate::parse::parser::Parser; +use crate::symbol::{Symbol, sym}; +use crate::tokenstream::TokenTree; + +use errors::{Applicability, DiagnosticBuilder, Handler}; +use rustc_data_structures::fx::FxHashMap; +use rustc_target::spec::abi::Abi; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; +use log::debug; + +use std::env; + +#[derive(Copy, Clone, Debug)] +pub enum Stability { + Unstable, + // First argument is tracking issue link; second argument is an optional + // help message, which defaults to "remove this attribute" + Deprecated(&'static str, Option<&'static str>), +} + +struct Context<'a> { + features: &'a Features, + parse_sess: &'a ParseSess, + plugin_attributes: &'a [(Symbol, AttributeType)], +} + +macro_rules! gate_feature_fn { + ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $level: expr) => {{ + let (cx, has_feature, span, + name, explain, level) = ($cx, $has_feature, $span, $name, $explain, $level); + let has_feature: bool = has_feature(&$cx.features); + debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); + if !has_feature && !span.allows_unstable($name) { + leveled_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain, level) + .emit(); + } + }} +} + +macro_rules! gate_feature { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, GateStrength::Hard) + }; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { + gate_feature_fn!($cx, |x:&Features| x.$feature, $span, + sym::$feature, $explain, $level) + }; +} + +impl<'a> Context<'a> { + fn check_attribute( + &self, + attr: &ast::Attribute, + attr_info: Option<&BuiltinAttribute>, + is_macro: bool + ) { + debug!("check_attribute(attr = {:?})", attr); + if let Some(&(name, ty, _template, ref gateage)) = attr_info { + if let AttributeGate::Gated(_, name, desc, ref has_feature) = *gateage { + if !attr.span.allows_unstable(name) { + gate_feature_fn!( + self, has_feature, attr.span, name, desc, GateStrength::Hard + ); + } + } else if name == sym::doc { + if let Some(content) = attr.meta_item_list() { + if content.iter().any(|c| c.check_name(sym::include)) { + gate_feature!(self, external_doc, attr.span, + "`#[doc(include = \"...\")]` is experimental" + ); + } + } + } + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); + return; + } else { + for segment in &attr.path.segments { + if segment.ident.as_str().starts_with("rustc") { + let msg = "attributes starting with `rustc` are \ + reserved for use by the `rustc` compiler"; + gate_feature!(self, rustc_attrs, segment.ident.span, msg); + } + } + } + for &(n, ty) in self.plugin_attributes { + if attr.path == n { + // Plugins can't gate attributes, so we don't check for it + // unlike the code above; we only use this loop to + // short-circuit to avoid the checks below. + debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); + return; + } + } + if !is_macro && !attr::is_known(attr) { + // Only run the custom attribute lint during regular feature gate + // checking. Macro gating runs before the plugin attributes are + // registered, so we skip this in that case. + let msg = format!("the attribute `{}` is currently unknown to the compiler and \ + may have meaning added to it in the future", attr.path); + gate_feature!(self, custom_attribute, attr.span, &msg); + } + } +} + +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features, parse_sess, plugin_attributes: &[] }; + cx.check_attribute( + attr, + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)), + true + ); +} + +fn find_lang_feature_issue(feature: Symbol) -> Option { + if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { + // FIXME (#28244): enforce that active features have issue numbers + // assert!(info.issue.is_some()) + info.issue + } else { + // search in Accepted, Removed, or Stable Removed features + let found = ACCEPTED_FEATURES.iter().chain(REMOVED_FEATURES).chain(STABLE_REMOVED_FEATURES) + .find(|t| t.name == feature); + match found { + Some(&Feature { issue, .. }) => issue, + None => panic!("Feature `{}` is not declared anywhere", feature), + } + } +} + +pub enum GateIssue { + Language, + Library(Option) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum GateStrength { + /// A hard error. (Most feature gates should use this.) + Hard, + /// Only a warning. (Use this only as backwards-compatibility demands.) + Soft, +} + +pub fn emit_feature_err( + sess: &ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + feature_err(sess, feature, span, issue, explain).emit(); +} + +pub fn feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, +) -> DiagnosticBuilder<'a> { + leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) +} + +fn leveled_feature_err<'a, S: Into>( + sess: &'a ParseSess, + feature: Symbol, + span: S, + issue: GateIssue, + explain: &str, + level: GateStrength, +) -> DiagnosticBuilder<'a> { + let diag = &sess.span_diagnostic; + + let issue = match issue { + GateIssue::Language => find_lang_feature_issue(feature), + GateIssue::Library(lib) => lib, + }; + + let mut err = match level { + GateStrength::Hard => { + diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) + } + GateStrength::Soft => diag.struct_span_warn(span, explain), + }; + + match issue { + None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility + Some(n) => { + err.note(&format!( + "for more information, see https://github.com/rust-lang/rust/issues/{}", + n, + )); + } + } + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); + } + + // If we're on stable and only emitting a "soft" warning, add a note to + // clarify that the feature isn't "on" (rather than being on but + // warning-worthy). + if !sess.unstable_features.is_nightly_build() && level == GateStrength::Soft { + err.help("a nightly build of the compiler is required to enable this feature"); + } + + err + +} + +const EXPLAIN_BOX_SYNTAX: &str = + "box expression syntax is experimental; you can call `Box::new` instead"; + +pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = + "attributes on expressions are experimental"; + +pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str = + "allow_internal_unstable side-steps feature gating and stability checks"; +pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str = + "allow_internal_unsafe side-steps the unsafe_code lint"; + +pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str = + "unsized tuple coercion is not stable enough for use and is subject to change"; + +struct PostExpansionVisitor<'a> { + context: &'a Context<'a>, + builtin_attributes: &'static FxHashMap, +} + +macro_rules! gate_feature_post { + ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx.context, $feature, span, $explain) + } + }}; + ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ + let (cx, span) = ($cx, $span); + if !span.allows_unstable(sym::$feature) { + gate_feature!(cx.context, $feature, span, $explain, $level) + } + }} +} + +impl<'a> PostExpansionVisitor<'a> { + fn check_abi(&self, abi: Abi, span: Span) { + match abi { + Abi::RustIntrinsic => { + gate_feature_post!(&self, intrinsics, span, + "intrinsics are subject to change"); + }, + Abi::PlatformIntrinsic => { + gate_feature_post!(&self, platform_intrinsics, span, + "platform intrinsics are experimental and possibly buggy"); + }, + Abi::Vectorcall => { + gate_feature_post!(&self, abi_vectorcall, span, + "vectorcall is experimental and subject to change"); + }, + Abi::Thiscall => { + gate_feature_post!(&self, abi_thiscall, span, + "thiscall is experimental and subject to change"); + }, + Abi::RustCall => { + gate_feature_post!(&self, unboxed_closures, span, + "rust-call ABI is subject to change"); + }, + Abi::PtxKernel => { + gate_feature_post!(&self, abi_ptx, span, + "PTX ABIs are experimental and subject to change"); + }, + Abi::Unadjusted => { + gate_feature_post!(&self, abi_unadjusted, span, + "unadjusted ABI is an implementation detail and perma-unstable"); + }, + Abi::Msp430Interrupt => { + gate_feature_post!(&self, abi_msp430_interrupt, span, + "msp430-interrupt ABI is experimental and subject to change"); + }, + Abi::X86Interrupt => { + gate_feature_post!(&self, abi_x86_interrupt, span, + "x86-interrupt ABI is experimental and subject to change"); + }, + Abi::AmdGpuKernel => { + gate_feature_post!(&self, abi_amdgpu_kernel, span, + "amdgpu-kernel ABI is experimental and subject to change"); + }, + // Stable + Abi::Cdecl | + Abi::Stdcall | + Abi::Fastcall | + Abi::Aapcs | + Abi::Win64 | + Abi::SysV64 | + Abi::Rust | + Abi::C | + Abi::System => {} + } + } +} + +impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { + fn visit_attribute(&mut self, attr: &ast::Attribute) { + let attr_info = attr.ident().and_then(|ident| { + self.builtin_attributes.get(&ident.name).map(|a| *a) + }); + + // Check for gated attributes. + self.context.check_attribute(attr, attr_info, false); + + if attr.check_name(sym::doc) { + if let Some(content) = attr.meta_item_list() { + if content.len() == 1 && content[0].check_name(sym::cfg) { + gate_feature_post!(&self, doc_cfg, attr.span, + "`#[doc(cfg(...))]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::masked)) { + gate_feature_post!(&self, doc_masked, attr.span, + "`#[doc(masked)]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::spotlight)) { + gate_feature_post!(&self, doc_spotlight, attr.span, + "`#[doc(spotlight)]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::alias)) { + gate_feature_post!(&self, doc_alias, attr.span, + "`#[doc(alias = \"...\")]` is experimental" + ); + } else if content.iter().any(|c| c.check_name(sym::keyword)) { + gate_feature_post!(&self, doc_keyword, attr.span, + "`#[doc(keyword = \"...\")]` is experimental" + ); + } + } + } + + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some(&(name, _, template, _)) if name != sym::rustc_dummy => + check_builtin_attribute(self.context.parse_sess, attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok(); + } + } + } + } + + fn visit_name(&mut self, sp: Span, name: ast::Name) { + if !name.as_str().is_ascii() { + gate_feature_post!( + &self, + non_ascii_idents, + self.context.parse_sess.source_map().def_span(sp), + "non-ascii idents are not fully supported" + ); + } + } + + fn visit_item(&mut self, i: &'a ast::Item) { + match i.node { + ast::ItemKind::ForeignMod(ref foreign_module) => { + self.check_abi(foreign_module.abi, i.span); + } + + ast::ItemKind::Fn(..) => { + if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { + gate_feature_post!(&self, plugin_registrar, i.span, + "compiler plugins are experimental and possibly buggy"); + } + if attr::contains_name(&i.attrs[..], sym::start) { + gate_feature_post!(&self, start, i.span, + "a `#[start]` function is an experimental \ + feature whose signature may change \ + over time"); + } + if attr::contains_name(&i.attrs[..], sym::main) { + gate_feature_post!(&self, main, i.span, + "declaration of a non-standard `#[main]` \ + function may change over time, for now \ + a top-level `fn main()` is required"); + } + } + + ast::ItemKind::Struct(..) => { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.check_name(sym::simd) { + gate_feature_post!(&self, repr_simd, attr.span, + "SIMD types are experimental and possibly buggy"); + } + } + } + } + + ast::ItemKind::Enum(ast::EnumDef{ref variants, ..}, ..) => { + for variant in variants { + match (&variant.data, &variant.disr_expr) { + (ast::VariantData::Unit(..), _) => {}, + (_, Some(disr_expr)) => + gate_feature_post!( + &self, + arbitrary_enum_discriminant, + disr_expr.value.span, + "discriminants on non-unit variants are experimental"), + _ => {}, + } + } + + let has_feature = self.context.features.arbitrary_enum_discriminant; + if !has_feature && !i.span.allows_unstable(sym::arbitrary_enum_discriminant) { + Parser::maybe_report_invalid_custom_discriminants( + self.context.parse_sess, + &variants, + ); + } + } + + ast::ItemKind::Impl(_, polarity, defaultness, ..) => { + if polarity == ast::ImplPolarity::Negative { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "negative trait bounds are not yet fully implemented; \ + use marker types for now"); + } + + if let ast::Defaultness::Default = defaultness { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } + } + + ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => { + gate_feature_post!(&self, optin_builtin_traits, + i.span, + "auto traits are experimental and possibly buggy"); + } + + ast::ItemKind::TraitAlias(..) => { + gate_feature_post!( + &self, + trait_alias, + i.span, + "trait aliases are experimental" + ); + } + + ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => { + let msg = "`macro` is experimental"; + gate_feature_post!(&self, decl_macro, i.span, msg); + } + + ast::ItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + i.span, + "`impl Trait` in type aliases is unstable" + ); + } + + _ => {} + } + + visit::walk_item(self, i); + } + + fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { + match i.node { + ast::ForeignItemKind::Fn(..) | + ast::ForeignItemKind::Static(..) => { + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); + let links_to_llvm = match link_name { + Some(val) => val.as_str().starts_with("llvm."), + _ => false + }; + if links_to_llvm { + gate_feature_post!(&self, link_llvm_intrinsics, i.span, + "linking to LLVM intrinsics is experimental"); + } + } + ast::ForeignItemKind::Ty => { + gate_feature_post!(&self, extern_types, i.span, + "extern types are experimental"); + } + ast::ForeignItemKind::Macro(..) => {} + } + + visit::walk_foreign_item(self, i) + } + + fn visit_ty(&mut self, ty: &'a ast::Ty) { + match ty.node { + ast::TyKind::BareFn(ref bare_fn_ty) => { + self.check_abi(bare_fn_ty.abi, ty.span); + } + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); + } + _ => {} + } + visit::walk_ty(self, ty) + } + + fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) { + if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty { + if let ast::TyKind::Never = output_ty.node { + // Do nothing. + } else { + self.visit_ty(output_ty) + } + } + } + + fn visit_expr(&mut self, e: &'a ast::Expr) { + match e.node { + ast::ExprKind::Box(_) => { + gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX); + } + ast::ExprKind::Type(..) => { + // To avoid noise about type ascription in common syntax errors, only emit if it + // is the *only* error. + if self.context.parse_sess.span_diagnostic.err_count() == 0 { + gate_feature_post!(&self, type_ascription, e.span, + "type ascription is experimental"); + } + } + ast::ExprKind::TryBlock(_) => { + gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); + } + ast::ExprKind::Block(_, opt_label) => { + if let Some(label) = opt_label { + gate_feature_post!(&self, label_break_value, label.ident.span, + "labels on blocks are unstable"); + } + } + _ => {} + } + visit::walk_expr(self, e) + } + + fn visit_arm(&mut self, arm: &'a ast::Arm) { + visit::walk_arm(self, arm) + } + + fn visit_pat(&mut self, pattern: &'a ast::Pat) { + match &pattern.node { + PatKind::Slice(pats) => { + for pat in &*pats { + let span = pat.span; + let inner_pat = match &pat.node { + PatKind::Ident(.., Some(pat)) => pat, + _ => pat, + }; + if inner_pat.is_rest() { + gate_feature_post!( + &self, + slice_patterns, + span, + "subslice patterns are unstable" + ); + } + } + } + PatKind::Box(..) => { + gate_feature_post!(&self, box_patterns, + pattern.span, + "box pattern syntax is experimental"); + } + PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => { + gate_feature_post!(&self, exclusive_range_pattern, pattern.span, + "exclusive range pattern syntax is experimental"); + } + _ => {} + } + visit::walk_pat(self, pattern) + } + + fn visit_fn(&mut self, + fn_kind: FnKind<'a>, + fn_decl: &'a ast::FnDecl, + span: Span, + _node_id: NodeId) { + if let Some(header) = fn_kind.header() { + // Stability of const fn methods are covered in + // `visit_trait_item` and `visit_impl_item` below; this is + // because default methods don't pass through this point. + self.check_abi(header.abi, span); + } + + if fn_decl.c_variadic { + gate_feature_post!(&self, c_variadic, span, "C-variadic functions are unstable"); + } + + visit::walk_fn(self, fn_kind, fn_decl, span) + } + + fn visit_generic_param(&mut self, param: &'a GenericParam) { + match param.kind { + GenericParamKind::Const { .. } => + gate_feature_post!(&self, const_generics, param.ident.span, + "const generics are unstable"), + _ => {} + } + visit::walk_generic_param(self, param) + } + + fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) { + match constraint.kind { + AssocTyConstraintKind::Bound { .. } => + gate_feature_post!(&self, associated_type_bounds, constraint.span, + "associated type bounds are unstable"), + _ => {} + } + visit::walk_assoc_ty_constraint(self, constraint) + } + + fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { + match ti.node { + ast::TraitItemKind::Method(ref sig, ref block) => { + if block.is_none() { + self.check_abi(sig.header.abi, ti.span); + } + if sig.decl.c_variadic { + gate_feature_post!(&self, c_variadic, ti.span, + "C-variadic functions are unstable"); + } + if sig.header.constness.node == ast::Constness::Const { + gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); + } + } + ast::TraitItemKind::Type(_, ref default) => { + // We use three if statements instead of something like match guards so that all + // of these errors can be emitted if all cases apply. + if default.is_some() { + gate_feature_post!(&self, associated_type_defaults, ti.span, + "associated type defaults are unstable"); + } + if !ti.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "generic associated types are unstable"); + } + if !ti.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_trait_item(self, ti) + } + + fn visit_impl_item(&mut self, ii: &'a ast::ImplItem) { + if ii.defaultness == ast::Defaultness::Default { + gate_feature_post!(&self, specialization, + ii.span, + "specialization is unstable"); + } + + match ii.node { + ast::ImplItemKind::Method(..) => {} + ast::ImplItemKind::OpaqueTy(..) => { + gate_feature_post!( + &self, + type_alias_impl_trait, + ii.span, + "`impl Trait` in type aliases is unstable" + ); + } + ast::ImplItemKind::TyAlias(_) => { + if !ii.generics.params.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "generic associated types are unstable"); + } + if !ii.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ii.span, + "where clauses on associated types are unstable"); + } + } + _ => {} + } + visit::walk_impl_item(self, ii) + } + + fn visit_vis(&mut self, vis: &'a ast::Visibility) { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + gate_feature_post!(&self, crate_visibility_modifier, vis.span, + "`crate` visibility modifier is experimental"); + } + visit::walk_vis(self, vis) + } +} + +pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], + crate_edition: Edition, allow_features: &Option>) -> Features { + fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { + let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); + if let Some(reason) = reason { + err.span_note(span, reason); + } else { + err.span_label(span, "feature has been removed"); + } + err.emit(); + } + + let mut features = Features::new(); + let mut edition_enabled_features = FxHashMap::default(); + + for &edition in ALL_EDITIONS { + if edition <= crate_edition { + // The `crate_edition` implies its respective umbrella feature-gate + // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). + edition_enabled_features.insert(edition.feature_name(), edition); + } + } + + for feature in active_features_up_to(crate_edition) { + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, crate_edition); + } + + // Process the edition umbrella feature-gates first, to ensure + // `edition_enabled_features` is completed before it's queried. + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + for mi in list { + if !mi.is_word() { + continue; + } + + let name = mi.name_or_empty(); + + let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); + if let Some(edition) = edition { + if edition <= crate_edition { + continue; + } + + for feature in active_features_up_to(edition) { + // FIXME(Manishearth) there is currently no way to set + // lib features by edition + feature.set(&mut features, DUMMY_SP); + edition_enabled_features.insert(feature.name, edition); + } + } + } + } + + for attr in krate_attrs { + if !attr.check_name(sym::feature) { + continue + } + + let list = match attr.meta_item_list() { + Some(list) => list, + None => continue, + }; + + let bad_input = |span| { + struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") + }; + + for mi in list { + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + Some(ident) => { + bad_input(mi.span()).span_suggestion( + mi.span(), + "expected just one word", + format!("{}", ident.name), + Applicability::MaybeIncorrect, + ).emit(); + continue + } + None => { + bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); + continue + } + }; + + if let Some(edition) = edition_enabled_features.get(&name) { + struct_span_warn!( + span_handler, + mi.span(), + E0705, + "the feature `{}` is included in the Rust {} edition", + name, + edition, + ).emit(); + continue; + } + + if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { + // Handled in the separate loop above. + continue; + } + + let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); + let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); + if let Some(Feature { state, .. }) = removed.or(stable_removed) { + if let FeatureState::Removed { reason } + | FeatureState::Stabilized { reason } = state + { + feature_removed(span_handler, mi.span(), *reason); + continue; + } + } + + if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + let since = Some(Symbol::intern(since)); + features.declared_lang_features.push((name, mi.span(), since)); + continue; + } + + if let Some(allowed) = allow_features.as_ref() { + if allowed.iter().find(|f| *f == name.as_str()).is_none() { + span_err!(span_handler, mi.span(), E0725, + "the feature `{}` is not in the list of allowed features", + name); + continue; + } + } + + if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { + f.set(&mut features, mi.span()); + features.declared_lang_features.push((name, mi.span(), None)); + continue; + } + + features.declared_lib_features.push((name, mi.span())); + } + } + + features +} + +fn active_features_up_to(edition: Edition) -> impl Iterator { + ACTIVE_FEATURES.iter() + .filter(move |feature| { + if let Some(feature_edition) = feature.edition { + feature_edition <= edition + } else { + false + } + }) +} + +pub fn check_crate(krate: &ast::Crate, + sess: &ParseSess, + features: &Features, + plugin_attributes: &[(Symbol, AttributeType)], + unstable: UnstableFeatures) { + maybe_stage_features(&sess.span_diagnostic, krate, unstable); + let ctx = Context { + features, + parse_sess: sess, + plugin_attributes, + }; + + macro_rules! gate_all { + ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; + ($spans:ident, $gate:ident, $msg:literal) => { + for span in &*sess.gated_spans.$spans.borrow() { + gate_feature!(&ctx, $gate, *span, $msg); + } + } + } + + gate_all!(param_attrs, "attributes on function parameters are unstable"); + gate_all!(let_chains, "`let` expressions in this position are experimental"); + gate_all!(async_closure, "async closures are unstable"); + gate_all!(yields, generators, "yield syntax is experimental"); + gate_all!(or_patterns, "or-patterns syntax is experimental"); + + let visitor = &mut PostExpansionVisitor { + context: &ctx, + builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP, + }; + visit::walk_crate(visitor, krate); +} + +#[derive(Clone, Copy, Hash)] +pub enum UnstableFeatures { + /// Hard errors for unstable features are active, as on beta/stable channels. + Disallow, + /// Allow features to be activated, as on nightly. + Allow, + /// Errors are bypassed for bootstrapping. This is required any time + /// during the build that feature-related lints are set to warn or above + /// because the build turns on warnings-as-errors and uses lots of unstable + /// features. As a result, this is always required for building Rust itself. + Cheat +} + +impl UnstableFeatures { + pub fn from_environment() -> UnstableFeatures { + // Whether this is a feature-staged build, i.e., on the beta or stable channel + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Whether we should enable unstable features for bootstrapping + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + match (disable_unstable_features, bootstrap) { + (_, true) => UnstableFeatures::Cheat, + (true, _) => UnstableFeatures::Disallow, + (false, _) => UnstableFeatures::Allow + } + } + + pub fn is_nightly_build(&self) -> bool { + match *self { + UnstableFeatures::Allow | UnstableFeatures::Cheat => true, + _ => false, + } + } +} + +fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) { + let allow_features = match unstable { + UnstableFeatures::Allow => true, + UnstableFeatures::Disallow => false, + UnstableFeatures::Cheat => true + }; + if !allow_features { + for attr in &krate.attrs { + if attr.check_name(sym::feature) { + let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); + span_err!(span_handler, attr.span, E0554, + "`#![feature]` may not be used on the {} release channel", + release_channel); + } + } + } +} diff --git a/src/libsyntax/feature_gate/mod.rs b/src/libsyntax/feature_gate/mod.rs new file mode 100644 index 0000000000000..1e41667ea411e --- /dev/null +++ b/src/libsyntax/feature_gate/mod.rs @@ -0,0 +1,64 @@ +//! # Feature gating +//! +//! This module implements the gating necessary for preventing certain compiler +//! features from being used by default. This module will crawl a pre-expanded +//! AST to ensure that there are no features which are used that are not +//! enabled. +//! +//! Features are enabled in programs via the crate-level attributes of +//! `#![feature(...)]` with a comma-separated list of features. +//! +//! For the purpose of future feature-tracking, once code for detection of feature +//! gate usage is added, *do not remove it again* even once the feature +//! becomes stable. + +mod accepted; +mod removed; +mod active; +mod builtin_attrs; +mod check; + +use std::fmt; +use crate::{edition::Edition, symbol::Symbol}; +use syntax_pos::Span; + +#[derive(Clone, Copy)] +pub enum State { + Accepted, + Active { set: fn(&mut Features, Span) }, + Removed { reason: Option<&'static str> }, + Stabilized { reason: Option<&'static str> }, +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + State::Accepted { .. } => write!(f, "accepted"), + State::Active { .. } => write!(f, "active"), + State::Removed { .. } => write!(f, "removed"), + State::Stabilized { .. } => write!(f, "stabilized"), + } + } +} + +#[derive(Debug, Clone)] +pub struct Feature { + state: State, + name: Symbol, + since: &'static str, + issue: Option, + edition: Option, + description: &'static str, +} + +pub use active::{Features, INCOMPLETE_FEATURES}; +pub use builtin_attrs::{ + AttributeGate, AttributeType, GatedCfg, + BuiltinAttribute, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + deprecated_attributes, is_builtin_attr, is_builtin_attr_name, +}; +pub use check::{ + check_attribute, check_crate, get_features, feature_err, emit_feature_err, + Stability, GateIssue, UnstableFeatures, + EXPLAIN_STMT_ATTR_SYNTAX, EXPLAIN_UNSIZED_TUPLE_COERCION, +}; diff --git a/src/libsyntax/feature_gate/removed.rs b/src/libsyntax/feature_gate/removed.rs new file mode 100644 index 0000000000000..ad7d69b3e7372 --- /dev/null +++ b/src/libsyntax/feature_gate/removed.rs @@ -0,0 +1,105 @@ +//! List of the removed feature gates. + +use crate::symbol::sym; +use super::{State, Feature}; + +macro_rules! declare_features { + ($( + $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), + )+) => { + /// Represents unstable features which have since been removed (it was once Active) + pub const REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Removed { reason: $reason }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + }; + + ($( + $(#[doc = $doc:tt])* (stable_removed, $feature:ident, $ver:expr, $issue:expr, None), + )+) => { + /// Represents stable features which have since been removed (it was once Accepted) + pub const STABLE_REMOVED_FEATURES: &[Feature] = &[ + $( + Feature { + state: State::Stabilized { reason: None }, + name: sym::$feature, + since: $ver, + issue: $issue, + edition: None, + description: concat!($($doc,)*), + } + ),+ + ]; + }; +} + +declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: removed features + // ------------------------------------------------------------------------- + + (removed, import_shadowing, "1.0.0", None, None, None), + (removed, managed_boxes, "1.0.0", None, None, None), + /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 + (removed, negate_unsigned, "1.0.0", Some(29645), None, None), + (removed, reflect, "1.0.0", Some(27749), None, None), + /// A way to temporarily opt out of opt in copy. This will *never* be accepted. + (removed, opt_out_copy, "1.0.0", None, None, None), + (removed, quad_precision_float, "1.0.0", None, None, None), + (removed, struct_inherit, "1.0.0", None, None, None), + (removed, test_removed_feature, "1.0.0", None, None, None), + (removed, visible_private_types, "1.0.0", None, None, None), + (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), + /// Allows using items which are missing stability attributes + (removed, unmarked_api, "1.0.0", None, None, None), + (removed, allocator, "1.0.0", None, None, None), + (removed, simd, "1.0.0", Some(27731), None, + Some("removed in favor of `#[repr(simd)]`")), + (removed, advanced_slice_patterns, "1.0.0", Some(62254), None, + Some("merged into `#![feature(slice_patterns)]`")), + (removed, macro_reexport, "1.0.0", Some(29638), None, + Some("subsumed by `pub use`")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), + (removed, proc_macro_mod, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_expr, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_non_items, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, proc_macro_gen, "1.27.0", Some(54727), None, + Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + (removed, panic_implementation, "1.28.0", Some(44489), None, + Some("subsumed by `#[panic_handler]`")), + /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. + (removed, custom_derive, "1.32.0", Some(29644), None, + Some("subsumed by `#[proc_macro_derive]`")), + /// Paths of the form: `extern::foo::bar` + (removed, extern_in_paths, "1.33.0", Some(55600), None, + Some("subsumed by `::foo::bar` paths")), + (removed, quote, "1.33.0", Some(29601), None, None), + /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). + (removed, dropck_parametricity, "1.38.0", Some(28498), None, None), + (removed, await_macro, "1.38.0", Some(50547), None, + Some("subsumed by `.await` syntax")), + /// Allows defining `existential type`s. + (removed, existential_type, "1.38.0", Some(63063), None, + Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), + + // ------------------------------------------------------------------------- + // feature-group-end: removed features + // ------------------------------------------------------------------------- +); + +declare_features! ( + (stable_removed, no_stack_check, "1.0.0", None, None), +); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 83c9c692bd30c..ada46f7bc5a74 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -219,7 +219,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false, None) .ui_testing(je.ui_testing).emit_diagnostic(db); let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap(); let output = String::from_utf8(output).unwrap(); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 8ac48d8d74a42..1741932c1b80e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -124,7 +124,6 @@ pub mod diagnostics { #[macro_use] pub mod macros; pub mod plugin; - pub mod metadata; } // N.B., this module needs to be declared first so diagnostics are diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 9785f8e2de098..e14ca4b06a09e 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -98,8 +98,8 @@ pub trait MutVisitor: Sized { noop_visit_fn_header(header, self); } - fn visit_struct_field(&mut self, sf: &mut StructField) { - noop_visit_struct_field(sf, self); + fn flat_map_struct_field(&mut self, sf: StructField) -> SmallVec<[StructField; 1]> { + noop_flat_map_struct_field(sf, self) } fn visit_item_kind(&mut self, i: &mut ItemKind) { @@ -130,8 +130,8 @@ pub trait MutVisitor: Sized { noop_flat_map_stmt(s, self) } - fn visit_arm(&mut self, a: &mut Arm) { - noop_visit_arm(a, self); + fn flat_map_arm(&mut self, arm: Arm) -> SmallVec<[Arm; 1]> { + noop_flat_map_arm(arm, self) } fn visit_pat(&mut self, p: &mut P) { @@ -174,8 +174,8 @@ pub trait MutVisitor: Sized { noop_visit_foreign_mod(nm, self); } - fn visit_variant(&mut self, v: &mut Variant) { - noop_visit_variant(v, self); + fn flat_map_variant(&mut self, v: Variant) -> SmallVec<[Variant; 1]> { + noop_flat_map_variant(v, self) } fn visit_ident(&mut self, i: &mut Ident) { @@ -225,8 +225,8 @@ pub trait MutVisitor: Sized { noop_visit_attribute(at, self); } - fn visit_arg(&mut self, a: &mut Arg) { - noop_visit_arg(a, self); + fn flat_map_param(&mut self, param: Param) -> SmallVec<[Param; 1]> { + noop_flat_map_param(param, self) } fn visit_generics(&mut self, generics: &mut Generics) { @@ -245,12 +245,8 @@ pub trait MutVisitor: Sized { noop_visit_variant_data(vdata, self); } - fn visit_generic_param(&mut self, param: &mut GenericParam) { - noop_visit_generic_param(param, self); - } - - fn visit_generic_params(&mut self, params: &mut Vec) { - noop_visit_generic_params(params, self); + fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> { + noop_flat_map_generic_param(param, self) } fn visit_tt(&mut self, tt: &mut TokenTree) { @@ -277,8 +273,8 @@ pub trait MutVisitor: Sized { noop_visit_mt(mt, self); } - fn visit_field(&mut self, field: &mut Field) { - noop_visit_field(field, self); + fn flat_map_field(&mut self, f: Field) -> SmallVec<[Field; 1]> { + noop_flat_map_field(f, self) } fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { @@ -300,6 +296,10 @@ pub trait MutVisitor: Sized { fn visit_span(&mut self, _sp: &mut Span) { // Do nothing. } + + fn flat_map_field_pattern(&mut self, fp: FieldPat) -> SmallVec<[FieldPat; 1]> { + noop_flat_map_field_pattern(fp, self) + } } /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful @@ -362,6 +362,26 @@ pub fn visit_method_sig(MethodSig { header, decl }: &mut MethodSi vis.visit_fn_decl(decl); } +pub fn noop_flat_map_field_pattern( + mut fp: FieldPat, + vis: &mut T, +) -> SmallVec<[FieldPat; 1]> { + let FieldPat { + attrs, + id, + ident, + is_shorthand: _, + pat, + span, + } = &mut fp; + vis.visit_id(id); + vis.visit_ident(ident); + vis.visit_pat(pat); + vis.visit_span(span); + visit_thin_attrs(attrs, vis); + smallvec![fp] +} + pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { let UseTree { prefix, kind, span } = use_tree; vis.visit_path(prefix); @@ -382,16 +402,18 @@ pub fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arm( - Arm { attrs, pats, guard, body, span, id }: &mut Arm, +pub fn noop_flat_map_arm( + mut arm: Arm, vis: &mut T, -) { +) -> SmallVec<[Arm; 1]> { + let Arm { attrs, pats, guard, body, span, id } = &mut arm; visit_attrs(attrs, vis); vis.visit_id(id); visit_vec(pats, |pat| vis.visit_pat(pat)); visit_opt(guard, |guard| vis.visit_expr(guard)); vis.visit_expr(body); vis.visit_span(span); + smallvec![arm] } pub fn noop_visit_ty_constraint( @@ -425,7 +447,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } TyKind::BareFn(bft) => { let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut(); - vis.visit_generic_params(generic_params); + generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)), @@ -455,14 +477,17 @@ pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } -pub fn noop_visit_variant(variant: &mut Variant, vis: &mut T) { - let Variant { ident, attrs, id, data, disr_expr, span } = variant; +pub fn noop_flat_map_variant(mut variant: Variant, vis: &mut T) + -> SmallVec<[Variant; 1]> +{ + let Variant { ident, attrs, id, data, disr_expr, span } = &mut variant; vis.visit_ident(ident); visit_attrs(attrs, vis); vis.visit_id(id); vis.visit_variant_data(data); visit_opt(disr_expr, |disr_expr| vis.visit_anon_const(disr_expr)); vis.visit_span(span); + smallvec![variant] } pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: &mut T) { @@ -562,12 +587,14 @@ pub fn noop_visit_meta_item(mi: &mut MetaItem, vis: &mut T) { vis.visit_span(span); } -pub fn noop_visit_arg(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) { +pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> SmallVec<[Param; 1]> { + let Param { attrs, id, pat, span, ty } = &mut param; vis.visit_id(id); visit_thin_attrs(attrs, vis); vis.visit_pat(pat); vis.visit_span(span); vis.visit_ty(ty); + smallvec![param] } pub fn noop_visit_tt(tt: &mut TokenTree, vis: &mut T) { @@ -693,7 +720,7 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); - visit_vec(inputs, |input| vis.visit_arg(input)); + inputs.flat_map_in_place(|param| vis.flat_map_param(param)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), FunctionRetTy::Ty(ty) => vis.visit_ty(ty), @@ -707,8 +734,12 @@ pub fn noop_visit_param_bound(pb: &mut GenericBound, vis: &mut T) } } -pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &mut T) { - let GenericParam { id, ident, attrs, bounds, kind } = param; +pub fn noop_flat_map_generic_param( + mut param: GenericParam, + vis: &mut T +) -> SmallVec<[GenericParam; 1]> +{ + let GenericParam { id, ident, attrs, bounds, kind } = &mut param; vis.visit_id(id); vis.visit_ident(ident); visit_thin_attrs(attrs, vis); @@ -722,10 +753,7 @@ pub fn noop_visit_generic_param(param: &mut GenericParam, vis: &m vis.visit_ty(ty); } } -} - -pub fn noop_visit_generic_params(params: &mut Vec, vis: &mut T){ - visit_vec(params, |param| vis.visit_generic_param(param)); + smallvec![param] } pub fn noop_visit_label(Label { ident }: &mut Label, vis: &mut T) { @@ -739,7 +767,7 @@ fn noop_visit_lifetime(Lifetime { id, ident }: &mut Lifetime, vis pub fn noop_visit_generics(generics: &mut Generics, vis: &mut T) { let Generics { params, where_clause, span } = generics; - vis.visit_generic_params(params); + params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_where_clause(where_clause); vis.visit_span(span); } @@ -755,7 +783,7 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: WherePredicate::BoundPredicate(bp) => { let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp; vis.visit_span(span); - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_ty(bounded_ty); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } @@ -777,9 +805,11 @@ pub fn noop_visit_where_predicate(pred: &mut WherePredicate, vis: pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut T) { match vdata { - VariantData::Struct(fields, ..) => visit_vec(fields, |field| vis.visit_struct_field(field)), + VariantData::Struct(fields, ..) => { + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); + }, VariantData::Tuple(fields, id) => { - visit_vec(fields, |field| vis.visit_struct_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_struct_field(field)); vis.visit_id(id); }, VariantData::Unit(id) => vis.visit_id(id), @@ -793,28 +823,32 @@ pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut Trait pub fn noop_visit_poly_trait_ref(p: &mut PolyTraitRef, vis: &mut T) { let PolyTraitRef { bound_generic_params, trait_ref, span } = p; - vis.visit_generic_params(bound_generic_params); + bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_trait_ref(trait_ref); vis.visit_span(span); } -pub fn noop_visit_struct_field(f: &mut StructField, visitor: &mut T) { - let StructField { span, ident, vis, id, ty, attrs } = f; +pub fn noop_flat_map_struct_field(mut sf: StructField, visitor: &mut T) + -> SmallVec<[StructField; 1]> +{ + let StructField { span, ident, vis, id, ty, attrs } = &mut sf; visitor.visit_span(span); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_vis(vis); visitor.visit_id(id); visitor.visit_ty(ty); visit_attrs(attrs, visitor); + smallvec![sf] } -pub fn noop_visit_field(f: &mut Field, vis: &mut T) { - let Field { ident, expr, span, is_shorthand: _, attrs, id } = f; +pub fn noop_flat_map_field(mut f: Field, vis: &mut T) -> SmallVec<[Field; 1]> { + let Field { ident, expr, span, is_shorthand: _, attrs, id } = &mut f; vis.visit_ident(ident); vis.visit_expr(expr); vis.visit_id(id); vis.visit_span(span); visit_thin_attrs(attrs, vis); + smallvec![f] } pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mut T) { @@ -858,7 +892,7 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_generics(generics); } ItemKind::Enum(EnumDef { variants }, generics) => { - visit_vec(variants, |variant| vis.visit_variant(variant)); + variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); vis.visit_generics(generics); } ItemKind::Struct(variant_data, generics) | @@ -1042,13 +1076,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { } PatKind::Struct(path, fields, _etc) => { vis.visit_path(path); - for FieldPat { ident, pat, is_shorthand: _, attrs, id, span } in fields { - vis.visit_ident(ident); - vis.visit_id(id); - vis.visit_pat(pat); - visit_thin_attrs(attrs, vis); - vis.visit_span(span); - }; + fields.flat_map_in_place(|field| vis.flat_map_field_pattern(field)); } PatKind::Box(inner) => vis.visit_pat(inner), PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner), @@ -1130,7 +1158,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, } ExprKind::Match(expr, arms) => { vis.visit_expr(expr); - visit_vec(arms, |arm| vis.visit_arm(arm)); + arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); } ExprKind::Closure(_capture_by, asyncness, _movability, decl, body, span) => { vis.visit_asyncness(asyncness); @@ -1193,7 +1221,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, ExprKind::Mac(mac) => vis.visit_mac(mac), ExprKind::Struct(path, fields, expr) => { vis.visit_path(path); - visit_vec(fields, |field| vis.visit_field(field)); + fields.flat_map_in_place(|field| vis.flat_map_field(field)); visit_opt(expr, |expr| vis.visit_expr(expr)); }, ExprKind::Paren(expr) => { diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a42da1123600a..671178223f503 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -19,11 +19,10 @@ const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; impl<'a> Parser<'a> { - crate fn parse_arg_attributes(&mut self) -> PResult<'a, Vec> { + crate fn parse_param_attributes(&mut self) -> PResult<'a, Vec> { let attrs = self.parse_outer_attributes()?; - attrs.iter().for_each(|a| - self.sess.param_attr_spans.borrow_mut().push(a.span) - ); + self.sess.gated_spans.param_attrs.borrow_mut() + .extend(attrs.iter().map(|a| a.span)); Ok(attrs) } diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 1fbf28fb83016..d4e661d1a38b7 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,5 +1,5 @@ use crate::ast::{ - self, Arg, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, VariantData, }; use crate::feature_gate::{feature_err, UnstableFeatures}; @@ -18,7 +18,7 @@ use log::{debug, trace}; use std::mem; /// Creates a placeholder argument. -crate fn dummy_arg(ident: Ident) -> Arg { +crate fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), @@ -29,7 +29,7 @@ crate fn dummy_arg(ident: Ident) -> Arg { span: ident.span, id: ast::DUMMY_NODE_ID }; - Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } + Param { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) } } pub enum Error { @@ -1183,7 +1183,7 @@ impl<'a> Parser<'a> { Err(err) } - crate fn eat_incorrect_doc_comment_for_arg_type(&mut self) { + crate fn eat_incorrect_doc_comment_for_param_type(&mut self) { if let token::DocComment(_) = self.token.kind { self.struct_span_err( self.token.span, @@ -1211,7 +1211,7 @@ impl<'a> Parser<'a> { } } - crate fn argument_without_type( + crate fn parameter_without_type( &mut self, err: &mut DiagnosticBuilder<'_>, pat: P, @@ -1286,13 +1286,13 @@ impl<'a> Parser<'a> { Ok((pat, ty)) } - crate fn recover_bad_self_arg( + crate fn recover_bad_self_param( &mut self, - mut arg: ast::Arg, + mut param: ast::Param, is_trait_item: bool, - ) -> PResult<'a, ast::Arg> { - let sp = arg.pat.span; - arg.ty.node = TyKind::Err; + ) -> PResult<'a, ast::Param> { + let sp = param.pat.span; + param.ty.node = TyKind::Err; let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); if is_trait_item { err.span_label(sp, "must be the first associated function parameter"); @@ -1301,7 +1301,7 @@ impl<'a> Parser<'a> { err.note("`self` is only valid as the first parameter of an associated function"); } err.emit(); - Ok(arg) + Ok(param) } crate fn consume_block(&mut self, delim: token::DelimToken) { @@ -1344,15 +1344,15 @@ impl<'a> Parser<'a> { err } - /// Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. /// /// This is necessary because at this point we don't know whether we parsed a function with - /// anonymous arguments or a function with names but no types. In order to minimize - /// unecessary errors, we assume the arguments are in the shape of `fn foo(a, b, c)` where - /// the arguments are *names* (so we don't emit errors about not being able to find `b` in + /// anonymous parameters or a function with names but no types. In order to minimize + /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where + /// the parameters are *names* (so we don't emit errors about not being able to find `b` in /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, - /// we deduplicate them to not complain about duplicated argument names. - crate fn deduplicate_recovered_arg_names(&self, fn_inputs: &mut Vec) { + /// we deduplicate them to not complain about duplicated parameter names. + crate fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index a915aa42fd15a..652ae95c85349 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -10,7 +10,14 @@ use errors::{Handler, emitter::EmitterWriter}; use syntax_pos::{BytePos, Span}; fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new(Box::new(io::sink()), Some(sm.clone()), false, false, false); + let emitter = EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + ); ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) } @@ -28,10 +35,11 @@ fn t1() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - let mut string_reader = setup(&sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n" - .to_string()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); assert_eq!(string_reader.next_token(), token::Comment); assert_eq!(string_reader.next_token(), token::Whitespace); let tok1 = string_reader.next_token(); @@ -127,8 +135,10 @@ fn character_a() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None)); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); }) } @@ -137,8 +147,10 @@ fn character_space() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None)); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); }) } @@ -147,8 +159,10 @@ fn character_escaped() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None)); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); }) } @@ -157,8 +171,10 @@ fn lifetime_name() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc"))); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); }) } @@ -167,8 +183,10 @@ fn raw_string() { with_default_globals(|| { let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None)); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); }) } @@ -179,11 +197,15 @@ fn literal_suffixes() { let sh = mk_sess(sm.clone()); macro_rules! test { ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!(setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix"))); + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); // with a whitespace separator: - assert_eq!(setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None)); + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); }} } @@ -197,12 +219,18 @@ fn literal_suffixes() { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); - assert_eq!(setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us"))); - assert_eq!(setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix"))); - assert_eq!(setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix"))); + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); }) } diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 6409acba573ad..36233de3cfb57 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -104,7 +104,7 @@ impl LitKind { Ok(match kind { token::Bool => { - assert!(symbol == kw::True || symbol == kw::False); + assert!(symbol.is_bool_lit()); LitKind::Bool(symbol == kw::True) } token::Byte => return unescape_byte(&symbol.as_str()) @@ -261,7 +261,7 @@ impl Lit { /// Converts arbitrary token into an AST literal. crate fn from_token(token: &Token) -> Result { let lit = match token.kind { - token::Ident(name, false) if name == kw::True || name == kw::False => + token::Ident(name, false) if name.is_bool_lit() => token::Lit::new(token::Bool, name, None), token::Literal(lit) => lit, diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b1f3612a839a2..b1af4806e2d78 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -39,6 +39,22 @@ crate mod unescape_error_reporting; pub type PResult<'a, T> = Result>; +/// Collected spans during parsing for places where a certain feature was +/// used and should be feature gated accordingly in `check_crate`. +#[derive(Default)] +pub struct GatedSpans { + /// Spans collected for gating `param_attrs`, e.g. `fn foo(#[attr] x: u8) {}`. + pub param_attrs: Lock>, + /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. + pub let_chains: Lock>, + /// Spans collected for gating `async_closure`, e.g. `async || ..`. + pub async_closure: Lock>, + /// Spans collected for gating `yield e?` expressions (`generators` gate). + pub yields: Lock>, + /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. + pub or_patterns: Lock>, +} + /// Info about a parsing session. pub struct ParseSess { pub span_diagnostic: Handler, @@ -58,16 +74,8 @@ pub struct ParseSess { /// operation token that followed it, but that the parser cannot identify without further /// analysis. pub ambiguous_block_expr_parse: Lock>, - pub param_attr_spans: Lock>, - // Places where `let` exprs were used and should be feature gated according to `let_chains`. - pub let_chains_spans: Lock>, - // Places where `async || ..` exprs were used and should be feature gated. - pub async_closure_spans: Lock>, - // Places where `yield e?` exprs were used and should be feature gated. - pub yield_spans: Lock>, pub injected_crate_name: Once, - // Places where or-patterns e.g. `Some(Foo | Bar)` were used and should be feature gated. - pub or_pattern_spans: Lock>, + pub gated_spans: GatedSpans, } impl ParseSess { @@ -93,12 +101,8 @@ impl ParseSess { buffered_lints: Lock::new(vec![]), edition: ExpnId::root().expn_data().edition, ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), - param_attr_spans: Lock::new(Vec::new()), - let_chains_spans: Lock::new(Vec::new()), - async_closure_spans: Lock::new(Vec::new()), - yield_spans: Lock::new(Vec::new()), injected_crate_name: Once::new(), - or_pattern_spans: Lock::new(Vec::new()), + gated_spans: GatedSpans::default(), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 89725d8b3395c..49b05551bae86 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -10,7 +10,7 @@ pub use path::PathStyle; mod stmt; mod generics; -use crate::ast::{self, AttrStyle, Attribute, Arg, BindingMode, StrStyle, SelfKind}; +use crate::ast::{self, AttrStyle, Attribute, Param, BindingMode, StrStyle, SelfKind}; use crate::ast::{FnDecl, Ident, IsAsync, MacDelimiter, Mutability, TyKind}; use crate::ast::{Visibility, VisibilityKind, Unsafety, CrateSugar}; use crate::source_map::{self, respan}; @@ -375,10 +375,11 @@ impl<'a> Parser<'a> { if let Some(directory) = directory { parser.directory = directory; } else if !parser.token.span.is_dummy() { - if let FileName::Real(mut path) = - sess.source_map().span_to_unmapped_path(parser.token.span) { - path.pop(); - parser.directory.path = Cow::from(path); + if let Some(FileName::Real(path)) = + &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { + if let Some(directory_path) = path.parent() { + parser.directory.path = Cow::from(directory_path.to_path_buf()); + } } } @@ -970,30 +971,27 @@ impl<'a> Parser<'a> { /// Skips unexpected attributes and doc comments in this position and emits an appropriate /// error. - /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general( + /// This version of parse param doesn't necessarily require identifier names. + fn parse_param_general( &mut self, is_trait_item: bool, allow_c_variadic: bool, - is_name_required: F, - ) -> PResult<'a, Arg> - where - F: Fn(&token::Token) -> bool - { + is_name_required: impl Fn(&token::Token) -> bool, + ) -> PResult<'a, Param> { let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; - if let Some(mut arg) = self.parse_self_arg()? { - arg.attrs = attrs.into(); - return self.recover_bad_self_arg(arg, is_trait_item); + let attrs = self.parse_param_attributes()?; + if let Some(mut param) = self.parse_self_param()? { + param.attrs = attrs.into(); + return self.recover_bad_self_param(param, is_trait_item); } let is_name_required = is_name_required(&self.token); let (pat, ty) = if is_name_required || self.is_named_argument() { - debug!("parse_arg_general parse_pat (is_name_required:{})", is_name_required); + debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required); - let pat = self.parse_pat(Some("argument name"))?; + let pat = self.parse_fn_param_pat()?; if let Err(mut err) = self.expect(&token::Colon) { - if let Some(ident) = self.argument_without_type( + if let Some(ident) = self.parameter_without_type( &mut err, pat, is_name_required, @@ -1006,12 +1004,12 @@ impl<'a> Parser<'a> { } } - self.eat_incorrect_doc_comment_for_arg_type(); + self.eat_incorrect_doc_comment_for_param_type(); (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { - debug!("parse_arg_general ident_to_pat"); + debug!("parse_param_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); - self.eat_incorrect_doc_comment_for_arg_type(); + self.eat_incorrect_doc_comment_for_param_type(); let mut ty = self.parse_ty_common(true, true, allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { @@ -1042,7 +1040,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.token.span); - Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) + Ok(Param { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty }) } /// Parses mutability (`mut` or nothing). @@ -1188,26 +1186,26 @@ impl<'a> Parser<'a> { } - fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool) - -> PResult<'a, (Vec , bool)> { + fn parse_fn_params(&mut self, named_params: bool, allow_c_variadic: bool) + -> PResult<'a, (Vec , bool)> { let sp = self.token.span; let mut c_variadic = false; - let (args, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { + let (params, _): (Vec>, _) = self.parse_paren_comma_seq(|p| { let do_not_enforce_named_arguments_for_c_variadic = |token: &token::Token| -> bool { if token == &token::DotDotDot { false } else { - named_args + named_params } }; - match p.parse_arg_general( + match p.parse_param_general( false, allow_c_variadic, do_not_enforce_named_arguments_for_c_variadic ) { - Ok(arg) => { - if let TyKind::CVarArgs = arg.ty.node { + Ok(param) => { + if let TyKind::CVarArgs = param.ty.node { c_variadic = true; if p.token != token::CloseDelim(token::Paren) { let span = p.token.span; @@ -1215,10 +1213,10 @@ impl<'a> Parser<'a> { "`...` must be the last argument of a C-variadic function"); Ok(None) } else { - Ok(Some(arg)) + Ok(Some(param)) } } else { - Ok(Some(arg)) + Ok(Some(param)) } }, Err(mut e) => { @@ -1233,20 +1231,20 @@ impl<'a> Parser<'a> { } })?; - let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); + let params: Vec<_> = params.into_iter().filter_map(|x| x).collect(); - if c_variadic && args.len() <= 1 { + if c_variadic && params.len() <= 1 { self.span_err(sp, "C-variadic function must be declared with at least one named argument"); } - Ok((args, c_variadic)) + Ok((params, c_variadic)) } - /// Returns the parsed optional self argument and whether a self shortcut was used. + /// Returns the parsed optional self parameter and whether a self shortcut was used. /// - /// See `parse_self_arg_with_attrs` to collect attributes. - fn parse_self_arg(&mut self) -> PResult<'a, Option> { + /// See `parse_self_param_with_attrs` to collect attributes. + fn parse_self_param(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token.kind { // Preserve hygienic context. token::Ident(name, _) => @@ -1351,49 +1349,51 @@ impl<'a> Parser<'a> { }; let eself = source_map::respan(eself_lo.to(eself_hi), eself); - Ok(Some(Arg::from_self(ThinVec::default(), eself, eself_ident))) + Ok(Some(Param::from_self(ThinVec::default(), eself, eself_ident))) } - /// Returns the parsed optional self argument with attributes and whether a self + /// Returns the parsed optional self parameter with attributes and whether a self /// shortcut was used. - fn parse_self_arg_with_attrs(&mut self) -> PResult<'a, Option> { - let attrs = self.parse_arg_attributes()?; - let arg_opt = self.parse_self_arg()?; - Ok(arg_opt.map(|mut arg| { - arg.attrs = attrs.into(); - arg + fn parse_self_parameter_with_attrs(&mut self) -> PResult<'a, Option> { + let attrs = self.parse_param_attributes()?; + let param_opt = self.parse_self_param()?; + Ok(param_opt.map(|mut param| { + param.attrs = attrs.into(); + param })) } /// Parses the parameter list and result type of a function that may have a `self` parameter. - fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> PResult<'a, P> - where F: FnMut(&mut Parser<'a>) -> PResult<'a, Arg>, + fn parse_fn_decl_with_self(&mut self, parse_param_fn: F) -> PResult<'a, P> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, Param>, { self.expect(&token::OpenDelim(token::Paren))?; // Parse optional self argument. - let self_arg = self.parse_self_arg_with_attrs()?; + let self_param = self.parse_self_parameter_with_attrs()?; // Parse the rest of the function parameter list. let sep = SeqSep::trailing_allowed(token::Comma); - let (mut fn_inputs, recovered) = if let Some(self_arg) = self_arg { + let (mut fn_inputs, recovered) = if let Some(self_param) = self_param { if self.check(&token::CloseDelim(token::Paren)) { - (vec![self_arg], false) + (vec![self_param], false) } else if self.eat(&token::Comma) { - let mut fn_inputs = vec![self_arg]; + let mut fn_inputs = vec![self_param]; let (mut input, _, recovered) = self.parse_seq_to_before_end( - &token::CloseDelim(token::Paren), sep, parse_arg_fn)?; + &token::CloseDelim(token::Paren), sep, parse_param_fn)?; fn_inputs.append(&mut input); (fn_inputs, recovered) } else { match self.expect_one_of(&[], &[]) { Err(err) => return Err(err), - Ok(recovered) => (vec![self_arg], recovered), + Ok(recovered) => (vec![self_param], recovered), } } } else { let (input, _, recovered) = - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?; + self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), + sep, + parse_param_fn)?; (input, recovered) }; @@ -1401,8 +1401,8 @@ impl<'a> Parser<'a> { // Parse closing paren and return type. self.expect(&token::CloseDelim(token::Paren))?; } - // Replace duplicated recovered arguments with `_` pattern to avoid unecessary errors. - self.deduplicate_recovered_arg_names(&mut fn_inputs); + // Replace duplicated recovered params with `_` pattern to avoid unecessary errors. + self.deduplicate_recovered_params_names(&mut fn_inputs); Ok(P(FnDecl { inputs: fn_inputs, diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index ccc6bd1506709..5b9f0f1df6718 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,12 +1,13 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle}; use super::{BlockMode, SemiColonMode}; use super::{SeqSep, TokenExpectType}; +use super::pat::{GateOr, PARAM_EXPECTED}; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::ptr::P; use crate::ast::{self, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode}; use crate::ast::{Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm}; -use crate::ast::{Ty, TyKind, FunctionRetTy, Arg, FnDecl}; +use crate::ast::{Ty, TyKind, FunctionRetTy, Param, FnDecl}; use crate::ast::{BinOpKind, BinOp, UnOp}; use crate::ast::{Mac, AnonConst, Field}; @@ -999,7 +1000,7 @@ impl<'a> Parser<'a> { } let span = lo.to(hi); - self.sess.yield_spans.borrow_mut().push(span); + self.sess.gated_spans.yields.borrow_mut().push(span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { @@ -1111,7 +1112,7 @@ impl<'a> Parser<'a> { }; if asyncness.is_async() { // Feature gate `async ||` closures. - self.sess.async_closure_spans.borrow_mut().push(self.prev_span); + self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span); } let capture_clause = self.parse_capture_clause(); @@ -1156,7 +1157,7 @@ impl<'a> Parser<'a> { &[&token::BinOp(token::Or), &token::OrOr], SeqSep::trailing_allowed(token::Comma), TokenExpectType::NoExpect, - |p| p.parse_fn_block_arg() + |p| p.parse_fn_block_param() )?.0; self.expect_or()?; args @@ -1171,11 +1172,11 @@ impl<'a> Parser<'a> { })) } - /// Parses an argument in a lambda header (e.g., `|arg, arg|`). - fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> { + /// Parses a parameter in a lambda header (e.g., `|arg, arg|`). + fn parse_fn_block_param(&mut self) -> PResult<'a, Param> { let lo = self.token.span; - let attrs = self.parse_arg_attributes()?; - let pat = self.parse_pat(Some("argument name"))?; + let attrs = self.parse_param_attributes()?; + let pat = self.parse_pat(PARAM_EXPECTED)?; let t = if self.eat(&token::Colon) { self.parse_ty()? } else { @@ -1186,7 +1187,7 @@ impl<'a> Parser<'a> { }) }; let span = lo.to(self.token.span); - Ok(Arg { + Ok(Param { attrs: attrs.into(), ty: t, pat, @@ -1234,26 +1235,27 @@ impl<'a> Parser<'a> { if let ExprKind::Let(..) = cond.node { // Remove the last feature gating of a `let` expression since it's stable. - let last = self.sess.let_chains_spans.borrow_mut().pop(); + let last = self.sess.gated_spans.let_chains.borrow_mut().pop(); debug_assert_eq!(cond.span, last.unwrap()); } Ok(cond) } - /// Parses a `let $pats = $expr` pseudo-expression. + /// Parses a `let $pat = $expr` pseudo-expression. /// The `let` token has already been eaten. fn parse_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(GateOr::No)?; self.expect(&token::Eq)?; let expr = self.with_res( Restrictions::NO_STRUCT_LITERAL, |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) )?; let span = lo.to(expr.span); - self.sess.let_chains_spans.borrow_mut().push(span); - Ok(self.mk_expr(span, ExprKind::Let(pats, expr), attrs)) + self.sess.gated_spans.let_chains.borrow_mut().push(span); + Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs)) } /// `else` token already eaten @@ -1283,7 +1285,7 @@ impl<'a> Parser<'a> { _ => None, }; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(GateOr::Yes)?; if !self.eat_keyword(kw::In) { let in_span = self.prev_span.between(self.token.span); self.struct_span_err(in_span, "missing `in` in `for` loop") @@ -1387,7 +1389,8 @@ impl<'a> Parser<'a> { crate fn parse_arm(&mut self) -> PResult<'a, Arm> { let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - let pats = self.parse_pats()?; + // FIXME(or_patterns, Centril | dlrobertson): use `parse_top_pat` instead. + let pat = self.parse_top_pat_unpack(GateOr::No)?; let guard = if self.eat_keyword(kw::If) { Some(self.parse_expr()?) } else { @@ -1448,7 +1451,7 @@ impl<'a> Parser<'a> { Ok(ast::Arm { attrs, - pats, + pats: pat, // FIXME(or_patterns, Centril | dlrobertson): this should just be `pat,`. guard, body: expr, span: lo.to(hi), diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 72819c9966035..59a3ade9c30e5 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -422,7 +422,7 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) { let ident = self.parse_ident().unwrap(); self.bump(); // `(` - let kw_name = if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + let kw_name = if let Ok(Some(_)) = self.parse_self_parameter_with_attrs() .map_err(|mut e| e.cancel()) { "method" @@ -475,7 +475,7 @@ impl<'a> Parser<'a> { self.eat_to_tokens(&[&token::Gt]); self.bump(); // `>` let (kw, kw_name, ambiguous) = if self.eat(&token::OpenDelim(token::Paren)) { - if let Ok(Some(_)) = self.parse_self_arg_with_attrs() + if let Ok(Some(_)) = self.parse_self_parameter_with_attrs() .map_err(|mut e| e.cancel()) { ("fn", "method", false) @@ -825,6 +825,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(1, &[ kw::Impl, kw::Const, + kw::Async, kw::Fn, kw::Unsafe, kw::Extern, @@ -860,7 +861,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| { - p.parse_arg_general(true, false, |_| true) + p.parse_param_general(true, false, |_| true) })?; generics.where_clause = self.parse_where_clause()?; *at_end = true; @@ -1039,7 +1040,7 @@ impl<'a> Parser<'a> { // We don't allow argument names to be left off in edition 2018. let is_name_required = p.token.span.rust_2018(); - p.parse_arg_general(true, false, |_| is_name_required) + p.parse_param_general(true, false, |_| is_name_required) })?; generics.where_clause = self.parse_where_clause()?; @@ -1290,7 +1291,7 @@ impl<'a> Parser<'a> { /// Parses the argument list and result type of a function declaration. fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { - let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; + let (args, c_variadic) = self.parse_fn_params(true, allow_c_variadic)?; let ret_ty = self.parse_ret_ty(true)?; Ok(P(FnDecl { diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index fd458aec74331..823f880337d13 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -4,6 +4,7 @@ use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac}; use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; +use crate::mut_visit::{noop_visit_pat, MutVisitor}; use crate::parse::token::{self}; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; @@ -12,80 +13,184 @@ use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder}; +type Expected = Option<&'static str>; + +/// `Expected` for function and lambda parameter patterns. +pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); + +/// Whether or not an or-pattern should be gated when occurring in the current context. +#[derive(PartialEq)] +pub enum GateOr { Yes, No } + +/// Whether or not to recover a `,` when parsing or-patterns. +#[derive(PartialEq, Copy, Clone)] +enum RecoverComma { Yes, No } + impl<'a> Parser<'a> { /// Parses a pattern. - pub fn parse_pat( + /// + /// Corresponds to `pat` in RFC 2535 and does not admit or-patterns + /// at the top level. Used when parsing the parameters of lambda expressions, + /// functions, function pointers, and `pat` macro fragments. + pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P> { + self.parse_pat_with_range_pat(true, expected) + } + + // FIXME(or_patterns, Centril | dlrobertson): + // remove this and use `parse_top_pat` everywhere it is used instead. + pub(super) fn parse_top_pat_unpack(&mut self, gate_or: GateOr) -> PResult<'a, Vec>> { + self.parse_top_pat(gate_or) + .map(|pat| pat.and_then(|pat| match pat.node { + PatKind::Or(pats) => pats, + node => vec![self.mk_pat(pat.span, node)], + })) + } + + /// Entry point to the main pattern parser. + /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. + pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { + // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). + let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let leading_vert_span = self.prev_span; + + // Parse the possibly-or-pattern. + let pat = self.parse_pat_with_or(None, gate_or, RecoverComma::Yes)?; + + // If we parsed a leading `|` which should be gated, + // and no other gated or-pattern has been parsed thus far, + // then we should really gate the leading `|`. + // This complicated procedure is done purely for diagnostics UX. + if gated_leading_vert { + let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); + if or_pattern_spans.is_empty() { + or_pattern_spans.push(leading_vert_span); + } + } + + Ok(pat) + } + + /// Parse the pattern for a function or function pointer parameter. + /// Special recovery is provided for or-patterns and leading `|`. + pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { + self.recover_leading_vert("not allowed in a parameter pattern"); + let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; + + if let PatKind::Or(..) = &pat.node { + self.ban_illegal_fn_param_or_pat(&pat); + } + + Ok(pat) + } + + /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens. + fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) { + let msg = "wrap the pattern in parenthesis"; + let fix = format!("({})", pprust::pat_to_string(pat)); + self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis") + .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable) + .emit(); + } + + /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`). + /// Corresponds to `pat` in RFC 2535. + fn parse_pat_with_or( &mut self, - expected: Option<&'static str> + expected: Expected, + gate_or: GateOr, + rc: RecoverComma, ) -> PResult<'a, P> { - self.parse_pat_with_range_pat(true, expected) + // Parse the first pattern. + let first_pat = self.parse_pat(expected)?; + self.maybe_recover_unexpected_comma(first_pat.span, rc)?; + + // If the next token is not a `|`, + // this is not an or-pattern and we should exit here. + if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr { + return Ok(first_pat) + } + + let lo = first_pat.span; + let mut pats = vec![first_pat]; + while self.eat_or_separator() { + let pat = self.parse_pat(expected).map_err(|mut err| { + err.span_label(lo, "while parsing this or-pattern starting here"); + err + })?; + self.maybe_recover_unexpected_comma(pat.span, rc)?; + pats.push(pat); + } + let or_pattern_span = lo.to(self.prev_span); + + // Feature gate the or-pattern if instructed: + if gate_or == GateOr::Yes { + self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + } + + Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } - /// Parses patterns, separated by '|' s. - pub(super) fn parse_pats(&mut self) -> PResult<'a, Vec>> { - // Allow a '|' before the pats (RFC 1925 + RFC 2530) - self.eat(&token::BinOp(token::Or)); - - let mut pats = Vec::new(); - loop { - pats.push(self.parse_top_level_pat()?); - - if self.token == token::OrOr { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to specify multiple patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + /// Eat the or-pattern `|` separator. + /// If instead a `||` token is encountered, recover and pretend we parsed `|`. + fn eat_or_separator(&mut self) -> bool { + match self.token.kind { + token::OrOr => { + // Found `||`; Recover and pretend we parsed `|`. + self.ban_unexpected_or_or(); self.bump(); - } else if self.eat(&token::BinOp(token::Or)) { - // This is a No-op. Continue the loop to parse the next - // pattern. - } else { - return Ok(pats); + true } - }; + _ => self.eat(&token::BinOp(token::Or)), + } } - /// A wrapper around `parse_pat` with some special error handling for the - /// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast - /// to subpatterns within such). - pub(super) fn parse_top_level_pat(&mut self) -> PResult<'a, P> { - let pat = self.parse_pat(None)?; - if self.token == token::Comma { - // An unexpected comma after a top-level pattern is a clue that the - // user (perhaps more accustomed to some other language) forgot the - // parentheses in what should have been a tuple pattern; return a - // suggestion-enhanced error here rather than choking on the comma - // later. - let comma_span = self.token.span; - self.bump(); - if let Err(mut err) = self.skip_pat_list() { - // We didn't expect this to work anyway; we just wanted - // to advance to the end of the comma-sequence so we know - // the span to suggest parenthesizing - err.cancel(); - } - let seq_span = pat.span.to(self.prev_span); - let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); - if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { - err.span_suggestion( - seq_span, - "try adding parentheses to match on a tuple..", - format!("({})", seq_snippet), - Applicability::MachineApplicable - ).span_suggestion( - seq_span, - "..or a vertical bar to match on multiple alternatives", - format!("{}", seq_snippet.replace(",", " |")), - Applicability::MachineApplicable - ); - } - return Err(err); + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. + fn ban_unexpected_or_or(&mut self) { + self.struct_span_err(self.token.span, "unexpected token `||` after pattern") + .span_suggestion( + self.token.span, + "use a single `|` to separate multiple alternative patterns", + "|".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + } + + /// Some special error handling for the "top-level" patterns in a match arm, + /// `for` loop, `let`, &c. (in contrast to subpatterns within such). + fn maybe_recover_unexpected_comma(&mut self, lo: Span, rc: RecoverComma) -> PResult<'a, ()> { + if rc == RecoverComma::No || self.token != token::Comma { + return Ok(()); } - Ok(pat) + + // An unexpected comma after a top-level pattern is a clue that the + // user (perhaps more accustomed to some other language) forgot the + // parentheses in what should have been a tuple pattern; return a + // suggestion-enhanced error here rather than choking on the comma later. + let comma_span = self.token.span; + self.bump(); + if let Err(mut err) = self.skip_pat_list() { + // We didn't expect this to work anyway; we just wanted to advance to the + // end of the comma-sequence so we know the span to suggest parenthesizing. + err.cancel(); + } + let seq_span = lo.to(self.prev_span); + let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern"); + if let Ok(seq_snippet) = self.span_to_snippet(seq_span) { + err.span_suggestion( + seq_span, + "try adding parentheses to match on a tuple..", + format!("({})", seq_snippet), + Applicability::MachineApplicable + ) + .span_suggestion( + seq_span, + "..or a vertical bar to match on multiple alternatives", + format!("{}", seq_snippet.replace(",", " |")), + Applicability::MachineApplicable + ); + } + Err(err) } /// Parse and throw away a parentesized comma separated @@ -100,32 +205,26 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses a pattern, that may be a or-pattern (e.g. `Some(Foo | Bar)`). - fn parse_pat_with_or(&mut self, expected: Option<&'static str>) -> PResult<'a, P> { - // Parse the first pattern. - let first_pat = self.parse_pat(expected)?; - - // If the next token is not a `|`, this is not an or-pattern and - // we should exit here. - if !self.check(&token::BinOp(token::Or)) { - return Ok(first_pat) - } + /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. + /// See `parse_pat_with_or` for details on parsing or-patterns. + fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { + self.recover_leading_vert("only allowed in a top-level pattern"); + self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) + } - let lo = first_pat.span; + /// Recover if `|` or `||` is here. + /// The user is thinking that a leading `|` is allowed in this position. + fn recover_leading_vert(&mut self, ctx: &str) { + if let token::BinOp(token::Or) | token::OrOr = self.token.kind { + let span = self.token.span; + let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - let mut pats = vec![first_pat]; + self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) + .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) + .emit(); - while self.eat(&token::BinOp(token::Or)) { - pats.push(self.parse_pat_with_range_pat( - true, expected - )?); + self.bump(); } - - let or_pattern_span = lo.to(self.prev_span); - - self.sess.or_pattern_spans.borrow_mut().push(or_pattern_span); - - Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) } /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are @@ -133,7 +232,7 @@ impl<'a> Parser<'a> { fn parse_pat_with_range_pat( &mut self, allow_range_pat: bool, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); @@ -144,7 +243,11 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Paren) => self.parse_pat_tuple_or_parens()?, token::OpenDelim(token::Bracket) => { // Parse `[pat, pat,...]` as a slice pattern. - PatKind::Slice(self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?.0) + let (pats, _) = self.parse_delim_comma_seq( + token::Bracket, + |p| p.parse_pat_with_or_inner(), + )?; + PatKind::Slice(pats) } token::DotDot => { self.bump(); @@ -171,7 +274,7 @@ impl<'a> Parser<'a> { // Parse _ PatKind::Wild } else if self.eat_keyword(kw::Mut) { - self.recover_pat_ident_mut_first()? + self.parse_pat_ident_mut()? } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); @@ -179,13 +282,12 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Box) { // Parse `box pat` PatKind::Box(self.parse_pat_with_range_pat(false, None)?) - } else if self.token.is_ident() && !self.token.is_reserved_ident() && - self.parse_as_ident() { + } else if self.can_be_ident_pat() { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. self.parse_pat_ident(BindingMode::ByValue(Mutability::Immutable))? - } else if self.token.is_path_start() { + } else if self.is_start_of_pat_with_path() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { // Parse a qualified path @@ -255,7 +357,7 @@ impl<'a> Parser<'a> { } /// Parse `&pat` / `&mut pat`. - fn parse_pat_deref(&mut self, expected: Option<&'static str>) -> PResult<'a, PatKind> { + fn parse_pat_deref(&mut self, expected: Expected) -> PResult<'a, PatKind> { self.expect_and()?; let mutbl = self.parse_mutability(); @@ -271,9 +373,7 @@ impl<'a> Parser<'a> { /// Parse a tuple or parenthesis pattern. fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> { - let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| { - p.parse_pat_with_or(None) - })?; + let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; // Here, `(pat,)` is a tuple pattern. // For backward compatibility, `(..)` is a tuple pattern as well. @@ -284,24 +384,108 @@ impl<'a> Parser<'a> { }) } + /// Parse a mutable binding with the `mut` token already eaten. + fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> { + let mut_span = self.prev_span; + + if self.eat_keyword(kw::Ref) { + return self.recover_mut_ref_ident(mut_span) + } + + self.recover_additional_muts(); + + // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. + if let token::Interpolated(ref nt) = self.token.kind { + if let token::NtPat(_) = **nt { + self.expected_ident_found().emit(); + } + } + + // Parse the pattern we hope to be an identifier. + let mut pat = self.parse_pat(Some("identifier"))?; + + // Add `mut` to any binding in the parsed pattern. + let changed_any_binding = Self::make_all_value_bindings_mutable(&mut pat); + + // Unwrap; If we don't have `mut $ident`, error. + let pat = pat.into_inner(); + match &pat.node { + PatKind::Ident(..) => {} + _ => self.ban_mut_general_pat(mut_span, &pat, changed_any_binding), + } + + Ok(pat.node) + } + /// Recover on `mut ref? ident @ pat` and suggest /// that the order of `mut` and `ref` is incorrect. - fn recover_pat_ident_mut_first(&mut self) -> PResult<'a, PatKind> { - let mutref_span = self.prev_span.to(self.token.span); - let binding_mode = if self.eat_keyword(kw::Ref) { - self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") - .span_suggestion( - mutref_span, - "try switching the order", - "ref mut".into(), - Applicability::MachineApplicable - ) - .emit(); - BindingMode::ByRef(Mutability::Mutable) + fn recover_mut_ref_ident(&mut self, lo: Span) -> PResult<'a, PatKind> { + let mutref_span = lo.to(self.prev_span); + self.struct_span_err(mutref_span, "the order of `mut` and `ref` is incorrect") + .span_suggestion( + mutref_span, + "try switching the order", + "ref mut".into(), + Applicability::MachineApplicable + ) + .emit(); + + self.parse_pat_ident(BindingMode::ByRef(Mutability::Mutable)) + } + + /// Turn all by-value immutable bindings in a pattern into mutable bindings. + /// Returns `true` if any change was made. + fn make_all_value_bindings_mutable(pat: &mut P) -> bool { + struct AddMut(bool); + impl MutVisitor for AddMut { + fn visit_pat(&mut self, pat: &mut P) { + if let PatKind::Ident(BindingMode::ByValue(ref mut m @ Mutability::Immutable), ..) + = pat.node + { + *m = Mutability::Mutable; + self.0 = true; + } + noop_visit_pat(pat, self); + } + } + + let mut add_mut = AddMut(false); + add_mut.visit_pat(pat); + add_mut.0 + } + + /// Error on `mut $pat` where `$pat` is not an ident. + fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) { + let span = lo.to(pat.span); + let fix = pprust::pat_to_string(&pat); + let (problem, suggestion) = if changed_any_binding { + ("`mut` must be attached to each individual binding", "add `mut` to each binding") } else { - BindingMode::ByValue(Mutability::Mutable) + ("`mut` must be followed by a named binding", "remove the `mut` prefix") }; - self.parse_pat_ident(binding_mode) + self.struct_span_err(span, problem) + .span_suggestion(span, suggestion, fix, Applicability::MachineApplicable) + .note("`mut` may be followed by `variable` and `variable @ pattern`") + .emit() + } + + /// Eat any extraneous `mut`s and error + recover if we ate any. + fn recover_additional_muts(&mut self) { + let lo = self.token.span; + while self.eat_keyword(kw::Mut) {} + if lo == self.token.span { + return; + } + + let span = lo.to(self.prev_span); + self.struct_span_err(span, "`mut` on a binding may not be repeated") + .span_suggestion( + span, + "remove the additional `mut`s", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); } /// Parse macro invocation @@ -361,7 +545,7 @@ impl<'a> Parser<'a> { fn fatal_unexpected_non_pat( &mut self, mut err: DiagnosticBuilder<'a>, - expected: Option<&'static str>, + expected: Expected, ) -> PResult<'a, P> { self.cancel(&mut err); @@ -379,17 +563,6 @@ impl<'a> Parser<'a> { Err(err) } - // Helper function to decide whether to parse as ident binding - // or to try to do something more complex like range patterns. - fn parse_as_ident(&mut self) -> bool { - self.look_ahead(1, |t| match t.kind { - token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::DotDotEq | token::DotDot | - token::ModSep | token::Not => false, - _ => true, - }) - } - /// Is the current token suitable as the start of a range patterns end? fn is_pat_range_end_start(&self) -> bool { self.token.is_path_start() // e.g. `MY_CONST`; @@ -463,6 +636,30 @@ impl<'a> Parser<'a> { } } + /// Is this the start of a pattern beginning with a path? + fn is_start_of_pat_with_path(&mut self) -> bool { + self.check_path() + // Just for recovery (see `can_be_ident`). + || self.token.is_ident() && !self.token.is_bool_lit() && !self.token.is_keyword(kw::In) + } + + /// Would `parse_pat_ident` be appropriate here? + fn can_be_ident_pat(&mut self) -> bool { + self.check_ident() + && !self.token.is_bool_lit() // Avoid `true` or `false` as a binding as it is a literal. + && !self.token.is_path_segment_keyword() // Avoid e.g. `Self` as it is a path. + // Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`. + && !self.token.is_keyword(kw::In) + && self.look_ahead(1, |t| match t.kind { // Try to do something more complex? + token::OpenDelim(token::Paren) // A tuple struct pattern. + | token::OpenDelim(token::Brace) // A struct pattern. + | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. + | token::ModSep // A tuple / struct variant pattern. + | token::Not => false, // A macro expanding to a pattern. + _ => true, + }) + } + /// Parses `ident` or `ident @ pat`. /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. @@ -516,7 +713,7 @@ impl<'a> Parser<'a> { err.span_label(self.token.span, msg); return Err(err); } - let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or(None))?; + let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?; Ok(PatKind::TupleStruct(path, fields)) } @@ -660,7 +857,7 @@ impl<'a> Parser<'a> { // Parsing a pattern of the form "fieldname: pat" let fieldname = self.parse_field_name()?; self.bump(); - let pat = self.parse_pat_with_or(None)?; + let pat = self.parse_pat_with_or_inner()?; hi = pat.span; (pat, fieldname, false) } else { diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 3eb4d45045a9e..d4b13cc2e0121 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -423,7 +423,7 @@ impl<'a> Parser<'a> { // FIXME(const_generics): to distinguish between idents for types and consts, // we should introduce a GenericArg::Ident in the AST and distinguish when // lowering to the HIR. For now, idents for const args are not permitted. - if self.token.is_keyword(kw::True) || self.token.is_keyword(kw::False) { + if self.token.is_bool_lit() { self.parse_literal_maybe_minus()? } else { return Err( diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index c911caba4cd41..651ebf6342e71 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -1,6 +1,7 @@ use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMode}; use super::expr::LhsExpr; use super::path::PathStyle; +use super::pat::GateOr; use crate::ptr::P; use crate::{maybe_whole, ThinVec}; @@ -207,7 +208,7 @@ impl<'a> Parser<'a> { /// Parses a local variable declaration. fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { let lo = self.prev_span; - let pat = self.parse_top_level_pat()?; + let pat = self.parse_top_pat(GateOr::Yes)?; let (err, ty) = if self.eat(&token::Colon) { // Save the state of the parser before parsing type normally, in case there is a `:` diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 337702b8d30c5..465e31ac57e64 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -292,7 +292,7 @@ impl<'a> Parser<'a> { }; self.expect_keyword(kw::Fn)?; - let (inputs, c_variadic) = self.parse_fn_args(false, true)?; + let (inputs, c_variadic) = self.parse_fn_params(false, true)?; let ret_ty = self.parse_ret_ty(false)?; let decl = P(FnDecl { inputs, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 1865f925165bd..fe3b51aa246b8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -409,7 +409,7 @@ impl Token { crate fn expect_lit(&self) -> Lit { match self.kind { Literal(lit) => lit, - _=> panic!("`expect_lit` called on non-literal"), + _ => panic!("`expect_lit` called on non-literal"), } } @@ -417,10 +417,8 @@ impl Token { /// for example a '-42', or one of the boolean idents). crate fn can_begin_literal_or_bool(&self) -> bool { match self.kind { - Literal(..) => true, - BinOp(Minus) => true, - Ident(name, false) if name == kw::True => true, - Ident(name, false) if name == kw::False => true, + Literal(..) | BinOp(Minus) => true, + Ident(name, false) if name.is_bool_lit() => true, Interpolated(ref nt) => match **nt { NtLiteral(..) => true, _ => false, @@ -457,6 +455,7 @@ impl Token { pub fn is_ident(&self) -> bool { self.ident().is_some() } + /// Returns `true` if the token is a lifetime. crate fn is_lifetime(&self) -> bool { self.lifetime().is_some() @@ -508,45 +507,43 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: Symbol) -> bool { - self.ident().map(|(id, is_raw)| id.name == kw && !is_raw).unwrap_or(false) + self.is_non_raw_ident_where(|id| id.name == kw) } crate fn is_path_segment_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_path_segment_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword) } // Returns true for reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. crate fn is_special_ident(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_special(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_special) } /// Returns `true` if the token is a keyword used in the language. crate fn is_used_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_used_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_used_keyword) } /// Returns `true` if the token is a keyword reserved for possible future use. crate fn is_unused_keyword(&self) -> bool { - match self.ident() { - Some((id, false)) => id.is_unused_keyword(), - _ => false, - } + self.is_non_raw_ident_where(ast::Ident::is_unused_keyword) } /// Returns `true` if the token is either a special identifier or a keyword. pub fn is_reserved_ident(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_reserved) + } + + /// Returns `true` if the token is the identifier `true` or `false`. + crate fn is_bool_lit(&self) -> bool { + self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) + } + + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. + fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool { match self.ident() { - Some((id, false)) => id.is_reserved(), + Some((id, false)) => pred(id), _ => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4dc00af486013..bead941b20d5a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -152,6 +152,18 @@ pub fn to_string(f: F) -> String where printer.s.eof() } +// This makes comma-separated lists look slightly nicer, +// and also addresses a specific regression described in issue #63896. +fn tt_prepend_space(tt: &TokenTree) -> bool { + match tt { + TokenTree::Token(token) => match token.kind { + token::Comma => false, + _ => true, + } + _ => true, + } +} + fn binop_to_string(op: BinOpToken) -> &'static str { match op { token::Plus => "+", @@ -406,8 +418,8 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { to_string(|s| s.print_attribute(attr)) } -pub fn arg_to_string(arg: &ast::Arg) -> String { - to_string(|s| s.print_arg(arg, false)) +pub fn param_to_string(arg: &ast::Param) -> String { + to_string(|s| s.print_param(arg, false)) } fn foreign_item_to_string(arg: &ast::ForeignItem) -> String { @@ -696,7 +708,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::DerefM fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) { for (i, tt) in tts.into_trees().enumerate() { - if i != 0 { + if i != 0 && tt_prepend_space(&tt) { self.space(); } self.print_tt(tt, convert_dollar_crate); @@ -2089,7 +2101,7 @@ impl<'a> State<'a> { self.print_asyncness(asyncness); self.print_capture_clause(capture_clause); - self.print_fn_block_args(decl); + self.print_fn_block_params(decl); self.s.space(); self.print_expr(body); self.end(); // need to close a box @@ -2524,21 +2536,21 @@ impl<'a> State<'a> { self.print_ident(name); } self.print_generic_params(&generics.params); - self.print_fn_args_and_ret(decl); + self.print_fn_params_and_ret(decl); self.print_where_clause(&generics.where_clause) } - crate fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl) { + crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl) { self.popen(); - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false)); + self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, false)); self.pclose(); self.print_fn_output(decl) } - crate fn print_fn_block_args(&mut self, decl: &ast::FnDecl) { + crate fn print_fn_block_params(&mut self, decl: &ast::FnDecl) { self.s.word("|"); - self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true)); + self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, true)); self.s.word("|"); if let ast::FunctionRetTy::Default(..) = decl.output { @@ -2747,7 +2759,7 @@ impl<'a> State<'a> { self.print_type(&mt.ty) } - crate fn print_arg(&mut self, input: &ast::Arg, is_closure: bool) { + crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) { self.ibox(INDENT_UNIT); self.print_outer_attributes_inline(&input.attrs); diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index 4c0e1e3704dff..c472212bc2096 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -144,11 +144,14 @@ fn test_harness(file_text: &str, span_labels: Vec, expected_output: & println!("text: {:?}", source_map.span_to_snippet(span)); } - let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false); + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + ); let handler = Handler::with_emitter(true, None, Box::new(emitter)); handler.span_err(msp, "foo"); diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 09a1b93c7bb19..0d9f3769ce904 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -19,7 +19,7 @@ use crate::parse::Directory; use crate::parse::token::{self, DelimToken, Token, TokenKind}; use crate::print::pprust; -use syntax_pos::{BytePos, ExpnId, Span, DUMMY_SP}; +use syntax_pos::{BytePos, Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; @@ -547,11 +547,4 @@ impl DelimSpan { pub fn entire(self) -> Span { self.open.with_hi(self.close.hi()) } - - pub fn apply_mark(self, expn_id: ExpnId) -> Self { - DelimSpan { - open: self.open.apply_mark(expn_id), - close: self.close.apply_mark(expn_id), - } - } } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index f17eb3b39432e..a64fec7096132 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -93,8 +93,7 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &VariantData, _: Ident, - _: &Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; walk_struct_def(self, s) } @@ -107,9 +106,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) { + fn visit_variant(&mut self, v: &Variant) { self.count += 1; - walk_variant(self, v, g, item_id) + walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &Lifetime) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 91b92d84a811f..ce1568316f8d4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -66,7 +66,7 @@ pub trait Visitor<'ast>: Sized { fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) } - fn visit_arg(&mut self, arg: &'ast Arg) { walk_arg(self, arg) } + fn visit_param(&mut self, param: &'ast Param) { walk_param(self, param) } fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) } fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) } fn visit_anon_const(&mut self, c: &'ast AnonConst) { walk_anon_const(self, c) } @@ -92,8 +92,7 @@ pub trait Visitor<'ast>: Sized { fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data(&mut self, s: &'ast VariantData, _: Ident, - _: &'ast Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) } fn visit_struct_field(&mut self, s: &'ast StructField) { walk_struct_field(self, s) } @@ -101,8 +100,8 @@ pub trait Visitor<'ast>: Sized { generics: &'ast Generics, item_id: NodeId, _: Span) { walk_enum_def(self, enum_definition, generics, item_id) } - fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'ast Variant) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'ast Label) { walk_label(self, label) @@ -163,6 +162,12 @@ pub trait Visitor<'ast>: Sized { fn visit_fn_header(&mut self, _header: &'ast FnHeader) { // Nothing to do } + fn visit_field(&mut self, f: &'ast Field) { + walk_field(self, f) + } + fn visit_field_pattern(&mut self, fp: &'ast FieldPat) { + walk_field_pattern(self, fp) + } } #[macro_export] @@ -280,8 +285,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_variant_data(struct_definition, item.ident, - generics, item.id, item.span); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, ref bounds, ref methods) => { visitor.visit_generics(generics); @@ -300,24 +304,32 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId) { - walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id); + _: &'a Generics, + _: NodeId) { + walk_list!(visitor, visit_variant, &enum_definition.variants); } -pub fn walk_variant<'a, V>(visitor: &mut V, - variant: &'a Variant, - generics: &'a Generics, - item_id: NodeId) +pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) where V: Visitor<'a>, { visitor.visit_ident(variant.ident); - visitor.visit_variant_data(&variant.data, variant.ident, - generics, item_id, variant.span); + visitor.visit_variant_data(&variant.data); walk_list!(visitor, visit_anon_const, &variant.disr_expr); walk_list!(visitor, visit_attribute, &variant.attrs); } +pub fn walk_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a Field) { + visitor.visit_expr(&f.expr); + visitor.visit_ident(f.ident); + walk_list!(visitor, visit_attribute, f.attrs.iter()); +} + +pub fn walk_field_pattern<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a FieldPat) { + visitor.visit_ident(fp.ident); + visitor.visit_pat(&fp.pat); + walk_list!(visitor, visit_attribute, fp.attrs.iter()); +} + pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { match typ.node { TyKind::Slice(ref ty) | TyKind::Paren(ref ty) => { @@ -441,11 +453,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { } PatKind::Struct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_pat(&field.pat) - } + walk_list!(visitor, visit_field_pattern, fields); } PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) | @@ -547,8 +555,8 @@ pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FunctionR } pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) { - for arg in &function_declaration.inputs { - visitor.visit_arg(arg); + for param in &function_declaration.inputs { + visitor.visit_param(param); } visitor.visit_fn_ret_ty(&function_declaration.output); } @@ -686,11 +694,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { } ExprKind::Struct(ref path, ref fields, ref optional_base) => { visitor.visit_path(path, expression.id); - for field in fields { - walk_list!(visitor, visit_attribute, field.attrs.iter()); - visitor.visit_ident(field.ident); - visitor.visit_expr(&field.expr) - } + walk_list!(visitor, visit_field, fields); walk_list!(visitor, visit_expr, optional_base); } ExprKind::Tup(ref subexpressions) => { @@ -820,10 +824,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr_post(expression) } -pub fn walk_arg<'a, V: Visitor<'a>>(visitor: &mut V, arg: &'a Arg) { - walk_list!(visitor, visit_attribute, arg.attrs.iter()); - visitor.visit_pat(&arg.pat); - visitor.visit_ty(&arg.ty); +pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) { + walk_list!(visitor, visit_attribute, param.attrs.iter()); + visitor.visit_pat(¶m.pat); + visitor.visit_ty(¶m.ty); } pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 644a44f1989db..28f907441d872 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -63,7 +63,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(inline_asm)), - span: sp.with_ctxt(cx.backtrace()), + span: cx.with_legacy_ctxt(sp), attrs: ThinVec::new(), })) } diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index 6301283460ac7..84583d0e5eca7 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -23,7 +23,7 @@ pub fn expand_assert<'cx>( } }; - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); let panic_call = Mac { path: Path::from_ident(Ident::new(sym::panic, sp)), tts: custom_message.unwrap_or_else(|| { diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 0e52c1af9086f..21cee8ae1cb9c 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -16,7 +16,7 @@ pub fn expand_cfg( sp: Span, tts: &[tokenstream::TokenTree], ) -> Box { - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); match parse_cfg(cx, sp, tts) { Ok(cfg) => { diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 4cd17531a4500..ffa5154ca0c36 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -59,6 +59,6 @@ pub fn expand_syntax_ext( } else if has_errors { return DummyResult::any(sp); } - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 8184fc442676d..96677072d1b80 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -39,7 +39,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, } } - let ident = ast::Ident::new(Symbol::intern(&res_str), sp.apply_mark(cx.current_expansion.id)); + let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_legacy_ctxt(sp)); struct ConcatIdentsResult { ident: ast::Ident } diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d030ea4a56ebb..4dd0ecfebefd4 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -112,7 +112,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::clone, Symbol::intern(helper_name)]), vec![GenericArg::Type(ty)], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 54027c600b4cd..32ab47969ada4 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -53,7 +53,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]), vec![GenericArg::Type(ty)], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 441535410480b..781645a574e9a 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -60,7 +60,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> }; // We want to make sure we have the ctxt set so that we can use unstable methods - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str_and_span("debug_trait_builder", span); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1475bac068846..6fd763f5a9100 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -929,10 +929,10 @@ impl<'a> MethodDef<'a> { let args = { let self_args = explicit_self.map(|explicit_self| { let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(trait_.span); - ast::Arg::from_self(ThinVec::default(), explicit_self, ident) + ast::Param::from_self(ThinVec::default(), explicit_self, ident) }); let nonself_args = arg_types.into_iter() - .map(|(name, ty)| cx.arg(trait_.span, name, ty)); + .map(|(name, ty)| cx.param(trait_.span, name, ty)); self_args.into_iter().chain(nonself_args).collect() }; diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 7fcf036fc8176..cb1c7b21fee0d 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -85,7 +85,7 @@ impl<'a> Path<'a> { PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()), PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()), PathKind::Std => { - let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id); + let def_site = cx.with_def_site_ctxt(DUMMY_SP); idents.insert(0, Ident::new(kw::DollarCrate, def_site)); cx.path_all(span, false, idents, params, Vec::new()) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index da68eea0c50e7..60b6eba7a4b53 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -48,6 +48,9 @@ impl MultiItemModifier for BuiltinDerive { meta_item: &MetaItem, item: Annotatable) -> Vec { + // FIXME: Built-in derives often forget to give spans contexts, + // so we are doing it here in a centralized way. + let span = ecx.with_def_site_ctxt(span); let mut items = Vec::new(); (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a)); items @@ -60,7 +63,7 @@ fn call_intrinsic(cx: &ExtCtxt<'_>, intrinsic: &str, args: Vec>) -> P { - let span = span.with_ctxt(cx.backtrace()); + let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 9834130fa23f0..6343d218de829 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -20,7 +20,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, Some(v) => v, }; - let sp = sp.apply_mark(cx.current_expansion.id); + let sp = cx.with_legacy_ctxt(sp); let e = match env::var(&*var.as_str()) { Err(..) => { let lt = cx.lifetime(sp, Ident::with_dummy_span(kw::StaticLifetime)); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 83764205a198e..47394c02b4186 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -12,7 +12,7 @@ use syntax::parse::token; use syntax::ptr::P; use syntax::symbol::{Symbol, sym}; use syntax::tokenstream; -use syntax_pos::{MultiSpan, Span, DUMMY_SP}; +use syntax_pos::{MultiSpan, Span}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::borrow::Cow; @@ -666,8 +666,7 @@ impl<'a, 'b> Context<'a, 'b> { // passed to this function. for (i, e) in self.args.into_iter().enumerate() { let name = names_pos[i]; - let span = - DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.id)); + let span = self.ecx.with_def_site_ctxt(e.span); pats.push(self.ecx.pat_ident(span, name)); for ref arg_ty in self.arg_unique_types[i].iter() { locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); @@ -745,7 +744,7 @@ impl<'a, 'b> Context<'a, 'b> { ty: &ArgumentType, arg: ast::Ident, ) -> P { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { Placeholder(ref tyname) => { @@ -798,7 +797,7 @@ fn expand_format_args_impl<'cx>( tts: &[tokenstream::TokenTree], nl: bool, ) -> Box { - sp = sp.apply_mark(ecx.current_expansion.id); + sp = ecx.with_def_site_ctxt(sp); match parse_args(ecx, sp, tts) { Ok((efmt, args, names)) => { MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl)) @@ -842,7 +841,7 @@ pub fn expand_preparsed_format_args( let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let mut macsp = ecx.call_site(); - macsp = macsp.with_ctxt(ecx.backtrace()); + macsp = ecx.with_def_site_ctxt(macsp); let msg = "format argument must be a string literal"; let fmt_sp = efmt.span; diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index d2121abe3b466..f4af1699cd683 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,9 +1,8 @@ use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; -use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident}; +use syntax::ast::{self, Param, Attribute, Expr, FnHeader, Generics, Ident}; use syntax::attr::check_builtin_macro_attribute; use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; use syntax_pos::Span; @@ -29,7 +28,7 @@ pub fn expand( }; // Generate a bunch of new items using the AllocFnFactory - let span = item.span.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id)); + let span = ecx.with_legacy_ctxt(item.span); let f = AllocFnFactory { span, kind: AllocatorKind::Global, @@ -115,7 +114,7 @@ impl AllocFnFactory<'_, '_> { fn arg_ty( &self, ty: &AllocatorTy, - args: &mut Vec, + args: &mut Vec, ident: &mut dyn FnMut() -> Ident, ) -> P { match *ty { @@ -124,8 +123,8 @@ impl AllocFnFactory<'_, '_> { let ty_usize = self.cx.ty_path(usize); let size = ident(); let align = ident(); - args.push(self.cx.arg(self.span, size, ty_usize.clone())); - args.push(self.cx.arg(self.span, align, ty_usize)); + args.push(self.cx.param(self.span, size, ty_usize.clone())); + args.push(self.cx.param(self.span, align, ty_usize)); let layout_new = self.cx.std_path(&[ Symbol::intern("alloc"), @@ -141,14 +140,14 @@ impl AllocFnFactory<'_, '_> { AllocatorTy::Ptr => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + args.push(self.cx.param(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.usize())); + args.push(self.cx.param(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 73ebeaec45497..a8b61593db749 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -30,7 +30,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, id: ast::DUMMY_NODE_ID, node: ast::ItemKind::GlobalAsm(P(global_asm)), vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), - span: sp.with_ctxt(cx.backtrace()), + span: cx.with_legacy_ctxt(sp), tokens: None, })]) } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 4add2261c6cda..1a6176916623b 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -7,13 +7,18 @@ #![feature(decl_macro)] #![feature(mem_take)] #![feature(nll)] +#![feature(proc_macro_internals)] +#![feature(proc_macro_quote)] #![feature(rustc_diagnostic_macros)] +extern crate proc_macro; + use crate::deriving::*; use syntax::ast::Ident; use syntax::edition::Edition; use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn}; +use syntax::ext::proc_macro::BangProcMacro; use syntax::symbol::sym; mod error_codes; @@ -100,4 +105,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e RustcDecodable: decodable::expand_deriving_rustc_decodable, RustcEncodable: encodable::expand_deriving_rustc_encodable, } + + let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote); + register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }))); } diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 08582e714ccb2..5fd87d3a0e5c6 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -4,7 +4,6 @@ use syntax::ast; use syntax::attr::{self, check_builtin_macro_attribute}; use syntax::ext::base::*; -use syntax::ext::hygiene::SyntaxContext; use syntax::print::pprust; use syntax::source_map::respan; use syntax::symbol::{Symbol, sym}; @@ -29,7 +28,7 @@ pub fn expand_test_case( if !ecx.ecfg.should_test { return vec![]; } - let sp = attr_sp.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id)); + let sp = ecx.with_legacy_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); @@ -93,8 +92,7 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let ctxt = SyntaxContext::root().apply_mark(cx.current_expansion.id); - let (sp, attr_sp) = (item.span.with_ctxt(ctxt), attr_sp.with_ctxt(ctxt)); + let (sp, attr_sp) = (cx.with_legacy_ctxt(item.span), cx.with_legacy_ctxt(attr_sp)); // Gensym "test" so we can extern crate without conflicting with any local names let test_id = cx.ident_of("test").gensym(); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ebfb0764fa2b2..733f6f0449065 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -119,18 +119,6 @@ impl ExpnId { pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt))) } - - // Used for enabling some compatibility fallback in resolve. - #[inline] - pub fn looks_like_proc_macro_derive(self) -> bool { - HygieneData::with(|data| { - let expn_data = data.expn_data(self); - if let ExpnKind::Macro(MacroKind::Derive, _) = expn_data.kind { - return expn_data.default_transparency == Transparency::Opaque; - } - false - }) - } } #[derive(Debug)] @@ -195,24 +183,25 @@ impl HygieneData { self.syntax_context_data[ctxt.0 as usize].outer_expn } - fn outer_transparency(&self, ctxt: SyntaxContext) -> Transparency { - self.syntax_context_data[ctxt.0 as usize].outer_transparency + fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { + let data = &self.syntax_context_data[ctxt.0 as usize]; + (data.outer_expn, data.outer_transparency) } fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { self.syntax_context_data[ctxt.0 as usize].parent } - fn remove_mark(&self, ctxt: &mut SyntaxContext) -> ExpnId { - let outer_expn = self.outer_expn(*ctxt); + fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { + let outer_mark = self.outer_mark(*ctxt); *ctxt = self.parent_ctxt(*ctxt); - outer_expn + outer_mark } fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> { let mut marks = Vec::new(); while ctxt != SyntaxContext::root() { - marks.push((self.outer_expn(ctxt), self.outer_transparency(ctxt))); + marks.push(self.outer_mark(ctxt)); ctxt = self.parent_ctxt(ctxt); } marks.reverse(); @@ -229,20 +218,14 @@ impl HygieneData { fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option { let mut scope = None; while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) { - scope = Some(self.remove_mark(ctxt)); + scope = Some(self.remove_mark(ctxt).0); } scope } - fn apply_mark(&mut self, ctxt: SyntaxContext, expn_id: ExpnId) -> SyntaxContext { - assert_ne!(expn_id, ExpnId::root()); - self.apply_mark_with_transparency( - ctxt, expn_id, self.expn_data(expn_id).default_transparency - ) - } - - fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, expn_id: ExpnId, - transparency: Transparency) -> SyntaxContext { + fn apply_mark( + &mut self, ctxt: SyntaxContext, expn_id: ExpnId, transparency: Transparency + ) -> SyntaxContext { assert_ne!(expn_id, ExpnId::root()); if transparency == Transparency::Opaque { return self.apply_mark_internal(ctxt, expn_id, transparency); @@ -376,15 +359,9 @@ impl SyntaxContext { SyntaxContext(raw) } - /// Extend a syntax context with a given expansion and default transparency for that expansion. - pub fn apply_mark(self, expn_id: ExpnId) -> SyntaxContext { - HygieneData::with(|data| data.apply_mark(self, expn_id)) - } - /// Extend a syntax context with a given expansion and transparency. - pub fn apply_mark_with_transparency(self, expn_id: ExpnId, transparency: Transparency) - -> SyntaxContext { - HygieneData::with(|data| data.apply_mark_with_transparency(self, expn_id, transparency)) + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext { + HygieneData::with(|data| data.apply_mark(self, expn_id, transparency)) } /// Pulls a single mark off of the syntax context. This effectively moves the @@ -404,7 +381,7 @@ impl SyntaxContext { /// invocation of f that created g1. /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> ExpnId { - HygieneData::with(|data| data.remove_mark(self)) + HygieneData::with(|data| data.remove_mark(self).0) } pub fn marks(self) -> Vec<(ExpnId, Transparency)> { @@ -477,8 +454,8 @@ impl SyntaxContext { let mut scope = None; let mut glob_ctxt = data.modern(glob_span.ctxt()); while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) { - scope = Some(data.remove_mark(&mut glob_ctxt)); - if data.remove_mark(self) != scope.unwrap() { + scope = Some(data.remove_mark(&mut glob_ctxt).0); + if data.remove_mark(self).0 != scope.unwrap() { return None; } } @@ -509,9 +486,9 @@ impl SyntaxContext { marks.push(data.remove_mark(&mut glob_ctxt)); } - let scope = marks.last().cloned(); - while let Some(mark) = marks.pop() { - *self = data.apply_mark(*self, mark); + let scope = marks.last().map(|mark| mark.0); + while let Some((expn_id, transparency)) = marks.pop() { + *self = data.apply_mark(*self, expn_id, transparency); } Some(scope) }) @@ -547,13 +524,11 @@ impl SyntaxContext { HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone()) } - /// `ctxt.outer_expn_with_data()` is equivalent to but faster than - /// `{ let outer = ctxt.outer_expn(); (outer, outer.expn_data()) }`. #[inline] - pub fn outer_expn_with_data(self) -> (ExpnId, ExpnData) { + pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) { HygieneData::with(|data| { - let outer = data.outer_expn(self); - (outer, data.expn_data(outer).clone()) + let (expn_id, transparency) = data.outer_mark(self); + (expn_id, transparency, data.expn_data(expn_id).clone()) }) } @@ -575,9 +550,15 @@ impl Span { /// The returned span belongs to the created expansion and has the new properties, /// but its location is inherited from the current span. pub fn fresh_expansion(self, expn_data: ExpnData) -> Span { + self.fresh_expansion_with_transparency(expn_data, Transparency::SemiTransparent) + } + + pub fn fresh_expansion_with_transparency( + self, expn_data: ExpnData, transparency: Transparency + ) -> Span { HygieneData::with(|data| { let expn_id = data.fresh_expn(Some(expn_data)); - self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id)) + self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency)) }) } } @@ -609,8 +590,6 @@ pub struct ExpnData { /// The span of the macro definition (possibly dummy). /// This span serves only informational purpose and is not used for resolution. pub def_site: Span, - /// Transparency used by `apply_mark` for the expansion with this expansion data by default. - pub default_transparency: Transparency, /// List of #[unstable]/feature-gated features that the macro is allowed to use /// internally without forcing the whole crate to opt-in /// to them. @@ -633,7 +612,6 @@ impl ExpnData { parent: ExpnId::root(), call_site, def_site: DUMMY_SP, - default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, local_inner_macros: false, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index a17cd7625fb19..3d8bfc77a8950 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -22,6 +22,7 @@ pub mod edition; use edition::Edition; pub mod hygiene; pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind}; +use hygiene::Transparency; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -512,10 +513,17 @@ impl Span { span.ctxt) } + /// Produces a span with the same location as `self` and context produced by a macro with the + /// given ID and transparency, assuming that macro was defined directly and not produced by + /// some other macro (which is the case for built-in and procedural macros). + pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.with_ctxt(SyntaxContext::root().apply_mark(expn_id, transparency)) + } + #[inline] - pub fn apply_mark(self, mark: ExpnId) -> Span { + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { let span = self.data(); - span.with_ctxt(span.ctxt.apply_mark(mark)) + span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency)) } #[inline] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 0b8f16bbc3b99..f44716e013ec8 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -225,9 +225,10 @@ symbols! { custom_inner_attributes, custom_test_frameworks, c_variadic, - Debug, + debug_trait, declare_lint_pass, decl_macro, + Debug, Decodable, Default, default_lib_allocator, @@ -238,6 +239,7 @@ symbols! { deref, deref_mut, derive, + diagnostic, direct, doc, doc_alias, @@ -569,6 +571,7 @@ symbols! { rustc_conversion_suggestion, rustc_def_path, rustc_deprecated, + rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, rustc_dummy, @@ -849,9 +852,29 @@ impl fmt::Display for Ident { } } -impl UseSpecializedEncodable for Ident {} +impl UseSpecializedEncodable for Ident { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_struct("Ident", 2, |s| { + s.emit_struct_field("name", 0, |s| { + self.name.encode(s) + })?; + s.emit_struct_field("span", 1, |s| { + self.span.encode(s) + }) + }) + } +} -impl UseSpecializedDecodable for Ident {} +impl UseSpecializedDecodable for Ident { + fn default_decode(d: &mut D) -> Result { + d.read_struct("Ident", 2, |d| { + Ok(Ident { + name: d.read_struct_field("name", 0, Decodable::decode)?, + span: d.read_struct_field("span", 1, Decodable::decode)?, + }) + }) + } +} /// A symbol is an interned or gensymed string. A gensym is a symbol that is /// never equal to any other symbol. @@ -1063,6 +1086,11 @@ impl Symbol { self == kw::DollarCrate } + /// Returns `true` if the symbol is `true` or `false`. + pub fn is_bool_lit(self) -> bool { + self == kw::True || self == kw::False + } + /// This symbol can be a raw identifier. pub fn can_be_raw(self) -> bool { self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() diff --git a/src/libterm/Cargo.toml b/src/libterm/Cargo.toml index 4eba9a9d79cc4..2931e0bda9518 100644 --- a/src/libterm/Cargo.toml +++ b/src/libterm/Cargo.toml @@ -5,6 +5,8 @@ version = "0.0.0" edition = "2018" [lib] -name = "term" path = "lib.rs" -crate-type = ["dylib", "rlib"] + +[dependencies] +core = { path = "../libcore" } +std = { path = "../libstd" } diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml index a72e4c7050289..170fbb984cf9b 100644 --- a/src/libtest/Cargo.toml +++ b/src/libtest/Cargo.toml @@ -10,8 +10,22 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] -getopts = "0.2.19" +getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } term = { path = "../libterm" } +std = { path = "../libstd" } +core = { path = "../libcore" } +libc = { version = "0.2", default-features = false } +panic_unwind = { path = "../libpanic_unwind" } +panic_abort = { path = "../libpanic_abort" } # not actually used but needed to always have proc_macro in the sysroot proc_macro = { path = "../libproc_macro" } + +# Forward features to the `std` crate as necessary +[features] +backtrace = ["std/backtrace"] +compiler-builtins-c = ["std/compiler-builtins-c"] +llvm-libunwind = ["std/llvm-libunwind"] +panic-unwind = ["std/panic_unwind"] +panic_immediate_abort = ["std/panic_immediate_abort"] +profiler = ["std/profiler"] diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs index a06497f98626a..e0bea4ce54530 100644 --- a/src/libtest/formatters/json.rs +++ b/src/libtest/formatters/json.rs @@ -9,44 +9,57 @@ impl JsonFormatter { Self { out } } - fn write_message(&mut self, s: &str) -> io::Result<()> { + fn writeln_message(&mut self, s: &str) -> io::Result<()> { assert!(!s.contains('\n')); self.out.write_all(s.as_ref())?; self.out.write_all(b"\n") } + fn write_message(&mut self, s: &str) -> io::Result<()> { + assert!(!s.contains('\n')); + + self.out.write_all(s.as_ref()) + } + fn write_event( &mut self, ty: &str, name: &str, evt: &str, - extra: Option, + stdout: Option>, + extra: Option<&str>, ) -> io::Result<()> { - if let Some(extras) = extra { + self.write_message(&*format!( + r#"{{ "type": "{}", "name": "{}", "event": "{}""#, + ty, name, evt + ))?; + if let Some(stdout) = stdout { self.write_message(&*format!( - r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, - ty, name, evt, extras - )) - } else { + r#", "stdout": "{}""#, + EscapedString(stdout) + ))?; + } + if let Some(extra) = extra { self.write_message(&*format!( - r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, - ty, name, evt - )) + r#", {}"#, + extra + ))?; } + self.writeln_message(" }") } } impl OutputFormatter for JsonFormatter { fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#, test_count )) } fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "test", "event": "started", "name": "{}" }}"#, desc.name )) @@ -57,34 +70,30 @@ impl OutputFormatter for JsonFormatter { desc: &TestDesc, result: &TestResult, stdout: &[u8], + state: &ConsoleTestState, ) -> io::Result<()> { + let stdout = if (state.options.display_output || *result != TrOk) && stdout.len() > 0 { + Some(String::from_utf8_lossy(stdout)) + } else { + None + }; match *result { - TrOk => self.write_event("test", desc.name.as_slice(), "ok", None), - - TrFailed => { - let extra_data = if stdout.len() > 0 { - Some(format!( - r#""stdout": "{}""#, - EscapedString(String::from_utf8_lossy(stdout)) - )) - } else { - None - }; + TrOk => self.write_event("test", desc.name.as_slice(), "ok", stdout, None), - self.write_event("test", desc.name.as_slice(), "failed", extra_data) - } + TrFailed => self.write_event("test", desc.name.as_slice(), "failed", stdout, None), TrFailedMsg(ref m) => self.write_event( "test", desc.name.as_slice(), "failed", - Some(format!(r#""message": "{}""#, EscapedString(m))), + stdout, + Some(&*format!(r#""message": "{}""#, EscapedString(m))), ), - TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None), + TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", stdout, None), TrAllowedFail => { - self.write_event("test", desc.name.as_slice(), "allowed_failure", None) + self.write_event("test", desc.name.as_slice(), "allowed_failure", stdout, None) } TrBench(ref bs) => { @@ -105,20 +114,20 @@ impl OutputFormatter for JsonFormatter { desc.name, median, deviation, mbps ); - self.write_message(&*line) + self.writeln_message(&*line) } } } fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { - self.write_message(&*format!( + self.writeln_message(&*format!( r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#, desc.name )) } fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result { - self.write_message(&*format!( + self.writeln_message(&*format!( "{{ \"type\": \"suite\", \ \"event\": \"{}\", \ \"passed\": {}, \ diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs index be5f6a65039b7..cc30b06e5ec38 100644 --- a/src/libtest/formatters/mod.rs +++ b/src/libtest/formatters/mod.rs @@ -17,6 +17,7 @@ pub(crate) trait OutputFormatter { desc: &TestDesc, result: &TestResult, stdout: &[u8], + state: &ConsoleTestState, ) -> io::Result<()>; fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result; } diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs index 4af00428ca87e..88331406a64d0 100644 --- a/src/libtest/formatters/pretty.rs +++ b/src/libtest/formatters/pretty.rs @@ -162,7 +162,13 @@ impl OutputFormatter for PrettyFormatter { Ok(()) } - fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + _: &[u8], + _: &ConsoleTestState, + ) -> io::Result<()> { if self.is_multithreaded { self.write_test_name(desc)?; } diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs index 1400fba5d6092..d10b0c5807d57 100644 --- a/src/libtest/formatters/terse.rs +++ b/src/libtest/formatters/terse.rs @@ -170,7 +170,13 @@ impl OutputFormatter for TerseFormatter { Ok(()) } - fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + _: &[u8], + _: &ConsoleTestState, + ) -> io::Result<()> { match *result { TrOk => self.write_ok(), TrFailed | TrFailedMsg(_) => self.write_failed(), diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index ef66c4df99da7..09d5fcc89520e 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -274,7 +274,7 @@ impl Options { // The default console test runner. It accepts the command line // arguments and a vector of test_descs. -pub fn test_main(args: &[String], tests: Vec, options: Options) { +pub fn test_main(args: &[String], tests: Vec, options: Option) { let mut opts = match parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { @@ -283,8 +283,9 @@ pub fn test_main(args: &[String], tests: Vec, options: Options) { } None => return, }; - - opts.options = options; + if let Some(options) = options { + opts.options = options; + } if opts.list { if let Err(e) = list_tests_console(&opts, tests) { eprintln!("error: io error when listing tests: {:?}", e); @@ -325,7 +326,7 @@ pub fn test_main_static(tests: &[&TestDescAndFn]) { _ => panic!("non-static tests passed to test::test_main_static"), }) .collect(); - test_main(&args, owned_tests, Options::new()) + test_main(&args, owned_tests, None) } /// Invoked when unit tests terminate. Should panic if the unit @@ -448,6 +449,11 @@ fn optgroups() -> getopts::Options { json = Output a json document", "pretty|terse|json", ) + .optflag( + "", + "show-output", + "Show captured stdout of successful tests" + ) .optopt( "Z", "", @@ -647,7 +653,7 @@ pub fn parse_opts(args: &[String]) -> Option { format, test_threads, skip: matches.opt_strs("skip"), - options: Options::new(), + options: Options::new().display_output(matches.opt_present("show-output")), }; Some(Ok(test_opts)) @@ -880,7 +886,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec) -> io::Resu TeTimeout(ref test) => out.write_timeout(test), TeResult(test, result, stdout) => { st.write_log_result(&test, &result)?; - out.write_result(&test, &result, &*stdout)?; + out.write_result(&test, &result, &*stdout, &st)?; match result { TrOk => { st.passed += 1; @@ -965,12 +971,11 @@ fn use_color(opts: &TestOpts) -> bool { #[cfg(any( target_os = "cloudabi", - target_os = "redox", all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx") ))] fn stdout_isatty() -> bool { - // FIXME: Implement isatty on Redox and SGX + // FIXME: Implement isatty on SGX false } #[cfg(unix)] @@ -1193,15 +1198,15 @@ fn get_concurrency() -> usize { } } - #[cfg(target_os = "redox")] + #[cfg(target_os = "vxworks")] fn num_cpus() -> usize { - // FIXME: Implement num_cpus on Redox + // FIXME: Implement num_cpus on vxWorks 1 } - #[cfg(target_os = "vxworks")] + #[cfg(target_os = "redox")] fn num_cpus() -> usize { - // FIXME: Implement num_cpus on vxWorks + // FIXME: Implement num_cpus on Redox 1 } @@ -1221,7 +1226,7 @@ fn get_concurrency() -> usize { target_os = "ios", target_os = "linux", target_os = "macos", - target_os = "solaris" + target_os = "solaris", ))] fn num_cpus() -> usize { unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } diff --git a/src/libtest/tests.rs b/src/libtest/tests.rs index f574743e4b669..afc4217ec1ba2 100644 --- a/src/libtest/tests.rs +++ b/src/libtest/tests.rs @@ -180,6 +180,17 @@ fn parse_ignored_flag() { assert_eq!(opts.run_ignored, RunIgnored::Only); } +#[test] +fn parse_show_output_flag() { + let args = vec![ + "progname".to_string(), + "filter".to_string(), + "--show-output".to_string(), + ]; + let opts = parse_opts(&args).unwrap().unwrap(); + assert!(opts.options.display_output); +} + #[test] fn parse_include_ignored_flag() { let args = vec![ diff --git a/src/test/codegen/README.md b/src/test/codegen/README.md new file mode 100644 index 0000000000000..00de55eeab1f4 --- /dev/null +++ b/src/test/codegen/README.md @@ -0,0 +1,2 @@ +The files here use the LLVM FileCheck framework, documented at +. diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs index 13be5ced27fa9..bb90a9653f573 100644 --- a/src/test/codegen/c-variadic.rs +++ b/src/test/codegen/c-variadic.rs @@ -2,6 +2,7 @@ #![crate_type = "lib"] #![feature(c_variadic)] +#![feature(unwind_attributes)] #![no_std] use core::ffi::VaList; @@ -10,6 +11,7 @@ extern "C" { fn foreign_c_variadic_1(_: VaList, ...); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_0() { // Ensure that we correctly call foreign C-variadic functions. // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0) @@ -24,20 +26,24 @@ pub unsafe extern "C" fn use_foreign_c_variadic_0() { // Ensure that we do not remove the `va_list` passed to the foreign function when // removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap) foreign_c_variadic_1(ap); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 42) foreign_c_variadic_1(ap, 42i32); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42) foreign_c_variadic_1(ap, 2i32, 42i32); } +#[unwind(aborts)] // FIXME(#58794) pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42, i32 0) foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); diff --git a/src/test/codegen/integer-cmp.rs b/src/test/codegen/integer-cmp.rs new file mode 100644 index 0000000000000..8ada3cf09d073 --- /dev/null +++ b/src/test/codegen/integer-cmp.rs @@ -0,0 +1,28 @@ +// This is test for more optimal Ord implementation for integers. +// See for more info. + +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +use std::cmp::Ordering; + +// CHECK-LABEL: @cmp_signed +#[no_mangle] +pub fn cmp_signed(a: i64, b: i64) -> Ordering { +// CHECK: icmp slt +// CHECK: icmp ne +// CHECK: zext i1 +// CHECK: select i1 + a.cmp(&b) +} + +// CHECK-LABEL: @cmp_unsigned +#[no_mangle] +pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { +// CHECK: icmp ult +// CHECK: icmp ne +// CHECK: zext i1 +// CHECK: select i1 + a.cmp(&b) +} diff --git a/src/test/debuginfo/generator-objects.rs b/src/test/debuginfo/generator-objects.rs index c6f98e5782b1f..bfa7a05cad057 100644 --- a/src/test/debuginfo/generator-objects.rs +++ b/src/test/debuginfo/generator-objects.rs @@ -10,31 +10,31 @@ // gdb-command:run // gdb-command:print b -// gdb-check:$1 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 0, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$1 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 0, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$2 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 3, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$2 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 3, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {c: 6, d: 7}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$3 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 4, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {c: 7, d: 8}}} +// gdb-check:$3 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 4, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {c: 7, d: 8}}} // gdb-command:continue // gdb-command:print b -// gdb-check:$4 = generator_objects::main::generator {__0: 0x[...], <>: {__state: 1, 0: generator_objects::main::generator::Unresumed, 1: generator_objects::main::generator::Returned, 2: generator_objects::main::generator::Panicked, 3: generator_objects::main::generator::Suspend0 {[...]}, 4: generator_objects::main::generator::Suspend1 {[...]}}} +// gdb-check:$4 = generator_objects::main::generator-0 {__0: 0x[...], <>: {__state: 1, 0: generator_objects::main::generator-0::Unresumed, 1: generator_objects::main::generator-0::Returned, 2: generator_objects::main::generator-0::Panicked, 3: generator_objects::main::generator-0::Suspend0 {[...]}, 4: generator_objects::main::generator-0::Suspend1 {[...]}}} // === LLDB TESTS ================================================================================== // lldb-command:run // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $0 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $0 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $1 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $1 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $2 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $2 = generator-0(&0x[...]) // lldb-command:continue // lldb-command:print b -// lldbg-check:(generator_objects::main::generator) $3 = generator(&0x[...]) +// lldbg-check:(generator_objects::main::generator-0) $3 = generator-0(&0x[...]) #![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/issue-57822.rs b/src/test/debuginfo/issue-57822.rs new file mode 100644 index 0000000000000..f18e41db0e6ba --- /dev/null +++ b/src/test/debuginfo/issue-57822.rs @@ -0,0 +1,55 @@ +// This test makes sure that the LLDB pretty printer does not throw an exception +// for nested closures and generators. + +// Require LLVM with DW_TAG_variant_part and a gdb that can read it. +// min-system-llvm-version: 8.0 +// min-gdb-version: 8.2 +// ignore-tidy-linelength + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run + +// gdb-command:print g +// gdb-check:$1 = issue_57822::main::closure-1 (issue_57822::main::closure-0 (1)) + +// gdb-command:print b +// gdb-check:$2 = issue_57822::main::generator-3 {__0: issue_57822::main::generator-2 {__0: 2, <>: {[...]}}, <>: {[...]}} + +// === LLDB TESTS ================================================================================== + +// lldb-command:run + +// lldb-command:print g +// lldbg-check:(issue_57822::main::closure-1) $0 = closure-1(closure-0(1)) + +// lldb-command:print b +// lldbg-check:(issue_57822::main::generator-3) $1 = generator-3(generator-2(2)) + +#![feature(omit_gdb_pretty_printer_section, generators, generator_trait)] +#![omit_gdb_pretty_printer_section] + +use std::ops::Generator; +use std::pin::Pin; + +fn main() { + let mut x = 1; + let f = move || x; + let g = move || f(); + + let mut y = 2; + let mut a = move || { + y += 1; + yield; + }; + let mut b = move || { + Pin::new(&mut a).resume(); + yield; + }; + + zzz(); // #break +} + +fn zzz() { () } diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index ca45d36a6b0e4..70820dfaea4a0 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -94,7 +94,7 @@ pub fn change_iterable() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, promoted_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_iterable() { let mut _x = 0; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index 84680a52ff3ce..4515e36166eb8 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -94,7 +94,7 @@ pub unsafe fn make_unsafe() {} pub fn make_extern() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, mir_built, typeck_tables_of, fn_sig")] +#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub extern "C" fn make_extern() {} diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 882383e841957..24d436f5f9727 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -42,7 +42,10 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] + #[rustc_clean( + cfg="cfail2", + except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + )] #[rustc_clean(cfg="cfail3")] pub fn method_body() { println!("Hello, world!"); @@ -63,7 +66,10 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] + #[rustc_clean( + cfg="cfail2", + except="HirBody,optimized_mir,promoted_mir,mir_built,typeck_tables_of" + )] #[rustc_clean(cfg="cfail3")] #[inline] pub fn method_body_inlined() { @@ -97,7 +103,7 @@ impl Foo { #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of")] + #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")] #[rustc_clean(cfg="cfail3")] pub fn method_selfness(&self) { } } @@ -263,7 +269,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,mir_built,fn_sig,typeck_tables_of")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern fn make_method_extern(&self) { } } diff --git a/src/test/pretty/attr-literals.rs b/src/test/pretty/attr-literals.rs index bcd6ffaaf815b..9db7e27b16103 100644 --- a/src/test/pretty/attr-literals.rs +++ b/src/test/pretty/attr-literals.rs @@ -5,10 +5,10 @@ #![feature(rustc_attrs)] fn main() { - #![rustc_dummy("hi" , 1 , 2 , 1.012 , pi = 3.14 , bye , name ("John"))] + #![rustc_dummy("hi", 1, 2, 1.012, pi = 3.14, bye, name ("John"))] #[rustc_dummy = 8] fn f() { } - #[rustc_dummy(1 , 2 , 3)] + #[rustc_dummy(1, 2, 3)] fn g() { } } diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp index f15d7cdc44ccd..9317b36ba497b 100644 --- a/src/test/pretty/block-comment-wchar.pp +++ b/src/test/pretty/block-comment-wchar.pp @@ -99,8 +99,5 @@ '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}', '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}', '\u{205F}', '\u{3000}']; - for c in &chars { - let ws = c.is_whitespace(); - println!("{} {}" , c , ws); - } + for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); } } diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs index 768f27ad23a8e..7bbb7dc911f93 100644 --- a/src/test/pretty/delimited-token-groups.rs +++ b/src/test/pretty/delimited-token-groups.rs @@ -5,7 +5,7 @@ macro_rules! mac { ($ ($ tt : tt) *) => () } mac! { - struct S { field1 : u8 , field2 : u16 , } impl Clone for S + struct S { field1 : u8, field2 : u16, } impl Clone for S { fn clone () -> S { diff --git a/src/test/pretty/do1.rs b/src/test/pretty/do1.rs index 7be835cb22f2d..233ccdb0098b3 100644 --- a/src/test/pretty/do1.rs +++ b/src/test/pretty/do1.rs @@ -2,4 +2,4 @@ fn f(f: F) where F: Fn(isize) { f(10) } -fn main() { f(|i| { assert_eq!(i , 10) }) } +fn main() { f(|i| { assert_eq!(i, 10) }) } diff --git a/src/test/pretty/match-block-expr.rs b/src/test/pretty/match-block-expr.rs index 0db6574b0737f..10903e928cda8 100644 --- a/src/test/pretty/match-block-expr.rs +++ b/src/test/pretty/match-block-expr.rs @@ -2,5 +2,5 @@ fn main() { let x = match { 5 } { 1 => 5, 2 => 6, _ => 7, }; - assert_eq!(x , 7); + assert_eq!(x, 7); } diff --git a/src/test/run-make-fulldeps/libtest-json/Makefile b/src/test/run-make-fulldeps/libtest-json/Makefile index a0bc8cf6688bc..8339e230bbe92 100644 --- a/src/test/run-make-fulldeps/libtest-json/Makefile +++ b/src/test/run-make-fulldeps/libtest-json/Makefile @@ -2,13 +2,17 @@ # Test expected libtest's JSON output -OUTPUT_FILE := $(TMPDIR)/libtest-json-output.json +OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-json-output-default.json +OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-json-output-stdout-success.json all: $(RUSTC) --test f.rs - RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE_DEFAULT) || true + RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true - cat $(OUTPUT_FILE) | "$(PYTHON)" validate_json.py + cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py + cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py # Compare to output file - diff output.json $(OUTPUT_FILE) + diff output-default.json $(OUTPUT_FILE_DEFAULT) + diff output-stdout-success.json $(OUTPUT_FILE_STDOUT_SUCCESS) diff --git a/src/test/run-make-fulldeps/libtest-json/f.rs b/src/test/run-make-fulldeps/libtest-json/f.rs index f5e44c2c24407..95ff36bd764ec 100644 --- a/src/test/run-make-fulldeps/libtest-json/f.rs +++ b/src/test/run-make-fulldeps/libtest-json/f.rs @@ -1,11 +1,12 @@ #[test] fn a() { + println!("print from successful test"); // Should pass } #[test] fn b() { - assert!(false) + assert!(false); } #[test] diff --git a/src/test/run-make-fulldeps/libtest-json/output.json b/src/test/run-make-fulldeps/libtest-json/output-default.json similarity index 91% rename from src/test/run-make-fulldeps/libtest-json/output.json rename to src/test/run-make-fulldeps/libtest-json/output-default.json index 0caf268aa007f..8046d72221703 100644 --- a/src/test/run-make-fulldeps/libtest-json/output.json +++ b/src/test/run-make-fulldeps/libtest-json/output-default.json @@ -2,7 +2,7 @@ { "type": "test", "event": "started", "name": "a" } { "type": "test", "name": "a", "event": "ok" } { "type": "test", "event": "started", "name": "b" } -{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:8:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } +{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } { "type": "test", "event": "started", "name": "c" } { "type": "test", "name": "c", "event": "ok" } { "type": "test", "event": "started", "name": "d" } diff --git a/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json new file mode 100644 index 0000000000000..303316278d8ab --- /dev/null +++ b/src/test/run-make-fulldeps/libtest-json/output-stdout-success.json @@ -0,0 +1,10 @@ +{ "type": "suite", "event": "started", "test_count": 4 } +{ "type": "test", "event": "started", "name": "a" } +{ "type": "test", "name": "a", "event": "ok", "stdout": "print from successful test\n" } +{ "type": "test", "event": "started", "name": "b" } +{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.\n" } +{ "type": "test", "event": "started", "name": "c" } +{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" } +{ "type": "test", "event": "started", "name": "d" } +{ "type": "test", "name": "d", "event": "ignored" } +{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0 } diff --git a/src/test/run-make-fulldeps/lto-empty/Makefile b/src/test/run-make-fulldeps/lto-empty/Makefile new file mode 100644 index 0000000000000..345d10bc4b9ea --- /dev/null +++ b/src/test/run-make-fulldeps/lto-empty/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +all: cdylib-fat cdylib-thin + +cdylib-fat: + $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat + $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat + +cdylib-thin: + $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin + $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin + diff --git a/src/test/run-make-fulldeps/lto-empty/lib.rs b/src/test/run-make-fulldeps/lto-empty/lib.rs new file mode 100644 index 0000000000000..e3663c79078f4 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-empty/lib.rs @@ -0,0 +1 @@ +#![crate_type = "cdylib"] diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index 3b4df73cdfd6d..9a113b7fa6370 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -12,7 +12,7 @@ RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options +RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index d2cdeb8f8f50e..fcbd7cabc6900 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -3,6 +3,7 @@ // adapted to use that, and that normalize line can go away // compile-flags:--test +// rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout index e362ecf349e45..ef1b419f52895 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.stdout +++ b/src/test/rustdoc-ui/failed-doctest-output.stdout @@ -1,13 +1,13 @@ running 2 tests -test $DIR/failed-doctest-output.rs - OtherStruct (line 20) ... FAILED -test $DIR/failed-doctest-output.rs - SomeStruct (line 10) ... FAILED +test $DIR/failed-doctest-output.rs - OtherStruct (line 21) ... FAILED +test $DIR/failed-doctest-output.rs - SomeStruct (line 11) ... FAILED failures: ----- $DIR/failed-doctest-output.rs - OtherStruct (line 20) stdout ---- +---- $DIR/failed-doctest-output.rs - OtherStruct (line 21) stdout ---- error[E0425]: cannot find value `no` in this scope - --> $DIR/failed-doctest-output.rs:21:1 + --> $DIR/failed-doctest-output.rs:22:1 | 3 | no | ^^ not found in this scope @@ -16,7 +16,7 @@ error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. Couldn't compile the test. ----- $DIR/failed-doctest-output.rs - SomeStruct (line 10) stdout ---- +---- $DIR/failed-doctest-output.rs - SomeStruct (line 11) stdout ---- Test executable failed (exit code 101). stdout: @@ -32,8 +32,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. failures: - $DIR/failed-doctest-output.rs - OtherStruct (line 20) - $DIR/failed-doctest-output.rs - SomeStruct (line 10) + $DIR/failed-doctest-output.rs - OtherStruct (line 21) + $DIR/failed-doctest-output.rs - SomeStruct (line 11) test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs index 2b02d47d4b851..3ef66e273d0d0 100644 --- a/src/test/rustdoc-ui/invalid-syntax.rs +++ b/src/test/rustdoc-ui/invalid-syntax.rs @@ -64,3 +64,13 @@ pub fn blargh() {} /// \_ #[doc = "```"] pub fn crazy_attrs() {} + +/// ```rust +/// ``` +pub fn empty_rust() {} + +/// ``` +/// +/// +/// ``` +pub fn empty_rust_with_whitespace() {} diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 3bebbecb9dfcf..36209e2927771 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -179,6 +179,28 @@ LL | | #[doc = "```"] | = help: mark blocks that do not contain Rust code as text: ```text +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:68:5 + | +LL | /// ```rust + | _____^ +LL | | /// ``` + | |_______^ + +warning: Rust code block is empty + --> $DIR/invalid-syntax.rs:72:5 + | +LL | /// ``` + | _____^ +LL | | /// +LL | | /// +LL | | /// ``` + | |_______^ +help: mark blocks that do not contain Rust code as text + | +LL | /// ```text + | ^^^^^^^ + error: unknown start of token: \ --> :1:1 | diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index ee622e74a08dc..bb6af7995a0ad 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -95,5 +95,5 @@ impl Qux for Bar { /// Docs for QUX_DEFAULT1 in impl. const QUX_DEFAULT1: i16 = 7; // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32' - // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." + // @has - '//*[@class="docblock hidden"]' "Docs for QUX_DEFAULT2 in trait." } diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs index d4f05bab5cabf..7eb3e43cb114e 100644 --- a/src/test/rustdoc/inline_cross/assoc-items.rs +++ b/src/test/rustdoc/inline_cross/assoc-items.rs @@ -16,15 +16,15 @@ extern crate assoc_items; // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16' // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault' // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16' -// @has - '//*[@class="docblock"]' 'docs for ConstWithDefault' +// @has - '//*[@class="docblock hidden"]' 'docs for ConstWithDefault' // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32' // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault' // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32' -// @has - '//*[@class="docblock"]' 'docs for TypeWithDefault' +// @has - '//*[@class="docblock hidden"]' 'docs for TypeWithDefault' // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()' // @has - '//*[@class="docblock"]' 'dox for method_no_default' // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()' -// @has - '//*[@class="docblock"]' 'docs for method_with_default' +// @has - '//*[@class="docblock hidden"]' 'docs for method_with_default' pub use assoc_items::MyStruct; // @has foo/trait.MyTrait.html diff --git a/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs new file mode 100644 index 0000000000000..21c733a9bc98e --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/impl_trait_aux.rs @@ -0,0 +1,18 @@ +use std::ops::Deref; + +pub fn func<'a>(_x: impl Clone + Into> + 'a) {} + +pub fn func2( + _x: impl Deref> + Iterator, + _y: impl Iterator, +) {} + +pub fn func3(_x: impl Iterator> + Clone) {} + +pub fn func4>(_x: T) {} + +pub struct Foo; + +impl Foo { + pub fn method<'a>(_x: impl Clone + Into> + 'a) {} +} diff --git a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs index c99ef74433358..37465ccf1c27e 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/proc_macro.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro #![crate_type="proc-macro"] #![crate_name="some_macros"] @@ -25,3 +26,9 @@ pub fn some_proc_attr(_attr: TokenStream, item: TokenStream) -> TokenStream { pub fn some_derive(_item: TokenStream) -> TokenStream { TokenStream::new() } + +/// Doc comment from the original crate +#[proc_macro] +pub fn reexported_macro(_input: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs index cadeccb60c817..4591bb526ae77 100644 --- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs +++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs @@ -8,5 +8,5 @@ extern crate impl_inline_without_trait; // @has 'foo/struct.MyStruct.html' // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()' -// @has - '//*[@class="docblock"]' 'docs for my_trait_method' +// @has - '//*[@class="docblock hidden"]' 'docs for my_trait_method' pub use impl_inline_without_trait::MyStruct; diff --git a/src/test/rustdoc/inline_cross/impl_trait.rs b/src/test/rustdoc/inline_cross/impl_trait.rs new file mode 100644 index 0000000000000..b1e3f8d145b5f --- /dev/null +++ b/src/test/rustdoc/inline_cross/impl_trait.rs @@ -0,0 +1,32 @@ +// aux-build:impl_trait_aux.rs + +extern crate impl_trait_aux; + +// @has impl_trait/fn.func.html +// @has - '//pre[@class="rust fn"]' "pub fn func<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func; + +// @has impl_trait/fn.func2.html +// @has - '//pre[@class="rust fn"]' "func2(" +// @has - '//pre[@class="rust fn"]' "_x: impl Deref> + Iterator," +// @has - '//pre[@class="rust fn"]' "_y: impl Iterator)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func2; + +// @has impl_trait/fn.func3.html +// @has - '//pre[@class="rust fn"]' "func3(" +// @has - '//pre[@class="rust fn"]' "_x: impl Clone + Iterator>)" +// @!has - '//pre[@class="rust fn"]' 'where' +pub use impl_trait_aux::func3; + + +// @has impl_trait/fn.func4.html +// @has - '//pre[@class="rust fn"]' "func4(" +// @has - '//pre[@class="rust fn"]' "T: Iterator," +pub use impl_trait_aux::func4; + +// @has impl_trait/struct.Foo.html +// @has - '//code[@id="method.v"]' "pub fn method<'a>(_x: impl Clone + Into> + 'a)" +// @!has - '//code[@id="method.v"]' 'where' +pub use impl_trait_aux::Foo; diff --git a/src/test/rustdoc/inline_cross/proc_macro.rs b/src/test/rustdoc/inline_cross/proc_macro.rs index e1cdcf4940244..6880e303df90b 100644 --- a/src/test/rustdoc/inline_cross/proc_macro.rs +++ b/src/test/rustdoc/inline_cross/proc_macro.rs @@ -1,16 +1,17 @@ // aux-build:proc_macro.rs // build-aux-docs -// FIXME: if/when proc-macros start exporting their doc attributes across crates, we can turn on -// cross-crate inlining for them - extern crate some_macros; // @has proc_macro/index.html -// @has - '//a/@href' '../some_macros/macro.some_proc_macro.html' -// @has - '//a/@href' '../some_macros/attr.some_proc_attr.html' -// @has - '//a/@href' '../some_macros/derive.SomeDerive.html' -// @!has proc_macro/macro.some_proc_macro.html -// @!has proc_macro/attr.some_proc_attr.html -// @!has proc_macro/derive.SomeDerive.html +// @has - '//a/@href' 'macro.some_proc_macro.html' +// @has - '//a/@href' 'attr.some_proc_attr.html' +// @has - '//a/@href' 'derive.SomeDerive.html' +// @has proc_macro/macro.some_proc_macro.html +// @has proc_macro/attr.some_proc_attr.html +// @has proc_macro/derive.SomeDerive.html pub use some_macros::{some_proc_macro, some_proc_attr, SomeDerive}; + +// @has proc_macro/macro.reexported_macro.html +// @has - 'Doc comment from the original crate' +pub use some_macros::reexported_macro; diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs index c9e4f4e0d3037..11ddab5f7ff26 100644 --- a/src/test/rustdoc/manual_impl.rs +++ b/src/test/rustdoc/manual_impl.rs @@ -24,10 +24,10 @@ pub trait T { // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.' // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait c_method definition.' // @!has - '//*[@class="docblock"]' 'There is another line' -// @has - '//*[@class="docblock"]' 'Read more' +// @has - '//*[@class="docblock hidden"]' 'Read more' pub struct S1(usize); /// Docs associated with the S1 trait implementation. @@ -44,7 +44,7 @@ impl T for S1 { // @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait c_method definition.' -// @has - '//*[@class="docblock"]' 'Docs associated with the trait b_method definition.' +// @has - '//*[@class="docblock hidden"]' 'Docs associated with the trait b_method definition.' pub struct S2(usize); /// Docs associated with the S2 trait implementation. diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index 4bd0b092b55a7..82196e413e94b 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro --document-private-items #![crate_type="proc-macro"] #![crate_name="some_macros"] @@ -58,7 +59,7 @@ pub fn some_derive(_item: TokenStream) -> TokenStream { } // @has some_macros/foo/index.html -pub mod foo { +mod foo { // @has - '//code' 'pub use some_proc_macro;' // @has - '//a/@href' '../../some_macros/macro.some_proc_macro.html' pub use some_proc_macro; diff --git a/src/test/rustdoc/rustc-macro-crate.rs b/src/test/rustdoc/rustc-macro-crate.rs index 2f6308b20c2ee..dd5edc984dafa 100644 --- a/src/test/rustdoc/rustc-macro-crate.rs +++ b/src/test/rustdoc/rustc-macro-crate.rs @@ -1,5 +1,6 @@ // force-host // no-prefer-dynamic +// compile-flags: --crate-type proc-macro #![crate_type = "proc-macro"] diff --git a/src/test/ui/abi/abort-on-c-abi.rs b/src/test/ui/abi/abort-on-c-abi.rs index cd7dd1b6a452f..2f08730ec6132 100644 --- a/src/test/ui/abi/abort-on-c-abi.rs +++ b/src/test/ui/abi/abort-on-c-abi.rs @@ -1,6 +1,7 @@ // run-pass #![allow(unused_must_use)] +#![feature(unwind_attributes)] // Since we mark some ABIs as "nounwind" to LLVM, we must make sure that // we never unwind through them. @@ -13,6 +14,7 @@ use std::io::prelude::*; use std::io; use std::process::{Command, Stdio}; +#[unwind(aborts)] // FIXME(#58794) extern "C" fn panic_in_ffi() { panic!("Test"); } diff --git a/src/test/ui/anon-params-denied-2018.rs b/src/test/ui/anon-params-denied-2018.rs index abff8275064e2..5721f5d235783 100644 --- a/src/test/ui/anon-params-denied-2018.rs +++ b/src/test/ui/anon-params-denied-2018.rs @@ -3,7 +3,7 @@ // edition:2018 trait T { - fn foo(i32); //~ expected one of `:` or `@`, found `)` + fn foo(i32); //~ expected one of `:`, `@`, or `|`, found `)` fn bar_with_default_impl(String, String) {} //~^ ERROR expected one of `:` diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index 438bcf4274daa..a58998e4891e0 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | LL | fn foo(i32); - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -14,11 +14,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(_: i32); | ^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -30,11 +30,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(_: String, String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:8:44 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -46,11 +46,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn bar_with_default_impl(String, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:13:22 | LL | fn baz(a:usize, b, c: usize) -> usize { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index 0ca3ca8437463..c65a44bfbccfe 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -5,12 +5,9 @@ LL | f1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), &'s ()) -> _` - | -note: required by `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 - | +... LL | fn f1(_: F) where F: Fn(&(), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------ required by `f1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:2:5 @@ -19,12 +16,9 @@ LL | f1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &()) -> _` - | -note: required by `f1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:27:1 - | +... LL | fn f1(_: F) where F: Fn(&(), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------ required by `f1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 @@ -33,12 +27,9 @@ LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'a, 'r> fn(&'a (), &'r ()) -> _` - | -note: required by `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 - | +... LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------------------- required by `f2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:4:5 @@ -47,12 +38,9 @@ LL | f2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'a (), &()) -> _` - | -note: required by `f2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:28:1 - | +... LL | fn f2(_: F) where F: for<'a> Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------------------- required by `f2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 @@ -61,12 +49,9 @@ LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&(), &'r ()) -> _` - | -note: required by `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 - | +... LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------- required by `f3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:6:5 @@ -75,12 +60,9 @@ LL | f3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &()) -> _` - | -note: required by `f3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:29:1 - | +... LL | fn f3<'a, F>(_: F) where F: Fn(&'a (), &()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------- required by `f3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 @@ -89,12 +71,9 @@ LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s, 'r> fn(&'s (), &'r ()) -> _` - | -note: required by `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 - | +... LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------------------- required by `f4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:8:5 @@ -103,12 +82,9 @@ LL | f4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), &'r ()) -> _` - | -note: required by `f4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:30:1 - | +... LL | fn f4(_: F) where F: for<'r> Fn(&(), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------------------- required by `f4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 @@ -117,12 +93,9 @@ LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), &'r ()) -> _` - | -note: required by `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1 - | +... LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -------------------------------------------------- required by `f5` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:10:5 @@ -131,12 +104,9 @@ LL | f5(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'r (), &'r ()) -> _` - | -note: required by `f5` - --> $DIR/anonymous-higher-ranked-lifetime.rs:31:1 - | +... LL | fn f5(_: F) where F: for<'r> Fn(&'r (), &'r ()) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -------------------------------------------------- required by `f5` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 @@ -145,12 +115,9 @@ LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _` - | -note: required by `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 - | +... LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------------- required by `g1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:12:5 @@ -159,12 +126,9 @@ LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:34:1 - | +... LL | fn g1(_: F) where F: Fn(&(), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------------- required by `g1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 @@ -173,12 +137,9 @@ LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'r> fn(&'r (), for<'s> fn(&'s ())) -> _` - | -note: required by `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 - | +... LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ---------------------------------------- required by `g2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:14:5 @@ -187,12 +148,9 @@ LL | g2(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` - | -note: required by `g2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:35:1 - | +... LL | fn g2(_: F) where F: Fn(&(), fn(&())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ---------------------------------------- required by `g2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 @@ -201,12 +159,9 @@ LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 - | +... LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------------------------ required by `g3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:16:5 @@ -215,12 +170,9 @@ LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` - | -note: required by `g3` - --> $DIR/anonymous-higher-ranked-lifetime.rs:36:1 - | +... LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ------------------------------------------------------------ required by `g3` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 @@ -229,12 +181,9 @@ LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `for<'s> fn(&'s (), for<'r> fn(&'r ())) -> _` - | -note: required by `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1 - | +... LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------------------------------- required by `g4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:18:5 @@ -243,12 +192,9 @@ LL | g4(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | | expected signature of `fn(&(), for<'r> fn(&'r ())) -> _` - | -note: required by `g4` - --> $DIR/anonymous-higher-ranked-lifetime.rs:37:1 - | +... LL | fn g4(_: F) where F: Fn(&(), for<'r> fn(&'r ())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------------------------------- required by `g4` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 @@ -257,12 +203,9 @@ LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` - | -note: required by `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 - | +... LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -------------------------------------------------------------------- required by `h1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:20:5 @@ -271,12 +214,9 @@ LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &(), for<'r, 's> fn(&'r (), &'s ())) -> _` - | -note: required by `h1` - --> $DIR/anonymous-higher-ranked-lifetime.rs:40:1 - | +... LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -------------------------------------------------------------------- required by `h1` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 @@ -285,12 +225,9 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` - | -note: required by `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 - | +... LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------------------------------------------------------------- required by `h2` error[E0631]: type mismatch in closure arguments --> $DIR/anonymous-higher-ranked-lifetime.rs:22:5 @@ -299,12 +236,9 @@ LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | | expected signature of `fn(&(), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>, &'t0 (), for<'r, 's> fn(&'r (), &'s ())) -> _` - | -note: required by `h2` - --> $DIR/anonymous-higher-ranked-lifetime.rs:41:1 - | +... LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------------------------------------------------------------- required by `h2` error: aborting due to 22 previous errors diff --git a/src/test/ui/array-break-length.rs b/src/test/ui/array-break-length.rs index 2696aea5e8993..959f4a2babbf8 100644 --- a/src/test/ui/array-break-length.rs +++ b/src/test/ui/array-break-length.rs @@ -1,11 +1,11 @@ fn main() { loop { - |_: [_; break]| {} //~ ERROR: `break` outside of loop + |_: [_; break]| {} //~ ERROR: `break` outside of a loop //~^ ERROR mismatched types } loop { - |_: [_; continue]| {} //~ ERROR: `continue` outside of loop + |_: [_; continue]| {} //~ ERROR: `continue` outside of a loop //~^ ERROR mismatched types } } diff --git a/src/test/ui/array-break-length.stderr b/src/test/ui/array-break-length.stderr index 0e0dc8f623e68..45f529bafe728 100644 --- a/src/test/ui/array-break-length.stderr +++ b/src/test/ui/array-break-length.stderr @@ -1,14 +1,14 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/array-break-length.rs:3:17 | LL | |_: [_; break]| {} - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/array-break-length.rs:8:17 | LL | |_: [_; continue]| {} - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop error[E0308]: mismatched types --> $DIR/array-break-length.rs:3:9 diff --git a/src/test/ui/associated-const/associated-const-array-len.stderr b/src/test/ui/associated-const/associated-const-array-len.stderr index ff56d112c8184..2fdfa3da3086c 100644 --- a/src/test/ui/associated-const/associated-const-array-len.stderr +++ b/src/test/ui/associated-const/associated-const-array-len.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/associated-const-array-len.rs:5:16 | +LL | const ID: usize; + | ---------------- required by `Foo::ID` +... LL | const X: [i32; ::ID] = [0, 1, 2]; | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `Foo::ID` - --> $DIR/associated-const-array-len.rs:2:5 - | -LL | const ID: usize; - | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr index 573b8ed39bcaa..30b6b4f3909b2 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays-2.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: Foo` is not satisfied --> $DIR/associated-const-type-parameter-arrays-2.rs:16:22 | +LL | const Y: usize; + | --------------- required by `Foo::Y` +... LL | let _array = [4; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` | = help: consider adding a `where A: Foo` bound -note: required by `Foo::Y` - --> $DIR/associated-const-type-parameter-arrays-2.rs:2:5 - | -LL | const Y: usize; - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr index bf1ee38571404..30fa9891a13e1 100644 --- a/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr +++ b/src/test/ui/associated-const/associated-const-type-parameter-arrays.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: Foo` is not satisfied --> $DIR/associated-const-type-parameter-arrays.rs:16:23 | +LL | const Y: usize; + | --------------- required by `Foo::Y` +... LL | let _array: [u32; ::Y]; | ^^^^^^^^^^^^^ the trait `Foo` is not implemented for `A` | = help: consider adding a `where A: Foo` bound -note: required by `Foo::Y` - --> $DIR/associated-const-type-parameter-arrays.rs:2:5 - | -LL | const Y: usize; - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index aebf29cc332ab..06e8230aa1589 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -24,6 +24,9 @@ LL | | } error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -35,15 +38,13 @@ LL | | } | = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Send` bound -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -55,15 +56,13 @@ LL | | } | = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` = help: consider adding a `where <::C as std::iter::Iterator>::Item: std::marker::Sync` bound -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` --> $DIR/bad-bounds-on-assoc-in-trait.rs:37:1 | +LL | trait Case1 { + | ----------- required by `Case1` +... LL | / fn assume_case1() { LL | | LL | | @@ -74,11 +73,6 @@ LL | | } | |_^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App` -note: required by `Case1` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:22:1 - | -LL | trait Case1 { - | ^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr index 89c48d50cdb65..a3049892abc39 100644 --- a/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr +++ b/src/test/ui/associated-types/associated-types-binding-to-type-defined-in-supertrait.stderr @@ -1,30 +1,26 @@ error[E0271]: type mismatch resolving `::Color == Blue` --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:31:10 | +LL | fn blue_car>(c: C) { + | ------------------------------------ required by `blue_car` +... LL | fn b() { blue_car(ModelT); } | ^^^^^^^^ expected struct `Black`, found struct `Blue` | = note: expected type `Black` found type `Blue` -note: required by `blue_car` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:27:1 - | -LL | fn blue_car>(c: C) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `::Color == Black` --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:32:10 | +LL | fn black_car>(c: C) { + | -------------------------------------- required by `black_car` +... LL | fn c() { black_car(ModelU); } | ^^^^^^^^^ expected struct `Blue`, found struct `Black` | = note: expected type `Blue` found type `Black` -note: required by `black_car` - --> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:24:1 - | -LL | fn black_car>(c: C) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-bound-failure.stderr b/src/test/ui/associated-types/associated-types-bound-failure.stderr index 502fb4f1c3033..54654b95edd90 100644 --- a/src/test/ui/associated-types/associated-types-bound-failure.stderr +++ b/src/test/ui/associated-types/associated-types-bound-failure.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `::R: ToInt` is not satisfied --> $DIR/associated-types-bound-failure.rs:17:5 | +LL | fn to_int(&self) -> isize; + | -------------------------- required by `ToInt::to_int` +... LL | ToInt::to_int(&g.get()) | ^^^^^^^^^^^^^ the trait `ToInt` is not implemented for `::R` | = help: consider adding a `where ::R: ToInt` bound -note: required by `ToInt::to_int` - --> $DIR/associated-types-bound-failure.rs:4:5 - | -LL | fn to_int(&self) -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr index 66fa4c288ca46..0f8c5257d445f 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.stderr +++ b/src/test/ui/associated-types/associated-types-eq-3.stderr @@ -10,16 +10,14 @@ LL | let _: Bar = x.boo(); error[E0271]: type mismatch resolving `::A == Bar` --> $DIR/associated-types-eq-3.rs:38:5 | +LL | fn foo1>(x: I) { + | ---------------------------- required by `foo1` +... LL | foo1(a); | ^^^^ expected usize, found struct `Bar` | = note: expected type `usize` found type `Bar` -note: required by `foo1` - --> $DIR/associated-types-eq-3.rs:18:1 - | -LL | fn foo1>(x: I) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `::A == Bar` --> $DIR/associated-types-eq-3.rs:41:9 diff --git a/src/test/ui/associated-types/associated-types-eq-hr.stderr b/src/test/ui/associated-types/associated-types-eq-hr.stderr index 353829c2f7631..05e6ed69812ad 100644 --- a/src/test/ui/associated-types/associated-types-eq-hr.stderr +++ b/src/test/ui/associated-types/associated-types-eq-hr.stderr @@ -1,124 +1,108 @@ error[E0271]: type mismatch resolving `for<'x> >::A == &'x isize` --> $DIR/associated-types-eq-hr.rs:82:5 | -LL | foo::(); - | ^^^^^^^^^^^^^^^^^ expected usize, found isize - | - = note: expected type `&usize` - found type `&isize` -note: required by `foo` - --> $DIR/associated-types-eq-hr.rs:44:1 - | LL | / fn foo() LL | | where T : for<'x> TheTrait<&'x isize, A = &'x isize> LL | | { LL | | // ok for IntStruct, but not UintStruct LL | | } - | |_^ + | |_- required by `foo` +... +LL | foo::(); + | ^^^^^^^^^^^^^^^^^ expected usize, found isize + | + = note: expected type `&usize` + found type `&isize` error[E0271]: type mismatch resolving `for<'x> >::A == &'x usize` --> $DIR/associated-types-eq-hr.rs:86:5 | -LL | bar::(); - | ^^^^^^^^^^^^^^^^ expected isize, found usize - | - = note: expected type `&isize` - found type `&usize` -note: required by `bar` - --> $DIR/associated-types-eq-hr.rs:50:1 - | LL | / fn bar() LL | | where T : for<'x> TheTrait<&'x isize, A = &'x usize> LL | | { LL | | // ok for UintStruct, but not IntStruct LL | | } - | |_^ + | |_- required by `bar` +... +LL | bar::(); + | ^^^^^^^^^^^^^^^^ expected isize, found usize + | + = note: expected type `&isize` + found type `&usize` error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:91:5 | -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 - | LL | / fn tuple_one() LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> LL | | { LL | | // not ok for tuple, two lifetimes and we pick first LL | | } - | |_^ + | |_- required by `tuple_one` +... +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | + = help: the following implementations were found: + > error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'x isize` --> $DIR/associated-types-eq-hr.rs:91:5 | -LL | tuple_one::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | -note: required by `tuple_one` - --> $DIR/associated-types-eq-hr.rs:56:1 - | LL | / fn tuple_one() LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize> LL | | { LL | | // not ok for tuple, two lifetimes and we pick first LL | | } - | |_^ + | |_- required by `tuple_one` +... +LL | tuple_one::(); + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:97:5 | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 - | LL | / fn tuple_two() LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> LL | | { LL | | // not ok for tuple, two lifetimes and we pick second LL | | } - | |_^ + | |_- required by `tuple_two` +... +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | + = help: the following implementations were found: + > error[E0271]: type mismatch resolving `for<'x, 'y> >::A == &'y isize` --> $DIR/associated-types-eq-hr.rs:97:5 | -LL | tuple_two::(); - | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime - | -note: required by `tuple_two` - --> $DIR/associated-types-eq-hr.rs:62:1 - | LL | / fn tuple_two() LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize> LL | | { LL | | // not ok for tuple, two lifetimes and we pick second LL | | } - | |_^ + | |_- required by `tuple_two` +... +LL | tuple_two::(); + | ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'x, found concrete lifetime error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied --> $DIR/associated-types-eq-hr.rs:107:5 | -LL | tuple_four::(); - | ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` - | - = help: the following implementations were found: - > -note: required by `tuple_four` - --> $DIR/associated-types-eq-hr.rs:74:1 - | LL | / fn tuple_four() LL | | where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)> LL | | { LL | | // not ok for tuple, two lifetimes, and lifetime matching is invariant LL | | } - | |_^ + | |_- required by `tuple_four` +... +LL | tuple_four::(); + | ^^^^^^^^^^^^^^^^^^^ the trait `for<'x, 'y> TheTrait<(&'x isize, &'y isize)>` is not implemented for `Tuple` + | + = help: the following implementations were found: + > error: aborting due to 7 previous errors diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index 7d5b16c6e62d0..7d6c025d69d55 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -1,16 +1,14 @@ error[E0271]: type mismatch resolving ` as Iterator>::Item == std::option::Option` --> $DIR/associated-types-issue-20346.rs:34:5 | +LL | fn is_iterator_of>(_: &I) {} + | ------------------------------------------------ required by `is_iterator_of` +... LL | is_iterator_of::, _>(&adapter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found enum `std::option::Option` | = note: expected type `T` found type `std::option::Option` -note: required by `is_iterator_of` - --> $DIR/associated-types-issue-20346.rs:15:1 - | -LL | fn is_iterator_of>(_: &I) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr index 2926bdae0525b..4a2a6d03c607f 100644 --- a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr +++ b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr @@ -3,28 +3,24 @@ error[E0271]: type mismatch resolving `::Y == i32` | LL | want_y(t); | ^^^^^^ expected associated type, found i32 +... +LL | fn want_y>(t: &T) { } + | ------------------------------ required by `want_y` | = note: expected type `::Y` found type `i32` -note: required by `want_y` - --> $DIR/associated-types-multiple-types-one-trait.rs:44:1 - | -LL | fn want_y>(t: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `::X == u32` --> $DIR/associated-types-multiple-types-one-trait.rs:18:5 | LL | want_x(t); | ^^^^^^ expected associated type, found u32 +... +LL | fn want_x>(t: &T) { } + | ------------------------------ required by `want_x` | = note: expected type `::X` found type `u32` -note: required by `want_x` - --> $DIR/associated-types-multiple-types-one-trait.rs:42:1 - | -LL | fn want_x>(t: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index a26ee23894f6d..a7238541cd96e 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,14 +1,10 @@ error[E0284]: type annotations required: cannot resolve `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:1 | +LL | trait Foo: Iterator {} + | ------------------------------- required by `Foo` LL | trait Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by `Foo` - --> $DIR/associated-types-overridden-binding.rs:3:1 - | -LL | trait Foo: Iterator {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index 1405cb1b4736c..a8fcaeac95d5f 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -11,14 +11,11 @@ LL | f1(2i32, 4u32); error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:5 | +LL | pub fn f1(a: T, x: T::A) {} + | -------------------------------- required by `f1` +... LL | f1(2u32, 4u32); | ^^ the trait `Foo` is not implemented for `u32` - | -note: required by `f1` - --> $DIR/associated-types-path-2.rs:13:1 - | -LL | pub fn f1(a: T, x: T::A) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:29:5 @@ -29,14 +26,11 @@ LL | f1(2u32, 4u32); error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:35:5 | +LL | pub fn f1(a: T, x: T::A) {} + | -------------------------------- required by `f1` +... LL | f1(2u32, 4i32); | ^^ the trait `Foo` is not implemented for `u32` - | -note: required by `f1` - --> $DIR/associated-types-path-2.rs:13:1 - | -LL | pub fn f1(a: T, x: T::A) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u32: Foo` is not satisfied --> $DIR/associated-types-path-2.rs:35:5 diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr index cc69e849fe144..22d44888e951b 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.stderr @@ -1,16 +1,13 @@ error[E0271]: type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` --> $DIR/higher-ranked-projection.rs:25:5 | -LL | foo(()); - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime - | -note: required by `foo` - --> $DIR/higher-ranked-projection.rs:14:1 - | LL | / fn foo(_t: T) LL | | where for<'a> &'a T: Mirror LL | | {} - | |__^ + | |__- required by `foo` +... +LL | foo(()); + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime error: aborting due to previous error diff --git a/src/test/ui/ast-json/ast-json-ice.rs b/src/test/ui/ast-json/ast-json-ice.rs new file mode 100644 index 0000000000000..e8a622e1b8772 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-ice.rs @@ -0,0 +1,41 @@ +// Test that AST json serialization doesn't ICE (#63728). + +// revisions: expand noexpand + +//[expand] compile-flags: -Zast-json +//[noexpand] compile-flags: -Zast-json-noexpand + +// check-pass +// dont-check-compiler-stdout - don't check for any AST change. + +#![feature(asm)] + +enum V { + A(i32), + B { f: [i64; 3 + 4] } +} + +trait X { + type Output; + fn read(&self) -> Self::Output; + fn write(&mut self, _: Self::Output); +} + +macro_rules! call_println { + ($y:ident) => { println!("{}", $y) } +} + +fn main() { + #[cfg(any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm", + target_arch = "aarch64"))] + unsafe { asm!(""::::); } + + let x: (i32) = 35; + let y = x as i64<> + 5; + + call_println!(y); + + struct A; +} diff --git a/src/test/ui/ast-json/ast-json-output.rs b/src/test/ui/ast-json/ast-json-output.rs new file mode 100644 index 0000000000000..e444a07460248 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-output.rs @@ -0,0 +1,9 @@ +// Check that AST json printing works. + +// check-pass +// compile-flags: -Zast-json-noexpand +// normalize-stdout-test ":\d+" -> ":0" + +// Only include a single item to reduce how often the test output needs +// updating. +extern crate core; diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout new file mode 100644 index 0000000000000..d23cbe0240ee1 --- /dev/null +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -0,0 +1 @@ +{"module":{"inner":{"lo":0,"hi":0},"items":[{"ident":{"name":"core","span":{"lo":0,"hi":0}},"attrs":[],"id":0,"node":{"variant":"ExternCrate","fields":[null]},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"span":{"lo":0,"hi":0},"tokens":[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["extern",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["core",false]},"span":{"lo":0,"hi":0}}]},{"variant":"Token","fields":[{"kind":"Semi","span":{"lo":0,"hi":0}}]}]}],"inline":true},"attrs":[],"span":{"lo":0,"hi":0}} diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 90d75118f8e42..753a4e491550f 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -30,14 +30,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 { fn no_break_in_async_block() { async { - break 0u8; //~ ERROR `break` inside of an async block + break 0u8; //~ ERROR `break` inside of an `async` block }; } fn no_break_in_async_block_even_with_outer_loop() { loop { async { - break 0u8; //~ ERROR `break` inside of an async block + break 0u8; //~ ERROR `break` inside of an `async` block }; } } diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index bc42a46ae1021..c36caa5586fb0 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,14 +1,22 @@ -error[E0267]: `break` inside of an async block +error[E0267]: `break` inside of an `async` block --> $DIR/async-block-control-flow-static-semantics.rs:33:9 | -LL | break 0u8; - | ^^^^^^^^^ cannot break inside of an async block +LL | async { + | ___________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_____- enclosing `async` block -error[E0267]: `break` inside of an async block +error[E0267]: `break` inside of an `async` block --> $DIR/async-block-control-flow-static-semantics.rs:40:13 | -LL | break 0u8; - | ^^^^^^^^^ cannot break inside of an async block +LL | async { + | _______________- +LL | | break 0u8; + | | ^^^^^^^^^ cannot `break` inside of an `async` block +LL | | }; + | |_________- enclosing `async` block error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:13:43 diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index 6b4fff2dc6844..fad90b29c0e6e 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -1,6 +1,9 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:50:5 | +LL | fn assert_send(_: impl Send) {} + | ---------------------------- required by `assert_send` +... LL | assert_send(local_dropped_before_await()); | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | @@ -11,15 +14,13 @@ LL | assert_send(local_dropped_before_await()); = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:21:39: 26:2 {impl std::fmt::Debug, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:47:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:52:5 | +LL | fn assert_send(_: impl Send) {} + | ---------------------------- required by `assert_send` +... LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | @@ -30,15 +31,13 @@ LL | assert_send(non_send_temporary_in_match()); = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:28:40: 37:2 {fn(impl std::fmt::Debug) -> std::option::Option {std::option::Option::::Some}, fn() -> impl std::fmt::Debug {non_send}, impl std::fmt::Debug, std::option::Option, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:47:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dyn std::fmt::Write` cannot be sent between threads safely --> $DIR/async-fn-nonsend.rs:54:5 | +LL | fn assert_send(_: impl Send) {} + | ---------------------------- required by `assert_send` +... LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ `dyn std::fmt::Write` cannot be sent between threads safely | @@ -51,15 +50,13 @@ LL | assert_send(non_sync_with_method_call()); = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:47:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/async-fn-nonsend.rs:54:5 | +LL | fn assert_send(_: impl Send) {} + | ---------------------------- required by `assert_send` +... LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -76,11 +73,6 @@ LL | assert_send(non_sync_with_method_call()); = note: required because it appears within the type `std::future::GenFuture<[static generator@$DIR/async-fn-nonsend.rs:39:38: 45:2 for<'r, 's> {&'r mut std::fmt::Formatter<'s>, bool, impl std::future::Future, ()}]>` = note: required because it appears within the type `impl std::future::Future` = note: required because it appears within the type `impl std::future::Future` -note: required by `assert_send` - --> $DIR/async-fn-nonsend.rs:47:1 - | -LL | fn assert_send(_: impl Send) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.rs b/src/test/ui/async-await/no-params-non-move-async-closure.rs similarity index 50% rename from src/test/ui/async-await/no-args-non-move-async-closure.rs rename to src/test/ui/async-await/no-params-non-move-async-closure.rs index 0ca50807f2626..3b15f35c260dc 100644 --- a/src/test/ui/async-await/no-args-non-move-async-closure.rs +++ b/src/test/ui/async-await/no-params-non-move-async-closure.rs @@ -4,5 +4,5 @@ fn main() { let _ = async |x: u8| {}; - //~^ ERROR `async` non-`move` closures with arguments are not currently supported + //~^ ERROR `async` non-`move` closures with parameters are not currently supported } diff --git a/src/test/ui/async-await/no-args-non-move-async-closure.stderr b/src/test/ui/async-await/no-params-non-move-async-closure.stderr similarity index 63% rename from src/test/ui/async-await/no-args-non-move-async-closure.stderr rename to src/test/ui/async-await/no-params-non-move-async-closure.stderr index 1b4b86210f840..04c8c325fe7da 100644 --- a/src/test/ui/async-await/no-args-non-move-async-closure.stderr +++ b/src/test/ui/async-await/no-params-non-move-async-closure.stderr @@ -1,5 +1,5 @@ -error[E0708]: `async` non-`move` closures with arguments are not currently supported - --> $DIR/no-args-non-move-async-closure.rs:6:13 +error[E0708]: `async` non-`move` closures with parameters are not currently supported + --> $DIR/no-params-non-move-async-closure.rs:6:13 | LL | let _ = async |x: u8| {}; | ^^^^^^^^^^^^^ diff --git a/src/test/ui/auxiliary/cond_plugin.rs b/src/test/ui/auxiliary/cond_plugin.rs index 1f97b556a0767..2819541bf6966 100644 --- a/src/test/ui/auxiliary/cond_plugin.rs +++ b/src/test/ui/auxiliary/cond_plugin.rs @@ -3,6 +3,7 @@ #![crate_type = "proc-macro"] #![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] extern crate proc_macro; diff --git a/src/test/ui/auxiliary/proc_macro_def.rs b/src/test/ui/auxiliary/proc_macro_def.rs index dfc5a42d19c69..49cfb5518ba9c 100644 --- a/src/test/ui/auxiliary/proc_macro_def.rs +++ b/src/test/ui/auxiliary/proc_macro_def.rs @@ -3,6 +3,7 @@ #![crate_type = "proc-macro"] #![feature(proc_macro_hygiene)] +#![feature(proc_macro_quote)] extern crate proc_macro; diff --git a/src/test/ui/borrowck/move-error-snippets-ext.rs b/src/test/ui/borrowck/move-error-snippets-ext.rs new file mode 100644 index 0000000000000..c77f6c8276e70 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets-ext.rs @@ -0,0 +1,7 @@ +// ignore-test + +macro_rules! aaa { + ($c:ident) => {{ + let a = $c; + }} +} diff --git a/src/test/ui/borrowck/move-error-snippets.rs b/src/test/ui/borrowck/move-error-snippets.rs new file mode 100644 index 0000000000000..64f9565382886 --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.rs @@ -0,0 +1,23 @@ +// Test that we don't ICE after trying to construct a cross-file snippet #63800. + +// compile-flags: --test + +#[macro_use] +#[path = "move-error-snippets-ext.rs"] +mod move_error_snippets_ext; + +struct A; + +macro_rules! sss { + () => { + #[test] + fn fff() { + static D: A = A; + aaa!(D); //~ ERROR cannot move + } + }; +} + +sss!(); + +fn main() {} diff --git a/src/test/ui/borrowck/move-error-snippets.stderr b/src/test/ui/borrowck/move-error-snippets.stderr new file mode 100644 index 0000000000000..77463c48591bc --- /dev/null +++ b/src/test/ui/borrowck/move-error-snippets.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of static item `D` + --> $DIR/move-error-snippets.rs:16:18 + | +LL | | #[macro_use] + | |__________________^ move occurs because `D` has type `A`, which does not implement the `Copy` trait +... +LL | aaa!(D); + | __________________^ +... +LL | sss!(); + | ------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/break-outside-loop.rs b/src/test/ui/break-outside-loop.rs index fef298f7c3919..c424c25c646bd 100644 --- a/src/test/ui/break-outside-loop.rs +++ b/src/test/ui/break-outside-loop.rs @@ -7,8 +7,8 @@ fn cond() -> bool { true } fn foo(_: F) where F: FnOnce() {} fn main() { - let pth = break; //~ ERROR: `break` outside of loop - if cond() { continue } //~ ERROR: `continue` outside of loop + let pth = break; //~ ERROR: `break` outside of a loop + if cond() { continue } //~ ERROR: `continue` outside of a loop while cond() { if cond() { break } @@ -21,5 +21,5 @@ fn main() { let rs: Foo = Foo{t: pth}; - let unconstrained = break; //~ ERROR: `break` outside of loop + let unconstrained = break; //~ ERROR: `break` outside of a loop } diff --git a/src/test/ui/break-outside-loop.stderr b/src/test/ui/break-outside-loop.stderr index 8f4656ab394cd..8b686356055a3 100644 --- a/src/test/ui/break-outside-loop.stderr +++ b/src/test/ui/break-outside-loop.stderr @@ -1,32 +1,37 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/break-outside-loop.rs:10:15 | LL | let pth = break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/break-outside-loop.rs:11:17 | LL | if cond() { continue } - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop error[E0267]: `break` inside of a closure --> $DIR/break-outside-loop.rs:17:25 | +LL | foo(|| { + | -- enclosing closure LL | if cond() { break } - | ^^^^^ cannot break inside of a closure + | ^^^^^ cannot `break` inside of a closure error[E0267]: `continue` inside of a closure --> $DIR/break-outside-loop.rs:18:25 | +LL | foo(|| { + | -- enclosing closure +LL | if cond() { break } LL | if cond() { continue } - | ^^^^^^^^ cannot break inside of a closure + | ^^^^^^^^ cannot `continue` inside of a closure -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/break-outside-loop.rs:24:25 | LL | let unconstrained = break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to 5 previous errors diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 6cb33f2f2c8c6..15c52f461c183 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -10,17 +10,15 @@ LL | only_foo(x); error[E0277]: the trait bound `{float}: Bar` is not satisfied --> $DIR/type_inference.rs:25:5 | +LL | fn only_bar(_x: T) { } + | -------------------------- required by `only_bar` +... LL | only_bar(x); | ^^^^^^^^ the trait `Bar` is not implemented for `{float}` | = help: the following implementations were found: -note: required by `only_bar` - --> $DIR/type_inference.rs:12:1 - | -LL | fn only_bar(_x: T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr index 7e4ac4e8ce656..565c60e5216dd 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr @@ -1,53 +1,44 @@ error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:30:5 | -LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `fn(fn(&'a u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_free_region` - --> $DIR/expect-fn-supply-fn.rs:1:1 - | LL | / fn with_closure_expecting_fn_with_free_region(_: F) LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_free_region` +... +LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` + | | + | expected signature of `fn(fn(&'a u32), &i32) -> _` error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:37:5 | -LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | LL | / fn with_closure_expecting_fn_with_bound_region(_: F) LL | | where F: FnOnce(fn(&u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_bound_region` +... +LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:46:5 | -LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | LL | / fn with_closure_expecting_fn_with_bound_region(_: F) LL | | where F: FnOnce(fn(&u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_bound_region` +... +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` error: aborting due to 3 previous errors diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr index 40fab4d4edf78..c618c2c550ba1 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.stderr @@ -39,53 +39,44 @@ LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:30:5 | -LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` - | | - | expected signature of `fn(fn(&'a u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_free_region` - --> $DIR/expect-fn-supply-fn.rs:1:1 - | LL | / fn with_closure_expecting_fn_with_free_region(_: F) LL | | where F: for<'a> FnOnce(fn(&'a u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_free_region` +... +LL | with_closure_expecting_fn_with_free_region(|x: fn(&u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ---------------- found signature of `fn(for<'r> fn(&'r u32), _) -> _` + | | + | expected signature of `fn(fn(&'a u32), &i32) -> _` error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:37:5 | -LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | LL | / fn with_closure_expecting_fn_with_bound_region(_: F) LL | | where F: FnOnce(fn(&u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_bound_region` +... +LL | with_closure_expecting_fn_with_bound_region(|x: fn(&'x u32), y| {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------------------- found signature of `fn(fn(&'x u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` error[E0631]: type mismatch in closure arguments --> $DIR/expect-fn-supply-fn.rs:46:5 | -LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` - | | - | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` - | -note: required by `with_closure_expecting_fn_with_bound_region` - --> $DIR/expect-fn-supply-fn.rs:6:1 - | LL | / fn with_closure_expecting_fn_with_bound_region(_: F) LL | | where F: FnOnce(fn(&u32), &i32) LL | | { LL | | } - | |_^ + | |_- required by `with_closure_expecting_fn_with_bound_region` +... +LL | with_closure_expecting_fn_with_bound_region(|x: Foo<'_>, y| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- found signature of `for<'r> fn(fn(&'r u32), _) -> _` + | | + | expected signature of `fn(for<'r> fn(&'r u32), &i32) -> _` error: aborting due to 5 previous errors diff --git a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr index c9a697496de59..a2b3a66dc4d23 100644 --- a/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr +++ b/src/test/ui/closure-expected-type/expect-infer-var-appearing-twice.stderr @@ -1,19 +1,16 @@ error[E0631]: type mismatch in closure arguments --> $DIR/expect-infer-var-appearing-twice.rs:14:5 | -LL | with_closure(|x: u32, y: i32| { - | ^^^^^^^^^^^^ ---------------- found signature of `fn(u32, i32) -> _` - | | - | expected signature of `fn(_, _) -> _` - | -note: required by `with_closure` - --> $DIR/expect-infer-var-appearing-twice.rs:1:1 - | LL | / fn with_closure(_: F) LL | | where F: FnOnce(A, A) LL | | { LL | | } - | |_^ + | |_- required by `with_closure` +... +LL | with_closure(|x: u32, y: i32| { + | ^^^^^^^^^^^^ ---------------- found signature of `fn(u32, i32) -> _` + | | + | expected signature of `fn(_, _) -> _` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-array-break-length.rs b/src/test/ui/closures/closure-array-break-length.rs index a7f16d70ba860..f3567db1fac9c 100644 --- a/src/test/ui/closures/closure-array-break-length.rs +++ b/src/test/ui/closures/closure-array-break-length.rs @@ -1,9 +1,9 @@ fn main() { - |_: [_; continue]| {}; //~ ERROR: `continue` outside of loop + |_: [_; continue]| {}; //~ ERROR: `continue` outside of a loop - while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of loop + while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of a loop //~^ ERROR mismatched types - while |_: [_; break]| {} {} //~ ERROR: `break` outside of loop + while |_: [_; break]| {} {} //~ ERROR: `break` outside of a loop //~^ ERROR mismatched types } diff --git a/src/test/ui/closures/closure-array-break-length.stderr b/src/test/ui/closures/closure-array-break-length.stderr index 46fbd3e0fae0b..18da4a94e6f05 100644 --- a/src/test/ui/closures/closure-array-break-length.stderr +++ b/src/test/ui/closures/closure-array-break-length.stderr @@ -1,20 +1,20 @@ -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/closure-array-break-length.rs:2:13 | LL | |_: [_; continue]| {}; - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/closure-array-break-length.rs:4:19 | LL | while |_: [_; continue]| {} {} - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/closure-array-break-length.rs:7:19 | LL | while |_: [_; break]| {} {} - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error[E0308]: mismatched types --> $DIR/closure-array-break-length.rs:4:11 diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 81c4f4e00aba0..51077b1b2922e 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -1,6 +1,9 @@ error[E0277]: `F` cannot be sent between threads safely --> $DIR/closure-bounds-cant-promote-superkind-in-struct.rs:5:1 | +LL | struct X where F: FnOnce() + 'static + Send { + | ---------------------------------------------- required by `X` +... LL | / fn foo(blk: F) -> X where F: FnOnce() + 'static { LL | | LL | | return X { field: blk }; @@ -9,11 +12,6 @@ LL | | } | = help: the trait `std::marker::Send` is not implemented for `F` = help: consider adding a `where F: std::marker::Send` bound -note: required by `X` - --> $DIR/closure-bounds-cant-promote-superkind-in-struct.rs:1:1 - | -LL | struct X where F: FnOnce() + 'static + Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 3b9fd10af3860..4958bd06d9b16 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -1,16 +1,14 @@ error[E0277]: `F` cannot be shared between threads safely --> $DIR/closure-bounds-subtype.rs:13:5 | +LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { + | ------------------------------------------------------------ required by `take_const_owned` +... LL | take_const_owned(f); | ^^^^^^^^^^^^^^^^ `F` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `F` = help: consider adding a `where F: std::marker::Sync` bound -note: required by `take_const_owned` - --> $DIR/closure-bounds-subtype.rs:4:1 - | -LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/commandline-argfile-badutf8.args b/src/test/ui/commandline-argfile-badutf8.args new file mode 100644 index 0000000000000..c070b0c2400d8 --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.args @@ -0,0 +1,2 @@ +--cfg +unbroken� \ No newline at end of file diff --git a/src/test/ui/commandline-argfile-badutf8.rs b/src/test/ui/commandline-argfile-badutf8.rs new file mode 100644 index 0000000000000..161715685b57f --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-fail +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-badutf8.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-badutf8.stderr b/src/test/ui/commandline-argfile-badutf8.stderr new file mode 100644 index 0000000000000..9af6fc0a518df --- /dev/null +++ b/src/test/ui/commandline-argfile-badutf8.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: Utf8 error in $DIR/commandline-argfile-badutf8.args + diff --git a/src/test/ui/commandline-argfile-missing.rs b/src/test/ui/commandline-argfile-missing.rs new file mode 100644 index 0000000000000..a29b4ab062de3 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.rs @@ -0,0 +1,16 @@ +// Check to see if we can get parameters from an @argsfile file +// +// ignore-tidy-linelength +// build-fail +// normalize-stderr-test: "os error \d+" -> "os error $$ERR" +// normalize-stderr-test: "commandline-argfile-missing.args:[^(]*" -> "commandline-argfile-missing.args: $$FILE_MISSING " +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile-missing.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/commandline-argfile-missing.stderr b/src/test/ui/commandline-argfile-missing.stderr new file mode 100644 index 0000000000000..179ad83100419 --- /dev/null +++ b/src/test/ui/commandline-argfile-missing.stderr @@ -0,0 +1,2 @@ +error: Failed to load argument file: IO Error: $DIR/commandline-argfile-missing.args: $FILE_MISSING (os error $ERR) + diff --git a/src/test/ui/commandline-argfile.args b/src/test/ui/commandline-argfile.args new file mode 100644 index 0000000000000..972938bf6c8dd --- /dev/null +++ b/src/test/ui/commandline-argfile.args @@ -0,0 +1,2 @@ +--cfg +unbroken \ No newline at end of file diff --git a/src/test/ui/commandline-argfile.rs b/src/test/ui/commandline-argfile.rs new file mode 100644 index 0000000000000..fc1ba0c8d677d --- /dev/null +++ b/src/test/ui/commandline-argfile.rs @@ -0,0 +1,13 @@ +// Check to see if we can get parameters from an @argsfile file +// +// build-pass +// compile-flags: --cfg cmdline_set @{{src-base}}/commandline-argfile.args + +#[cfg(not(cmdline_set))] +compile_error!("cmdline_set not set"); + +#[cfg(not(unbroken))] +compile_error!("unbroken not set"); + +fn main() { +} diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs index 0dceba28b6ec3..7dbeba53afcfe 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.rs @@ -3,6 +3,6 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_core)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_core)] //~ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 5a70a5efc7f2a..7b77701ee190f 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-crate-2.rs:6:21 | LL | #![cfg_attr(broken, no_core)] diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs index be762c56048d4..42ffb71e3d7b9 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.rs @@ -1,6 +1,7 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_core, no_std)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_core, no_std)] +//~^ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr index 5e9adf1780737..ab7e1eb96032d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-multi-invalid-1.rs:4:21 | LL | #![cfg_attr(broken, no_core, no_std)] diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs index 8a9e99d703c70..29690e2848f2d 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.rs @@ -1,6 +1,7 @@ // compile-flags: --cfg broken #![crate_type = "lib"] -#![cfg_attr(broken, no_std, no_core)] //~ ERROR no_core is experimental +#![cfg_attr(broken, no_std, no_core)] +//~^ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr index 06b67156651cc..8126affbd36cd 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/cfg-attr-multi-invalid-2.rs:4:29 | LL | #![cfg_attr(broken, no_std, no_core)] diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index 76013c77de0c2..492182921ba34 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -2,5 +2,4 @@ fn main() { &{[1, 2, 3][4]}; //~^ ERROR index out of bounds //~| ERROR reaching this expression at runtime will panic or abort - //~| ERROR this expression will panic at runtime } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 18a09fdda7be4..0ddc2a0e79cd3 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -6,12 +6,6 @@ LL | &{[1, 2, 3][4]}; | = note: `#[deny(const_err)]` on by default -error: this expression will panic at runtime - --> $DIR/array-literal-index-oob.rs:2:5 - | -LL | &{[1, 2, 3][4]}; - | ^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 - error: reaching this expression at runtime will panic or abort --> $DIR/array-literal-index-oob.rs:2:7 | @@ -20,5 +14,5 @@ LL | &{[1, 2, 3][4]}; | | | index out of bounds: the len is 3 but the index is 4 -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs index cc5ddb4401644..a2196db780ce0 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.rs @@ -1,5 +1,6 @@ // only-x86_64 +#[repr(C)] union Nonsense { u: usize, int_32_ref: &'static i32, diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index 73aca911531f1..3333ffac4c9b0 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:24:5 + --> $DIR/const-pointer-values-in-various-types.rs:25:5 | LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -7,7 +7,7 @@ LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 } = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:27:43 + --> $DIR/const-pointer-values-in-various-types.rs:28:43 | LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -17,7 +17,7 @@ LL | const I32_REF_U8_UNION: u8 = unsafe { Nonsense { int_32_ref: &3 }.uint_ = note: `#[deny(const_err)]` on by default error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:30:45 + --> $DIR/const-pointer-values-in-various-types.rs:31:45 | LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uint_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -25,7 +25,7 @@ LL | const I32_REF_U16_UNION: u16 = unsafe { Nonsense { int_32_ref: &3 }.uin | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:33:45 + --> $DIR/const-pointer-values-in-various-types.rs:34:45 | LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uint_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -33,7 +33,7 @@ LL | const I32_REF_U32_UNION: u32 = unsafe { Nonsense { int_32_ref: &3 }.uin | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:36:5 + --> $DIR/const-pointer-values-in-various-types.rs:37:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -41,7 +41,7 @@ LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:39:5 + --> $DIR/const-pointer-values-in-various-types.rs:40:5 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes @@ -49,7 +49,7 @@ LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.u = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:42:43 + --> $DIR/const-pointer-values-in-various-types.rs:43:43 | LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -57,7 +57,7 @@ LL | const I32_REF_I8_UNION: i8 = unsafe { Nonsense { int_32_ref: &3 }.int_8 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:45:45 + --> $DIR/const-pointer-values-in-various-types.rs:46:45 | LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int_16 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -65,7 +65,7 @@ LL | const I32_REF_I16_UNION: i16 = unsafe { Nonsense { int_32_ref: &3 }.int | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:48:45 + --> $DIR/const-pointer-values-in-various-types.rs:49:45 | LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -73,7 +73,7 @@ LL | const I32_REF_I32_UNION: i32 = unsafe { Nonsense { int_32_ref: &3 }.int | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:51:5 + --> $DIR/const-pointer-values-in-various-types.rs:52:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -81,7 +81,7 @@ LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:54:5 + --> $DIR/const-pointer-values-in-various-types.rs:55:5 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes @@ -89,7 +89,7 @@ LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.i = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:57:45 + --> $DIR/const-pointer-values-in-various-types.rs:58:45 | LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.float_32 }; | ----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -97,7 +97,7 @@ LL | const I32_REF_F32_UNION: f32 = unsafe { Nonsense { int_32_ref: &3 }.flo | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:60:5 + --> $DIR/const-pointer-values-in-various-types.rs:61:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -105,7 +105,7 @@ LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.flo = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:63:47 + --> $DIR/const-pointer-values-in-various-types.rs:64:47 | LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.truthy_falsey }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -113,7 +113,7 @@ LL | const I32_REF_BOOL_UNION: bool = unsafe { Nonsense { int_32_ref: &3 }.t | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:66:47 + --> $DIR/const-pointer-values-in-various-types.rs:67:47 | LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.character }; | ------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -121,7 +121,7 @@ LL | const I32_REF_CHAR_UNION: char = unsafe { Nonsense { int_32_ref: &3 }.c | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:69:39 + --> $DIR/const-pointer-values-in-various-types.rs:70:39 | LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -129,7 +129,7 @@ LL | const STR_U8_UNION: u8 = unsafe { Nonsense { stringy: "3" }.uint_8 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:72:41 + --> $DIR/const-pointer-values-in-various-types.rs:73:41 | LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -137,7 +137,7 @@ LL | const STR_U16_UNION: u16 = unsafe { Nonsense { stringy: "3" }.uint_16 } | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:75:41 + --> $DIR/const-pointer-values-in-various-types.rs:76:41 | LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -145,7 +145,7 @@ LL | const STR_U32_UNION: u32 = unsafe { Nonsense { stringy: "3" }.uint_32 } | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:78:5 + --> $DIR/const-pointer-values-in-various-types.rs:79:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -153,7 +153,7 @@ LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 } = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:81:43 + --> $DIR/const-pointer-values-in-various-types.rs:82:43 | LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -161,7 +161,7 @@ LL | const STR_U128_UNION: u128 = unsafe { Nonsense { stringy: "3" }.uint_12 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:84:39 + --> $DIR/const-pointer-values-in-various-types.rs:85:39 | LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; | ----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -169,7 +169,7 @@ LL | const STR_I8_UNION: i8 = unsafe { Nonsense { stringy: "3" }.int_8 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:87:41 + --> $DIR/const-pointer-values-in-various-types.rs:88:41 | LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -177,7 +177,7 @@ LL | const STR_I16_UNION: i16 = unsafe { Nonsense { stringy: "3" }.int_16 }; | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:90:41 + --> $DIR/const-pointer-values-in-various-types.rs:91:41 | LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -185,7 +185,7 @@ LL | const STR_I32_UNION: i32 = unsafe { Nonsense { stringy: "3" }.int_32 }; | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:93:5 + --> $DIR/const-pointer-values-in-various-types.rs:94:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -193,7 +193,7 @@ LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:96:43 + --> $DIR/const-pointer-values-in-various-types.rs:97:43 | LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -201,7 +201,7 @@ LL | const STR_I128_UNION: i128 = unsafe { Nonsense { stringy: "3" }.int_128 | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:99:41 + --> $DIR/const-pointer-values-in-various-types.rs:100:41 | LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 }; | ------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -209,7 +209,7 @@ LL | const STR_F32_UNION: f32 = unsafe { Nonsense { stringy: "3" }.float_32 | a raw memory access tried to access part of a pointer value as raw bytes error[E0080]: it is undefined behavior to use this value - --> $DIR/const-pointer-values-in-various-types.rs:102:5 + --> $DIR/const-pointer-values-in-various-types.rs:103:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -217,7 +217,7 @@ LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:105:43 + --> $DIR/const-pointer-values-in-various-types.rs:106:43 | LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_falsey }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -225,7 +225,7 @@ LL | const STR_BOOL_UNION: bool = unsafe { Nonsense { stringy: "3" }.truthy_ | a raw memory access tried to access part of a pointer value as raw bytes error: any use of this value will cause an error - --> $DIR/const-pointer-values-in-various-types.rs:108:43 + --> $DIR/const-pointer-values-in-various-types.rs:109:43 | LL | const STR_CHAR_UNION: char = unsafe { Nonsense { stringy: "3" }.character }; | --------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- diff --git a/src/test/ui/consts/const-eval/const_transmute.rs b/src/test/ui/consts/const-eval/const_transmute.rs index 0e0e003dcf476..4a7d8490ef25f 100644 --- a/src/test/ui/consts/const-eval/const_transmute.rs +++ b/src/test/ui/consts/const-eval/const_transmute.rs @@ -2,6 +2,7 @@ #![feature(const_fn_union)] +#[repr(C)] union Transmute { t: T, u: U, diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs new file mode 100644 index 0000000000000..b5d72d46f2861 --- /dev/null +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -0,0 +1,13 @@ +#![feature(const_transmute, const_raw_ptr_deref)] + +use std::{mem, usize}; + +// Make sure we error with the right kind of error on a too large slice. +const TEST: () = { unsafe { //~ NOTE + let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); + let _val = &*slice; //~ ERROR: any use of this value will cause an error + //~^ NOTE: total size is bigger than largest supported object + //~^^ on by default +} }; + +fn main() {} diff --git a/src/test/ui/consts/const-eval/dangling.stderr b/src/test/ui/consts/const-eval/dangling.stderr new file mode 100644 index 0000000000000..286de08009754 --- /dev/null +++ b/src/test/ui/consts/const-eval/dangling.stderr @@ -0,0 +1,16 @@ +error: any use of this value will cause an error + --> $DIR/dangling.rs:8:16 + | +LL | / const TEST: () = { unsafe { +LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); +LL | | let _val = &*slice; + | | ^^^^^^^ invalid slice: total size is bigger than largest supported object +LL | | +LL | | +LL | | } }; + | |____- + | + = note: `#[deny(const_err)]` on by default + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-eval/double_check.rs b/src/test/ui/consts/const-eval/double_check.rs index 2cf6a5494dd8d..ff2fff7fb790e 100644 --- a/src/test/ui/consts/const-eval/double_check.rs +++ b/src/test/ui/consts/const-eval/double_check.rs @@ -8,6 +8,7 @@ enum Bar { C = 42, D = 99, } +#[repr(C)] union Union { foo: &'static Foo, bar: &'static Bar, diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index dc2b58faf9215..7c222b113cd7d 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -6,6 +6,7 @@ enum Bar { C = 42, D = 99, } +#[repr(C)] union Union { foo: &'static Foo, bar: &'static Bar, diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 2b61d33852c98..9c56f1995208f 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:15:1 + --> $DIR/double_check2.rs:16:1 | LL | / static FOO: (&Foo, &Bar) = unsafe {( LL | | Union { u8: &BAR }.foo, diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs index b0ae746ace58d..3f7bab065869a 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.rs @@ -2,6 +2,7 @@ fn main() {} +#[repr(C)] union Foo { u: u32, i: i32, diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr index 5bf43cb8b6add..6899b7b82c532 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr @@ -1,5 +1,5 @@ error[E0658]: unions in const fn are unstable - --> $DIR/feature-gate-const_fn_union.rs:11:5 + --> $DIR/feature-gate-const_fn_union.rs:12:5 | LL | Foo { u }.i | ^^^^^^^^^^^ diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index 478e453fe0834..d971d825f278c 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -21,16 +21,16 @@ LL | const Y: u32 = foo(0-1); | attempt to subtract with overflow error[E0080]: evaluation of constant expression failed - --> $DIR/issue-43197.rs:12:26 + --> $DIR/issue-43197.rs:12:23 | LL | println!("{} {}", X, Y); - | ^ referenced constant has errors + | ^ referenced constant has errors error[E0080]: evaluation of constant expression failed - --> $DIR/issue-43197.rs:12:23 + --> $DIR/issue-43197.rs:12:26 | LL | println!("{} {}", X, Y); - | ^ referenced constant has errors + | ^ referenced constant has errors error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/issue-49296.rs b/src/test/ui/consts/const-eval/issue-49296.rs index a7c3c5318d430..c6caeeffd22dd 100644 --- a/src/test/ui/consts/const-eval/issue-49296.rs +++ b/src/test/ui/consts/const-eval/issue-49296.rs @@ -4,6 +4,7 @@ #![feature(const_fn_union)] const unsafe fn transmute(t: T) -> U { + #[repr(C)] union Transmute { from: T, to: U, diff --git a/src/test/ui/consts/const-eval/issue-49296.stderr b/src/test/ui/consts/const-eval/issue-49296.stderr index 7a4bba8daa70b..48809e0ae649c 100644 --- a/src/test/ui/consts/const-eval/issue-49296.stderr +++ b/src/test/ui/consts/const-eval/issue-49296.stderr @@ -1,5 +1,5 @@ error: any use of this value will cause an error - --> $DIR/issue-49296.rs:18:16 + --> $DIR/issue-49296.rs:19:16 | LL | const X: u64 = *wat(42); | ---------------^^^^^^^^- diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs index 88181cb86100f..3edd4e086867b 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.rs @@ -2,6 +2,7 @@ #![allow(const_err)] +#[repr(C)] union Bar { a: &'static u8, b: usize, diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr index 519ba7d84b087..6618f1cd1c0b5 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail.rs:20:27 + --> $DIR/promoted_const_fn_fail.rs:21:27 | LL | let x: &'static u8 = &(bar() + 1); | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs index 061ab7eeb029d..7887e42653464 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.rs @@ -2,6 +2,7 @@ #![deny(const_err)] +#[repr(C)] union Bar { a: &'static u8, b: usize, diff --git a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr index 987d2304ae871..5f9f3bda87b15 100644 --- a/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr +++ b/src/test/ui/consts/const-eval/promoted_const_fn_fail_deny_const_err.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/promoted_const_fn_fail_deny_const_err.rs:21:27 + --> $DIR/promoted_const_fn_fail_deny_const_err.rs:22:27 | LL | let x: &'static u8 = &(bar() + 1); | ----------- ^^^^^^^^^^^ creates a temporary which is freed while still in use diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index fa8859cbb3bb6..cd989731452b3 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -7,15 +7,13 @@ fn main() { let _x = 0u32 - 1; //~^ ERROR this expression will panic at runtime [const_err] println!("{}", 1/(1-1)); - //~^ ERROR this expression will panic at runtime [const_err] - //~| ERROR attempt to divide by zero [const_err] + //~^ ERROR attempt to divide by zero [const_err] //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(1-1); //~^ ERROR const_err //~| ERROR const_err println!("{}", 1/(false as u32)); - //~^ ERROR this expression will panic at runtime [const_err] - //~| ERROR attempt to divide by zero [const_err] + //~^ ERROR attempt to divide by zero [const_err] //~| ERROR reaching this expression at runtime will panic or abort [const_err] let _x = 1/(false as u32); //~^ ERROR const_err diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index 12407accf096f..40d5c73e86679 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -16,59 +16,47 @@ error: attempt to divide by zero LL | println!("{}", 1/(1-1)); | ^^^^^^^ -error: this expression will panic at runtime +error: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:9:20 | LL | println!("{}", 1/(1-1)); | ^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:13:14 + --> $DIR/promoted_errors.rs:12:14 | LL | let _x = 1/(1-1); | ^^^^^^^ error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:13:14 + --> $DIR/promoted_errors.rs:12:14 | LL | let _x = 1/(1-1); | ^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:16:20 + --> $DIR/promoted_errors.rs:15:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ -error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:16:20 +error: reaching this expression at runtime will panic or abort + --> $DIR/promoted_errors.rs:15:20 | LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ attempt to divide by zero error: attempt to divide by zero - --> $DIR/promoted_errors.rs:20:14 + --> $DIR/promoted_errors.rs:18:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ error: this expression will panic at runtime - --> $DIR/promoted_errors.rs:20:14 + --> $DIR/promoted_errors.rs:18:14 | LL | let _x = 1/(false as u32); | ^^^^^^^^^^^^^^^^ attempt to divide by zero -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1/(false as u32)); - | ^^^^^^^^^^^^^^^^ attempt to divide by zero - -error: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:9:20 - | -LL | println!("{}", 1/(1-1)); - | ^^^^^^^ attempt to divide by zero - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.rs b/src/test/ui/consts/const-eval/ref_to_int_match.rs index b6a2ed1f9bcf4..45ce040fb9eef 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.rs +++ b/src/test/ui/consts/const-eval/ref_to_int_match.rs @@ -9,6 +9,7 @@ fn main() { } } +#[repr(C)] union Foo { f: Int, r: &'static u32, diff --git a/src/test/ui/consts/const-eval/ref_to_int_match.stderr b/src/test/ui/consts/const-eval/ref_to_int_match.stderr index f8eafed68e43d..0be82e3434142 100644 --- a/src/test/ui/consts/const-eval/ref_to_int_match.stderr +++ b/src/test/ui/consts/const-eval/ref_to_int_match.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ref_to_int_match.rs:23:1 + --> $DIR/ref_to_int_match.rs:24:1 | LL | const BAR: Int = unsafe { Foo { r: &42 }.f }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index d4b2220695102..483285aa4e123 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -10,6 +10,7 @@ struct Wrap(T); enum Enum { A = 0, } +#[repr(C)] union TransmuteEnum { in1: &'static u8, in2: usize, @@ -35,6 +36,7 @@ enum Enum2 { A = 2, } +#[repr(C)] union TransmuteEnum2 { in1: usize, in2: &'static u8, @@ -60,6 +62,7 @@ const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }. // Invalid enum field content (mostly to test printing of paths for enum tuple // variants and tuples). +#[repr(C)] union TransmuteChar { a: u32, b: char, diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 8ecb1aabdd0f7..30dd86592d469 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:22:1 + --> $DIR/ub-enum.rs:23:1 | LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant @@ -7,7 +7,7 @@ LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:25:1 + --> $DIR/ub-enum.rs:26:1 | LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -15,7 +15,7 @@ LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:28:1 + --> $DIR/ub-enum.rs:29:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0 @@ -23,7 +23,7 @@ LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { TransmuteEnum { in1: &1 }.out = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:46:1 + --> $DIR/ub-enum.rs:48:1 | LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant @@ -31,7 +31,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:48:1 + --> $DIR/ub-enum.rs:50:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -39,7 +39,7 @@ LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:50:1 + --> $DIR/ub-enum.rs:52:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }.out2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2 @@ -47,7 +47,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { TransmuteEnum2 { in2: &0 }. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:54:1 + --> $DIR/ub-enum.rs:56:1 | LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant @@ -55,7 +55,7 @@ LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:58:1 + --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: &0 }.out3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant @@ -63,7 +63,7 @@ LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { TransmuteEnum2 { in2: = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-enum.rs:68:1 + --> $DIR/ub-enum.rs:71:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at ..0.1, but expected something less or equal to 1114111 diff --git a/src/test/ui/consts/const-eval/ub-nonnull.rs b/src/test/ui/consts/const-eval/ub-nonnull.rs index 9edae1965ce16..8ce64ced7dff4 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.rs +++ b/src/test/ui/consts/const-eval/ub-nonnull.rs @@ -24,6 +24,7 @@ const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +#[repr(C)] union Transmute { uninit: (), out: NonZeroU8, diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 7b3c97e5fbf96..de20c3d0b8cfe 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -41,7 +41,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:31:1 + --> $DIR/ub-nonnull.rs:32:1 | LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1 @@ -49,7 +49,7 @@ LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:39:1 + --> $DIR/ub-nonnull.rs:40:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30 @@ -57,7 +57,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-nonnull.rs:45:1 + --> $DIR/ub-nonnull.rs:46:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30 diff --git a/src/test/ui/consts/const-eval/ub-ref.rs b/src/test/ui/consts/const-eval/ub-ref.rs index bbab85c2121a5..03ac12c8b1ac1 100644 --- a/src/test/ui/consts/const-eval/ub-ref.rs +++ b/src/test/ui/consts/const-eval/ub-ref.rs @@ -11,6 +11,9 @@ const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; const NULL: &u16 = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value +// It is very important that we reject this: We do promote `&(4 * REF_AS_USIZE)`, +// but that would fail to compile; so we ended up breaking user code that would +// have worked fine had we not promoted. const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; //~^ ERROR it is undefined behavior to use this value diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index f1702955ed7b1..cd3cc38467c36 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -15,7 +15,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:14:1 + --> $DIR/ub-ref.rs:17:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain (non-pointer) bytes @@ -23,7 +23,7 @@ LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:17:1 + --> $DIR/ub-ref.rs:20:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain (non-pointer) bytes @@ -31,7 +31,7 @@ LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-ref.rs:20:1 + --> $DIR/ub-ref.rs:23:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (created from integer) diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.rs b/src/test/ui/consts/const-eval/ub-uninhabit.rs index 42cba02f579b7..d2745d71bdb2f 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.rs +++ b/src/test/ui/consts/const-eval/ub-uninhabit.rs @@ -6,6 +6,7 @@ use std::mem; #[derive(Copy, Clone)] enum Bar {} +#[repr(C)] union TransmuteUnion { a: A, b: B, diff --git a/src/test/ui/consts/const-eval/ub-uninhabit.stderr b/src/test/ui/consts/const-eval/ub-uninhabit.stderr index c8842ecc23ca2..43d91483797bf 100644 --- a/src/test/ui/consts/const-eval/ub-uninhabit.stderr +++ b/src/test/ui/consts/const-eval/ub-uninhabit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:14:1 + --> $DIR/ub-uninhabit.rs:15:1 | LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type @@ -7,7 +7,7 @@ LL | const BAD_BAD_BAD: Bar = unsafe { (TransmuteUnion::<(), Bar> { a: () }).b } = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:17:1 + --> $DIR/ub-uninhabit.rs:18:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at . @@ -15,7 +15,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-uninhabit.rs:20:1 + --> $DIR/ub-uninhabit.rs:21:1 | LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { (TransmuteUnion::<(), [Bar; 1]> { a: () }).b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs new file mode 100644 index 0000000000000..1f810c40572c0 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -0,0 +1,159 @@ +// ignore-tidy-linelength +#![allow(unused)] +#![allow(const_err)] // make sure we cannot allow away the errors tested here + +// normalize-stderr-test "alignment \d+" -> "alignment N" +// normalize-stderr-test "offset \d+" -> "offset N" +// normalize-stderr-test "allocation \d+" -> "allocation N" +// normalize-stderr-test "size \d+" -> "size N" + +#[repr(C)] +union BoolTransmute { + val: u8, + bl: bool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadSliceRepr { + ptr: *const u8, + len: &'static u8, +} + +#[repr(C)] +union SliceTransmute { + repr: SliceRepr, + bad: BadSliceRepr, + addr: usize, + slice: &'static [u8], + raw_slice: *const [u8], + str: &'static str, + my_str: &'static MyStr, + my_slice: &'static MySliceBool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr { + ptr: *const u8, + vtable: *const u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr2 { + ptr: *const u8, + vtable: *const u64, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadDynRepr { + ptr: *const u8, + vtable: usize, +} + +#[repr(C)] +union DynTransmute { + repr: DynRepr, + repr2: DynRepr2, + bad: BadDynRepr, + addr: usize, + rust: &'static dyn Trait, + raw_rust: *const dyn Trait, +} + +trait Trait {} +impl Trait for bool {} + +// custom unsized type +struct MyStr(str); + +// custom unsized type with sized fields +struct MySlice(bool, T); +type MySliceBool = MySlice<[bool]>; + +// # str +// OK +const STR_VALID: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; +// bad str +const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; +//~^ ERROR it is undefined behavior to use this value +// bad str +const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; +//~^ ERROR it is undefined behavior to use this value +// bad str in user-defined unsized type +const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; +//~^ ERROR it is undefined behavior to use this value + +// invalid UTF-8 +const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; +//~^ ERROR it is undefined behavior to use this value +// invalid UTF-8 in user-defined str-like +const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; +//~^ ERROR it is undefined behavior to use this value + +// # slice +// OK +const SLICE_VALID: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; +// bad slice: length uninit +const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length too big +const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; +//~^ ERROR it is undefined behavior to use this value +// bad slice: length not an int +const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; +//~^ ERROR it is undefined behavior to use this value + +// bad data *inside* the slice +const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; +//~^ ERROR it is undefined behavior to use this value + +// good MySliceBool +const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]); +// bad: sized field is not okay +const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); +//~^ ERROR it is undefined behavior to use this value +// bad: unsized part is not okay +const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); +//~^ ERROR it is undefined behavior to use this value + +// # raw slice +const RAW_SLICE_VALID: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.raw_slice}; // ok +const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.raw_slice}; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: usize::max_value() } }.raw_slice}; // ok because raw +const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; +//~^ ERROR it is undefined behavior to use this value + +// # trait object +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +// bad trait object +const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +// bad trait object +const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +//~^ ERROR it is undefined behavior to use this value + +// bad data *inside* the trait object +const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; +//~^ ERROR it is undefined behavior to use this value + +// # raw trait object +const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust}; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; +//~^ ERROR it is undefined behavior to use this value +const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw + +fn main() { +} diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr new file mode 100644 index 0000000000000..aadabc323fbd4 --- /dev/null +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -0,0 +1,147 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:87:1 + | +LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:90:1 + | +LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:93:1 + | +LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:97:1 + | +LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:100:1 + | +LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:107:1 + | +LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:110:1 + | +LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:113:1 + | +LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:117:1 + | +LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:123:1 + | +LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:126:1 + | +LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:133:1 + | +LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:138:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:141:1 + | +LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:144:1 + | +LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:148:1 + | +LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:152:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:154:1 + | +LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.rs b/src/test/ui/consts/const-eval/union-const-eval-field.rs index 56f3ef3db25d1..7f29a5bc24e4e 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.rs +++ b/src/test/ui/consts/const-eval/union-const-eval-field.rs @@ -4,6 +4,7 @@ type Field1 = i32; type Field2 = f32; type Field3 = i64; +#[repr(C)] union DummyUnion { field1: Field1, field2: Field2, diff --git a/src/test/ui/consts/const-eval/union-const-eval-field.stderr b/src/test/ui/consts/const-eval/union-const-eval-field.stderr index 4a53337341e67..4d008a0e02ad7 100644 --- a/src/test/ui/consts/const-eval/union-const-eval-field.stderr +++ b/src/test/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-const-eval-field.rs:27:5 + --> $DIR/union-const-eval-field.rs:28:5 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes diff --git a/src/test/ui/consts/const-eval/union-ice.rs b/src/test/ui/consts/const-eval/union-ice.rs index 33736b360d33a..5a14c7fd99345 100644 --- a/src/test/ui/consts/const-eval/union-ice.rs +++ b/src/test/ui/consts/const-eval/union-ice.rs @@ -3,6 +3,7 @@ type Field1 = i32; type Field3 = i64; +#[repr(C)] union DummyUnion { field1: Field1, field3: Field3, diff --git a/src/test/ui/consts/const-eval/union-ice.stderr b/src/test/ui/consts/const-eval/union-ice.stderr index b25cb8c5aa021..8d950e86d27fc 100644 --- a/src/test/ui/consts/const-eval/union-ice.stderr +++ b/src/test/ui/consts/const-eval/union-ice.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:13:1 + --> $DIR/union-ice.rs:14:1 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes @@ -7,7 +7,7 @@ LL | const FIELD3: Field3 = unsafe { UNION.field3 }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:15:1 + --> $DIR/union-ice.rs:16:1 | LL | / const FIELD_PATH: Struct = Struct { LL | | a: 42, @@ -18,7 +18,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ice.rs:25:1 + --> $DIR/union-ice.rs:26:1 | LL | / const FIELD_PATH2: Struct2 = Struct2 { LL | | b: [ diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs b/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs deleted file mode 100644 index d5405f3441fec..0000000000000 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.rs +++ /dev/null @@ -1,131 +0,0 @@ -#![allow(unused)] -#![allow(const_err)] // make sure we cannot allow away the errors tested here - -// normalize-stderr-test "alignment \d+" -> "alignment N" -// normalize-stderr-test "offset \d+" -> "offset N" -// normalize-stderr-test "allocation \d+" -> "allocation N" -// normalize-stderr-test "size \d+" -> "size N" - -union BoolTransmute { - val: u8, - bl: bool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct SliceRepr { - ptr: *const u8, - len: usize, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadSliceRepr { - ptr: *const u8, - len: &'static u8, -} - -union SliceTransmute { - repr: SliceRepr, - bad: BadSliceRepr, - slice: &'static [u8], - str: &'static str, - my_str: &'static MyStr, - my_slice: &'static MySliceBool, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr { - ptr: *const u8, - vtable: *const u8, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct DynRepr2 { - ptr: *const u8, - vtable: *const u64, -} - -#[repr(C)] -#[derive(Copy, Clone)] -struct BadDynRepr { - ptr: *const u8, - vtable: usize, -} - -union DynTransmute { - repr: DynRepr, - repr2: DynRepr2, - bad: BadDynRepr, - rust: &'static dyn Trait, -} - -trait Trait {} -impl Trait for bool {} - -// custom unsized type -struct MyStr(str); - -// custom unsized type with sized fields -struct MySlice(bool, T); -type MySliceBool = MySlice<[bool]>; - -// OK -const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; -// bad str -const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; -//~^ ERROR it is undefined behavior to use this value -// bad str -const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; -//~^ ERROR it is undefined behavior to use this value -// bad str in user-defined unsized type -const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; -//~^ ERROR it is undefined behavior to use this value - -// OK -const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; -// bad slice -const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; -//~^ ERROR it is undefined behavior to use this value -// bad slice -const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; -//~^ ERROR it is undefined behavior to use this value - -// bad trait object -const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value -// bad trait object -const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value -// bad trait object -const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; -//~^ ERROR it is undefined behavior to use this value - -// bad data *inside* the trait object -const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; -//~^ ERROR it is undefined behavior to use this value - -// bad data *inside* the slice -const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; -//~^ ERROR it is undefined behavior to use this value - -// good MySliceBool -const I1: &MySliceBool = &MySlice(true, [false]); -// bad: sized field is not okay -const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); -//~^ ERROR it is undefined behavior to use this value -// bad: unsized part is not okay -const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); -//~^ ERROR it is undefined behavior to use this value - -// invalid UTF-8 -const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; -//~^ ERROR it is undefined behavior to use this value -// invalid UTF-8 in user-defined str-like -const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; -//~^ ERROR it is undefined behavior to use this value - -fn main() { -} diff --git a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr b/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr deleted file mode 100644 index aac32ecc5b747..0000000000000 --- a/src/test/ui/consts/const-eval/union-ub-fat-ptr.stderr +++ /dev/null @@ -1,115 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:78:1 - | -LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:81:1 - | -LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:84:1 - | -LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:90:1 - | -LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds) - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:93:1 - | -LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:97:1 - | -LL | const D: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:100:1 - | -LL | const E: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:103:1 - | -LL | const F: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer or too small vtable - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:107:1 - | -LL | const G: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:111:1 - | -LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:117:1 - | -LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:120:1 - | -LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected something less or equal to 1 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:124:1 - | -LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub-fat-ptr.rs:127:1 - | -LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error: aborting due to 14 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/union-ub.rs b/src/test/ui/consts/const-eval/union-ub.rs index cf436141c5a02..848826e6ef7f2 100644 --- a/src/test/ui/consts/const-eval/union-ub.rs +++ b/src/test/ui/consts/const-eval/union-ub.rs @@ -1,5 +1,6 @@ #![allow(const_err)] // make sure we cannot allow away the errors tested here +#[repr(C)] union DummyUnion { u8: u8, bool: bool, @@ -14,11 +15,13 @@ enum Enum { } #[derive(Copy, Clone)] +#[repr(C)] union Foo { a: bool, b: Enum, } +#[repr(C)] union Bar { foo: Foo, u8: u8, diff --git a/src/test/ui/consts/const-eval/union-ub.stderr b/src/test/ui/consts/const-eval/union-ub.stderr index 7baa55be6e11e..6a3a397585c89 100644 --- a/src/test/ui/consts/const-eval/union-ub.stderr +++ b/src/test/ui/consts/const-eval/union-ub.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/union-ub.rs:28:1 + --> $DIR/union-ub.rs:31:1 | LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something less or equal to 1 diff --git a/src/test/ui/consts/const-eval/union_promotion.rs b/src/test/ui/consts/const-eval/union_promotion.rs index d3566511ef8ee..7167f88a1185b 100644 --- a/src/test/ui/consts/const-eval/union_promotion.rs +++ b/src/test/ui/consts/const-eval/union_promotion.rs @@ -1,5 +1,6 @@ #![allow(const_err)] +#[repr(C)] union Foo { a: &'static u32, b: usize, diff --git a/src/test/ui/consts/const-eval/union_promotion.stderr b/src/test/ui/consts/const-eval/union_promotion.stderr index b530c02f2fb93..ed186e3ebd2f5 100644 --- a/src/test/ui/consts/const-eval/union_promotion.stderr +++ b/src/test/ui/consts/const-eval/union_promotion.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/union_promotion.rs:9:29 + --> $DIR/union_promotion.rs:10:29 | LL | let x: &'static bool = &unsafe { | ____________-------------____^ diff --git a/src/test/ui/consts/const-eval/valid-const.rs b/src/test/ui/consts/const-eval/valid-const.rs index 30bd47219239e..65c642d750b51 100644 --- a/src/test/ui/consts/const-eval/valid-const.rs +++ b/src/test/ui/consts/const-eval/valid-const.rs @@ -1,7 +1,8 @@ -// build-pass (FIXME(62277): could be check-pass?) +// check-pass // Some constants that *are* valid #![feature(const_transmute)] +#![deny(const_err)] use std::mem; use std::ptr::NonNull; diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index 113ec29239616..fdba359e7464a 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -4,6 +4,11 @@ error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{con LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... + --> $DIR/const-size_of-cycle.rs:6:17 + | +LL | bytes: [u8; std::mem::size_of::()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... --> $SRC_DIR/libcore/mem/mod.rs:LL:COL | @@ -11,11 +16,6 @@ LL | intrinsics::size_of::() | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`... -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... - --> $DIR/const-size_of-cycle.rs:6:17 - | -LL | bytes: [u8; std::mem::size_of::()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when processing `Foo` --> $DIR/const-size_of-cycle.rs:5:1 diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index eef79421270ce..0733a51233e33 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -14,32 +14,28 @@ LL | [5; Self::HOST_SIZE] == [6; 0] error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/too_generic_eval_ice.rs:7:13 | +LL | pub struct Foo(A, B); + | --------------------------- required by `Foo` +... LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = help: consider adding a `where A: std::marker::Sized` bound -note: required by `Foo` - --> $DIR/too_generic_eval_ice.rs:1:1 - | -LL | pub struct Foo(A, B); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `B` cannot be known at compilation time --> $DIR/too_generic_eval_ice.rs:7:13 | +LL | pub struct Foo(A, B); + | --------------------------- required by `Foo` +... LL | [5; Self::HOST_SIZE] == [6; 0] | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `B` = note: to learn more, visit = help: consider adding a `where B: std::marker::Sized` bound -note: required by `Foo` - --> $DIR/too_generic_eval_ice.rs:1:1 - | -LL | pub struct Foo(A, B); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/defaulted-never-note.stderr b/src/test/ui/defaulted-never-note.stderr index 45174c322947d..277477a0b0acd 100644 --- a/src/test/ui/defaulted-never-note.stderr +++ b/src/test/ui/defaulted-never-note.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied --> $DIR/defaulted-never-note.rs:26:5 | +LL | fn foo(_t: T) {} + | ----------------------------------------------- required by `foo` +... LL | foo(_x); | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` | = note: the trait is implemented for `()`. Possibly this error has been caused by changes to Rust's type-inference algorithm (see: https://github.com/rust-lang/rust/issues/48950 for more info). Consider whether you meant to use the type `()` here instead. -note: required by `foo` - --> $DIR/defaulted-never-note.rs:21:1 - | -LL | fn foo(_t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/derive-uninhabited-enum-38885.rs b/src/test/ui/derive-uninhabited-enum-38885.rs index 2c4d64e4e6063..010464adf5bce 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.rs +++ b/src/test/ui/derive-uninhabited-enum-38885.rs @@ -5,12 +5,15 @@ // when deriving Debug on an empty enum #[derive(Debug)] -enum Void {} //~ WARN never used +enum Void {} #[derive(Debug)] -enum Foo { //~ WARN never used +enum Foo { Bar(u8), - Void(Void), + Void(Void), //~ WARN never used } -fn main() {} +fn main() { + let x = Foo::Bar(42); + println!("{:?}", x); +} diff --git a/src/test/ui/derive-uninhabited-enum-38885.stderr b/src/test/ui/derive-uninhabited-enum-38885.stderr index 941c98b5506b2..a3ed6798a7039 100644 --- a/src/test/ui/derive-uninhabited-enum-38885.stderr +++ b/src/test/ui/derive-uninhabited-enum-38885.stderr @@ -1,14 +1,8 @@ -warning: enum is never used: `Void` - --> $DIR/derive-uninhabited-enum-38885.rs:8:1 +warning: variant is never constructed: `Void` + --> $DIR/derive-uninhabited-enum-38885.rs:13:5 | -LL | enum Void {} - | ^^^^^^^^^ +LL | Void(Void), + | ^^^^^^^^^^ | = note: `-W dead-code` implied by `-W unused` -warning: enum is never used: `Foo` - --> $DIR/derive-uninhabited-enum-38885.rs:11:1 - | -LL | enum Foo { - | ^^^^^^^^ - diff --git a/src/test/ui/derives/deriving-bounds.stderr b/src/test/ui/derives/deriving-bounds.stderr index 99976da72da1d..b18df3511817d 100644 --- a/src/test/ui/derives/deriving-bounds.stderr +++ b/src/test/ui/derives/deriving-bounds.stderr @@ -1,15 +1,3 @@ -error: cannot find derive macro `Send` in this scope - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - | -note: unsafe traits like `Send` should be implemented explicitly - --> $DIR/deriving-bounds.rs:1:10 - | -LL | #[derive(Send)] - | ^^^^ - error: cannot find derive macro `Sync` in this scope --> $DIR/deriving-bounds.rs:5:10 | @@ -22,5 +10,17 @@ note: unsafe traits like `Sync` should be implemented explicitly LL | #[derive(Sync)] | ^^^^ +error: cannot find derive macro `Send` in this scope + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + | +note: unsafe traits like `Send` should be implemented explicitly + --> $DIR/deriving-bounds.rs:1:10 + | +LL | #[derive(Send)] + | ^^^^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index e6060c269e10a..46b6a0d337695 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,41 +1,35 @@ error[E0277]: the trait bound `C: std::marker::Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:5 | +LL | fn is_copy(_: T) {} + | ------------------------- required by `is_copy` +... LL | is_copy(B { a: 1, b: C }); | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `C` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` -note: required by `is_copy` - --> $DIR/deriving-copyclone.rs:18:1 - | -LL | fn is_copy(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:5 | +LL | fn is_clone(_: T) {} + | --------------------------- required by `is_clone` +... LL | is_clone(B { a: 1, b: C }); | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `C` | = note: required because of the requirements on the impl of `std::clone::Clone` for `B` -note: required by `is_clone` - --> $DIR/deriving-copyclone.rs:19:1 - | -LL | fn is_clone(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `D: std::marker::Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:5 | +LL | fn is_copy(_: T) {} + | ------------------------- required by `is_copy` +... LL | is_copy(B { a: 1, b: D }); | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `D` | = note: required because of the requirements on the impl of `std::marker::Copy` for `B` -note: required by `is_copy` - --> $DIR/deriving-copyclone.rs:18:1 - | -LL | fn is_copy(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr index cfb1da037dc07..ea2017f485a7b 100644 --- a/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr +++ b/src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `i8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:24:5 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&1i8); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i8` | @@ -10,15 +13,13 @@ LL | Foo::::bar(&1i8); > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error[E0277]: the trait bound `u8: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:25:5 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&1u8); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `u8` | @@ -27,15 +28,13 @@ LL | Foo::::bar(&1u8); > > > -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error[E0277]: the trait bound `bool: Foo` is not satisfied --> $DIR/issue-39802-show-5-trait-impls.rs:26:5 | +LL | fn bar(&self){} + | ------------- required by `Foo::bar` +... LL | Foo::::bar(&true); | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `bool` | @@ -45,11 +44,6 @@ LL | Foo::::bar(&true); > > and 2 others -note: required by `Foo::bar` - --> $DIR/issue-39802-show-5-trait-impls.rs:2:5 - | -LL | fn bar(&self){} - | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.rs b/src/test/ui/did_you_mean/multiple-pattern-typo.rs deleted file mode 100644 index 14ad33d53b08c..0000000000000 --- a/src/test/ui/did_you_mean/multiple-pattern-typo.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x = 3; - match x { - 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern - _ => (), - } -} diff --git a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr b/src/test/ui/did_you_mean/multiple-pattern-typo.stderr deleted file mode 100644 index a29fa584b2924..0000000000000 --- a/src/test/ui/did_you_mean/multiple-pattern-typo.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: unexpected token `||` after pattern - --> $DIR/multiple-pattern-typo.rs:4:15 - | -LL | 1 | 2 || 3 => (), - | ^^ help: use a single `|` to specify multiple patterns: `|` - -error: aborting due to previous error - diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index a646d98324e09..745d90a5d4cbf 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,6 +1,9 @@ error[E0275]: overflow evaluating the requirement `J: std::marker::Send` --> $DIR/recursion_limit.rs:34:5 | +LL | fn is_send() { } + | -------------------- required by `is_send` +... LL | is_send::(); | ^^^^^^^^^^^^ | @@ -14,11 +17,6 @@ LL | is_send::(); = note: required because it appears within the type `C` = note: required because it appears within the type `B` = note: required because it appears within the type `A` -note: required by `is_send` - --> $DIR/recursion_limit.rs:31:1 - | -LL | fn is_send() { } - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0267.stderr b/src/test/ui/error-codes/E0267.stderr index b14cfd1a52d47..1f8657373efec 100644 --- a/src/test/ui/error-codes/E0267.stderr +++ b/src/test/ui/error-codes/E0267.stderr @@ -2,7 +2,9 @@ error[E0267]: `break` inside of a closure --> $DIR/E0267.rs:2:18 | LL | let w = || { break; }; - | ^^^^^ cannot break inside of a closure + | -- ^^^^^ cannot `break` inside of a closure + | | + | enclosing closure error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0268.stderr b/src/test/ui/error-codes/E0268.stderr index 3c77e7f3df2be..c926f9e487494 100644 --- a/src/test/ui/error-codes/E0268.stderr +++ b/src/test/ui/error-codes/E0268.stderr @@ -1,8 +1,8 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/E0268.rs:2:5 | LL | break; - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0271.stderr b/src/test/ui/error-codes/E0271.stderr index 16c3ab9d7425b..0afcbcc79eee9 100644 --- a/src/test/ui/error-codes/E0271.stderr +++ b/src/test/ui/error-codes/E0271.stderr @@ -1,16 +1,14 @@ error[E0271]: type mismatch resolving `::AssociatedType == u32` --> $DIR/E0271.rs:10:5 | +LL | fn foo(t: T) where T: Trait { + | -------------------------------------------------- required by `foo` +... LL | foo(3_i8); | ^^^ expected reference, found u32 | = note: expected type `&'static str` found type `u32` -note: required by `foo` - --> $DIR/E0271.rs:3:1 - | -LL | fn foo(t: T) where T: Trait { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 40991cb2297c9..f607a9fbbf269 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -1,6 +1,9 @@ error[E0275]: overflow evaluating the requirement `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/E0275.rs:5:1 | +LL | trait Foo {} + | --------- required by `Foo` +... LL | impl Foo for T where Bar: Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -132,11 +135,6 @@ LL | impl Foo for T where Bar: Foo {} = note: required because of the requirements on the impl of `Foo` for `Bar>>` = note: required because of the requirements on the impl of `Foo` for `Bar>` = note: required because of the requirements on the impl of `Foo` for `Bar` -note: required by `Foo` - --> $DIR/E0275.rs:1:1 - | -LL | trait Foo {} - | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index a4db1c8b09523..b42849cd84201 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -1,6 +1,9 @@ error[E0277]: `*const u8` cannot be sent between threads safely --> $DIR/E0277-2.rs:16:5 | +LL | fn is_send() { } + | --------------------- required by `is_send` +... LL | is_send::(); | ^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely | @@ -8,11 +11,6 @@ LL | is_send::(); = note: required because it appears within the type `Baz` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Foo` -note: required by `is_send` - --> $DIR/E0277-2.rs:13:1 - | -LL | fn is_send() { } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index e5e416da883de..352102dd38629 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -13,14 +13,11 @@ LL | fn f(p: Path) { } error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/E0277.rs:17:5 | +LL | fn some_func(foo: T) { + | ---------------------------- required by `some_func` +... LL | some_func(5i32); | ^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `some_func` - --> $DIR/E0277.rs:9:1 - | -LL | fn some_func(foo: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0283.stderr b/src/test/ui/error-codes/E0283.stderr index e1f53e592fc85..1d99f99c62383 100644 --- a/src/test/ui/error-codes/E0283.stderr +++ b/src/test/ui/error-codes/E0283.stderr @@ -1,14 +1,11 @@ error[E0283]: type annotations required: cannot resolve `_: Generator` --> $DIR/E0283.rs:18:21 | +LL | fn create() -> u32; + | ------------------- required by `Generator::create` +... LL | let cont: u32 = Generator::create(); | ^^^^^^^^^^^^^^^^^ - | -note: required by `Generator::create` - --> $DIR/E0283.rs:2:5 - | -LL | fn create() -> u32; - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-should-say-copy-not-pod.stderr b/src/test/ui/error-should-say-copy-not-pod.stderr index 7143f8c914dd0..78d54c3836db4 100644 --- a/src/test/ui/error-should-say-copy-not-pod.stderr +++ b/src/test/ui/error-should-say-copy-not-pod.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/error-should-say-copy-not-pod.rs:6:5 | +LL | fn check_bound(_: T) {} + | ---------------------------- required by `check_bound` +... LL | check_bound("nocopy".to_string()); | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `check_bound` - --> $DIR/error-should-say-copy-not-pod.rs:3:1 - | -LL | fn check_bound(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/extern/extern-types-not-sync-send.stderr b/src/test/ui/extern/extern-types-not-sync-send.stderr index bc9d96df776ed..0f32d4489dece 100644 --- a/src/test/ui/extern/extern-types-not-sync-send.stderr +++ b/src/test/ui/extern/extern-types-not-sync-send.stderr @@ -1,28 +1,24 @@ error[E0277]: `A` cannot be shared between threads safely --> $DIR/extern-types-not-sync-send.rs:13:5 | +LL | fn assert_sync() { } + | ---------------------------------- required by `assert_sync` +... LL | assert_sync::(); | ^^^^^^^^^^^^^^^^ `A` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `A` -note: required by `assert_sync` - --> $DIR/extern-types-not-sync-send.rs:9:1 - | -LL | fn assert_sync() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `A` cannot be sent between threads safely --> $DIR/extern-types-not-sync-send.rs:16:5 | +LL | fn assert_send() { } + | ---------------------------------- required by `assert_send` +... LL | assert_send::(); | ^^^^^^^^^^^^^^^^ `A` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `A` -note: required by `assert_send` - --> $DIR/extern-types-not-sync-send.rs:10:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 4e4f5550fe833..06527d973e2ab 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -1,50 +1,47 @@ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:22:5 | +LL | fn assert_sized() { } + | -------------------- required by `assert_sized` +... LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:25:5 | +LL | fn assert_sized() { } + | -------------------- required by `assert_sized` +... LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Foo` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:28:5 | +LL | fn assert_sized() { } + | -------------------- required by `assert_sized` +... LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit = note: required because it appears within the type `Bar` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:31:5 | +LL | fn assert_sized() { } + | -------------------- required by `assert_sized` +... LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | @@ -52,11 +49,6 @@ LL | assert_sized::>>(); = note: to learn more, visit = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` -note: required by `assert_sized` - --> $DIR/extern-types-unsized.rs:19:1 - | -LL | fn assert_sized() { } - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index dce33f3d6323d..52fcb90e6de0c 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -1,16 +1,14 @@ error[E0277]: expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` --> $DIR/extern-wrong-value-type.rs:9:5 | +LL | fn is_fn(_: F) where F: Fn() {} + | ------------------------------- required by `is_fn` +... LL | is_fn(f); | ^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` | = help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}` = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ } -note: required by `is_fn` - --> $DIR/extern-wrong-value-type.rs:4:1 - | -LL | fn is_fn(_: F) where F: Fn() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/feature-gate-optimize_attribute.rs b/src/test/ui/feature-gate-optimize_attribute.rs index 7fc0fdde6fba8..15aa3a6af4ca9 100644 --- a/src/test/ui/feature-gate-optimize_attribute.rs +++ b/src/test/ui/feature-gate-optimize_attribute.rs @@ -1,17 +1,17 @@ #![crate_type="rlib"] -#![optimize(speed)] //~ ERROR `#[optimize]` attribute is an unstable feature +#![optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature -#[optimize(size)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(size)] //~ ERROR the `#[optimize]` attribute is an experimental feature mod module { -#[optimize(size)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(size)] //~ ERROR the `#[optimize]` attribute is an experimental feature fn size() {} -#[optimize(speed)] //~ ERROR `#[optimize]` attribute is an unstable feature +#[optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature fn speed() {} #[optimize(banana)] -//~^ ERROR `#[optimize]` attribute is an unstable feature +//~^ ERROR the `#[optimize]` attribute is an experimental feature //~| ERROR E0722 fn not_known() {} diff --git a/src/test/ui/feature-gate-optimize_attribute.stderr b/src/test/ui/feature-gate-optimize_attribute.stderr index 4ec512eaf39a4..3e3ad71c344ee 100644 --- a/src/test/ui/feature-gate-optimize_attribute.stderr +++ b/src/test/ui/feature-gate-optimize_attribute.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:7:1 | LL | #[optimize(size)] @@ -7,7 +7,7 @@ LL | #[optimize(size)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:10:1 | LL | #[optimize(speed)] @@ -16,7 +16,7 @@ LL | #[optimize(speed)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:13:1 | LL | #[optimize(banana)] @@ -25,7 +25,7 @@ LL | #[optimize(banana)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:4:1 | LL | #[optimize(size)] @@ -34,7 +34,7 @@ LL | #[optimize(size)] = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable -error[E0658]: `#[optimize]` attribute is an unstable feature +error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:2:1 | LL | #![optimize(speed)] diff --git a/src/test/ui/feature-gate/feature-gate-or_patterns.rs b/src/test/ui/feature-gate/feature-gate-or_patterns.rs deleted file mode 100644 index 036a6095965bd..0000000000000 --- a/src/test/ui/feature-gate/feature-gate-or_patterns.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![crate_type="lib"] - -pub fn example(x: Option) { - match x { - Some(0 | 1 | 2) => {} - //~^ ERROR: or-patterns syntax is experimental - _ => {} - } -} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr index be3536aa789c1..f14591c85e62e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive-2.stderr @@ -1,5 +1,5 @@ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 | LL | #[derive(x3300)] | ^^^^^ @@ -11,7 +11,7 @@ LL | #[derive(x3300)] | ^^^^^ error: cannot find derive macro `x3300` in this scope - --> $DIR/issue-43106-gating-of-derive-2.rs:12:14 + --> $DIR/issue-43106-gating-of-derive-2.rs:4:14 | LL | #[derive(x3300)] | ^^^^^ diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs index 1397412988491..c5d9e0db4d389 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.rs @@ -1,9 +1,6 @@ // `#![derive]` raises errors when it occurs at contexts other than ADT // definitions. -#![derive(Debug)] -//~^ ERROR `derive` may only be applied to structs, enums and unions - #[derive(Debug)] //~^ ERROR `derive` may only be applied to structs, enums and unions mod derive { diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index 25f160983d3df..db29a2bddd35c 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,38 +1,32 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | -LL | #![derive(Debug)] - | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` - -error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:7:1 - | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:10:17 + --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:13:5 + --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:26:5 + --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ error: `derive` may only be applied to structs, enums and unions - --> $DIR/issue-43106-gating-of-derive.rs:30:5 + --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs index 17b4f775ad4de..ad89096183080 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs @@ -5,7 +5,7 @@ use core::alloc::Layout; -#[alloc_error_handler] //~ ERROR `#[alloc_error_handler]` is an unstable feature +#[alloc_error_handler] //~ ERROR the `#[alloc_error_handler]` attribute is an experimental feature fn oom(info: Layout) -> ! { loop {} } diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr index d18cc09ffe777..79e44bf0d8ec1 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[alloc_error_handler]` is an unstable feature +error[E0658]: the `#[alloc_error_handler]` attribute is an experimental feature --> $DIR/feature-gate-alloc-error-handler.rs:8:1 | LL | #[alloc_error_handler] diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.rs b/src/test/ui/feature-gates/feature-gate-allow_fail.rs index f9ad48551410c..287d4ccf18010 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.rs +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.rs @@ -1,6 +1,6 @@ // check that #[allow_fail] is feature-gated -#[allow_fail] //~ ERROR allow_fail attribute is currently unstable +#[allow_fail] //~ ERROR the `#[allow_fail]` attribute is an experimental feature fn ok_to_fail() { assert!(false); } diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr index 37bf3a262aaa0..0f60a2de3a4e5 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr @@ -1,4 +1,4 @@ -error[E0658]: allow_fail attribute is currently unstable +error[E0658]: the `#[allow_fail]` attribute is an experimental feature --> $DIR/feature-gate-allow_fail.rs:3:1 | LL | #[allow_fail] diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs index ea06c775b1a60..5050c4792b064 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Display}; #[marker] trait ExplicitMarker {} -//~^ ERROR marker traits is an experimental feature +//~^ ERROR the `#[marker]` attribute is an experimental feature impl ExplicitMarker for T {} impl ExplicitMarker for T {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr index 94dfaf9206d14..304c081c5aace 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -1,4 +1,4 @@ -error[E0658]: marker traits is an experimental feature +error[E0658]: the `#[marker]` attribute is an experimental feature --> $DIR/feature-gate-marker_trait_attr.rs:3:1 | LL | #[marker] trait ExplicitMarker {} diff --git a/src/test/ui/feature-gates/feature-gate-no_core.rs b/src/test/ui/feature-gates/feature-gate-no_core.rs index 40178edd74b8d..706efd7867211 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.rs +++ b/src/test/ui/feature-gates/feature-gate-no_core.rs @@ -1,5 +1,5 @@ #![crate_type = "rlib"] -#![no_core] //~ ERROR no_core is experimental +#![no_core] //~ ERROR the `#[no_core]` attribute is an experimental feature pub struct S {} diff --git a/src/test/ui/feature-gates/feature-gate-no_core.stderr b/src/test/ui/feature-gates/feature-gate-no_core.stderr index 4d4ca96544e56..a80b3cbba25b1 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.stderr +++ b/src/test/ui/feature-gates/feature-gate-no_core.stderr @@ -1,4 +1,4 @@ -error[E0658]: no_core is experimental +error[E0658]: the `#[no_core]` attribute is an experimental feature --> $DIR/feature-gate-no_core.rs:3:1 | LL | #![no_core] diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs index aca214d1935e2..950f170f4fd41 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs @@ -1,6 +1,6 @@ //#![feature(non_exhaustive)] -#[non_exhaustive] //~ERROR non exhaustive is an experimental feature +#[non_exhaustive] //~ERROR the `#[non_exhaustive]` attribute is an experimental feature pub enum NonExhaustiveEnum { Unit, Tuple(u32), diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr index 8a01aa9eb6a9a..482332b8d706c 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr @@ -1,4 +1,4 @@ -error[E0658]: non exhaustive is an experimental feature +error[E0658]: the `#[non_exhaustive]` attribute is an experimental feature --> $DIR/feature-gate-non_exhaustive.rs:3:1 | LL | #[non_exhaustive] diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs index 13983726c78de..4044fd2b895e4 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs @@ -16,7 +16,7 @@ fn f() {} fn g() {} #[rustc_dummy] -//~^ ERROR used by the test suite +//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests #[rustc_unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR cannot find attribute macro `rustc_unknown` in this scope diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 23cf936ee8350..c1063027fa444 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -43,7 +43,7 @@ error: cannot find attribute macro `rustc_unknown` in this scope LL | #[rustc_unknown] | ^^^^^^^^^^^^^ -error[E0658]: used by the test suite +error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs.rs:18:1 | LL | #[rustc_dummy] diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs index 08e8ec9a56e51..6d8ac7e8f2911 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.rs @@ -8,7 +8,7 @@ extern { fn extern_fn(); // CHECK-NOT: Function Attrs: nounwind // CHECK: declare void @unwinding_extern_fn - #[unwind(allowed)] //~ ERROR `#[unwind]` is experimental + #[unwind(allowed)] //~ ERROR the `#[unwind]` attribute is an experimental feature fn unwinding_extern_fn(); } diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr index 639b87e016214..10cc494213507 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr @@ -1,4 +1,4 @@ -error[E0658]: `#[unwind]` is experimental +error[E0658]: the `#[unwind]` attribute is an experimental feature --> $DIR/feature-gate-unwind-attributes.rs:11:5 | LL | #[unwind(allowed)] diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index 1f698c90cb9a4..599dcfaa72617 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -1,6 +1,9 @@ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:8:5 | +LL | fn send(_: T) {} + | ---------------------- required by `send` +... LL | send(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -12,15 +15,13 @@ LL | send(format_args!("{:?}", c)); = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -note: required by `send` - --> $DIR/send-sync.rs:1:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 | +LL | fn sync(_: T) {} + | ---------------------- required by `sync` +... LL | sync(format_args!("{:?}", c)); | ^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely | @@ -32,11 +33,6 @@ LL | sync(format_args!("{:?}", c)); = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]` = note: required because it appears within the type `std::fmt::Arguments<'_>` -note: required by `sync` - --> $DIR/send-sync.rs:2:1 - | -LL | fn sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index 504bc2605ec38..20d7d9ea5b7a8 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -28,15 +28,13 @@ LL | let _: () = (box || -> isize { unimplemented!() }) as Box` closure, found `{integer}` --> $DIR/fn-trait-formatting.rs:19:5 | +LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} + | ------------------------------------------------ required by `needs_fn` +... LL | needs_fn(1); | ^^^^^^^^ expected an `Fn<(isize,)>` closure, found `{integer}` | = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `{integer}` -note: required by `needs_fn` - --> $DIR/fn-trait-formatting.rs:3:1 - | -LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator-yielding-or-returning-itself.stderr index 42591683fe4e3..1049bb6240a24 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator-yielding-or-returning-itself.stderr @@ -16,20 +16,18 @@ LL | | }) error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | -LL | want_cyclic_generator_yield(|| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size - | - = note: closures cannot capture themselves or take themselves as argument; - this error may be the result of a recent compiler bug-fix, - see https://github.com/rust-lang/rust/issues/46062 for more details -note: required by `want_cyclic_generator_yield` - --> $DIR/generator-yielding-or-returning-itself.rs:22:1 - | LL | / pub fn want_cyclic_generator_yield(_: T) LL | | where T: Generator LL | | { LL | | } - | |_^ + | |_- required by `want_cyclic_generator_yield` +... +LL | want_cyclic_generator_yield(|| { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | + = note: closures cannot capture themselves or take themselves as argument; + this error may be the result of a recent compiler bug-fix, + see https://github.com/rust-lang/rust/issues/46062 for more details error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr deleted file mode 100644 index 23ae21585fd38..0000000000000 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error[E0628]: generators cannot have explicit arguments - --> $DIR/no-arguments-on-generators.rs:4:15 - | -LL | let gen = |start| { - | ^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/generator/no-arguments-on-generators.rs b/src/test/ui/generator/no-parameters-on-generators.rs similarity index 90% rename from src/test/ui/generator/no-arguments-on-generators.rs rename to src/test/ui/generator/no-parameters-on-generators.rs index 344c1179be90e..a2632a4bd7d84 100644 --- a/src/test/ui/generator/no-arguments-on-generators.rs +++ b/src/test/ui/generator/no-parameters-on-generators.rs @@ -1,7 +1,7 @@ #![feature(generators)] fn main() { - let gen = |start| { //~ ERROR generators cannot have explicit arguments + let gen = |start| { //~ ERROR generators cannot have explicit parameters yield; }; } diff --git a/src/test/ui/generator/no-parameters-on-generators.stderr b/src/test/ui/generator/no-parameters-on-generators.stderr new file mode 100644 index 0000000000000..41862f2b0704b --- /dev/null +++ b/src/test/ui/generator/no-parameters-on-generators.stderr @@ -0,0 +1,8 @@ +error[E0628]: generators cannot have explicit parameters + --> $DIR/no-parameters-on-generators.rs:4:15 + | +LL | let gen = |start| { + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 7ea9832c99a24..51416ce0d2f7a 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -1,32 +1,28 @@ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:16:5 | +LL | fn assert_send(_: T) {} + | ----------------------------- required by `main::assert_send` +... LL | assert_send(|| { | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` -note: required by `main::assert_send` - --> $DIR/not-send-sync.rs:7:5 - | -LL | fn assert_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | +LL | fn assert_sync(_: T) {} + | ----------------------------- required by `main::assert_sync` +... LL | assert_sync(|| { | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because it appears within the type `{std::cell::Cell, ()}` = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]` -note: required by `main::assert_sync` - --> $DIR/not-send-sync.rs:6:5 - | -LL | fn assert_sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 404d3069f79f3..28a6fac5b85e3 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied --> $DIR/static-not-unpin.rs:14:5 | +LL | fn assert_unpin(_: T) { + | ------------------------------- required by `assert_unpin` +... LL | assert_unpin(generator); | ^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` - | -note: required by `assert_unpin` - --> $DIR/static-not-unpin.rs:7:1 - | -LL | fn assert_unpin(_: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-conflate-regions.stderr b/src/test/ui/hrtb/hrtb-conflate-regions.stderr index 20265d66c6f43..e0b968b67645e 100644 --- a/src/test/ui/hrtb/hrtb-conflate-regions.stderr +++ b/src/test/ui/hrtb/hrtb-conflate-regions.stderr @@ -1,19 +1,17 @@ error[E0277]: the trait bound `for<'a, 'b> SomeStruct: Foo<(&'a isize, &'b isize)>` is not satisfied --> $DIR/hrtb-conflate-regions.rs:27:10 | -LL | fn b() { want_foo2::(); } - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct` - | - = help: the following implementations were found: - > -note: required by `want_foo2` - --> $DIR/hrtb-conflate-regions.rs:8:1 - | LL | / fn want_foo2() LL | | where T : for<'a,'b> Foo<(&'a isize, &'b isize)> LL | | { LL | | } - | |_^ + | |_- required by `want_foo2` +... +LL | fn b() { want_foo2::(); } + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Foo<(&'a isize, &'b isize)>` is not implemented for `SomeStruct` + | + = help: the following implementations were found: + > error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr index 7f2ca037f0f49..bc58b8e16aaf2 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-contravariant.stderr @@ -1,20 +1,18 @@ error[E0277]: the trait bound `(): Trait fn(&'b u32)>` is not satisfied --> $DIR/hrtb-exists-forall-trait-contravariant.rs:34:5 | -LL | foo::<()>(); - | ^^^^^^^^^ the trait `Trait fn(&'b u32)>` is not implemented for `()` - | - = help: the following implementations were found: - <() as Trait> -note: required by `foo` - --> $DIR/hrtb-exists-forall-trait-contravariant.rs:8:1 - | LL | / fn foo() LL | | where LL | | T: Trait fn(&'b u32)>, LL | | { LL | | } - | |_^ + | |_- required by `foo` +... +LL | foo::<()>(); + | ^^^^^^^^^ the trait `Trait fn(&'b u32)>` is not implemented for `()` + | + = help: the following implementations were found: + <() as Trait> error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr index cd5982e7588a7..441f75135f3a4 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-covariant.stderr @@ -1,20 +1,18 @@ error[E0277]: the trait bound `(): Trait fn(fn(&'b u32))>` is not satisfied --> $DIR/hrtb-exists-forall-trait-covariant.rs:36:5 | -LL | foo::<()>(); - | ^^^^^^^^^ the trait `Trait fn(fn(&'b u32))>` is not implemented for `()` - | - = help: the following implementations were found: - <() as Trait> -note: required by `foo` - --> $DIR/hrtb-exists-forall-trait-covariant.rs:8:1 - | LL | / fn foo() LL | | where LL | | T: Trait fn(fn(&'b u32))>, LL | | { LL | | } - | |_^ + | |_- required by `foo` +... +LL | foo::<()>(); + | ^^^^^^^^^ the trait `Trait fn(fn(&'b u32))>` is not implemented for `()` + | + = help: the following implementations were found: + <() as Trait> error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index f10e427a545fb..a11949735b9d2 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -1,20 +1,18 @@ error[E0277]: the trait bound `(): Trait fn(std::cell::Cell<&'b u32>)>` is not satisfied --> $DIR/hrtb-exists-forall-trait-invariant.rs:28:5 | -LL | foo::<()>(); - | ^^^^^^^^^ the trait `Trait fn(std::cell::Cell<&'b u32>)>` is not implemented for `()` - | - = help: the following implementations were found: - <() as Trait)>> -note: required by `foo` - --> $DIR/hrtb-exists-forall-trait-invariant.rs:10:1 - | LL | / fn foo() LL | | where LL | | T: Trait fn(Cell<&'b u32>)>, LL | | { LL | | } - | |_^ + | |_- required by `foo` +... +LL | foo::<()>(); + | ^^^^^^^^^ the trait `Trait fn(std::cell::Cell<&'b u32>)>` is not implemented for `()` + | + = help: the following implementations were found: + <() as Trait)>> error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr index b5d945fe15ca0..0cddd353d679e 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits-transitive.stderr @@ -1,18 +1,16 @@ error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:47:5 | -LL | want_bar_for_any_ccx(b); - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound -note: required by `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits-transitive.rs:31:1 - | LL | / fn want_bar_for_any_ccx(b: &B) LL | | where B : for<'ccx> Bar<'ccx> LL | | { LL | | } - | |_^ + | |_- required by `want_bar_for_any_ccx` +... +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` + | + = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound error: aborting due to previous error diff --git a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr index 20a8fd459fa41..6df486ebaff38 100644 --- a/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr +++ b/src/test/ui/hrtb/hrtb-higher-ranker-supertraits.stderr @@ -1,31 +1,25 @@ error[E0277]: the trait bound `for<'tcx> F: Foo<'tcx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:18:5 | -LL | want_foo_for_any_tcx(f); - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` - | - = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound -note: required by `want_foo_for_any_tcx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:21:1 - | +LL | want_foo_for_any_tcx(f); + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'tcx> Foo<'tcx>` is not implemented for `F` +... LL | / fn want_foo_for_any_tcx(f: &F) LL | | where F : for<'tcx> Foo<'tcx> LL | | { LL | | want_foo_for_some_tcx(f); LL | | want_foo_for_any_tcx(f); LL | | } - | |_^ + | |_- required by `want_foo_for_any_tcx` + | + = help: consider adding a `where for<'tcx> F: Foo<'tcx>` bound error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:35:5 | -LL | want_bar_for_any_ccx(b); - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` - | - = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound -note: required by `want_bar_for_any_ccx` - --> $DIR/hrtb-higher-ranker-supertraits.rs:38:1 - | +LL | want_bar_for_any_ccx(b); + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'ccx> Bar<'ccx>` is not implemented for `B` +... LL | / fn want_bar_for_any_ccx(b: &B) LL | | where B : for<'ccx> Bar<'ccx> LL | | { @@ -33,7 +27,9 @@ LL | | want_foo_for_some_tcx(b); ... | LL | | want_bar_for_any_ccx(b); LL | | } - | |_^ + | |_- required by `want_bar_for_any_ccx` + | + = help: consider adding a `where for<'ccx> B: Bar<'ccx>` bound error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/hrtb-just-for-static.stderr b/src/test/ui/hrtb/hrtb-just-for-static.stderr index 115851ddf9385..b2938e541fdd8 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.stderr @@ -1,36 +1,32 @@ error[E0277]: the trait bound `for<'a> StaticInt: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:24:5 | -LL | want_hrtb::() - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` - | - = help: the following implementations were found: - > -note: required by `want_hrtb` - --> $DIR/hrtb-just-for-static.rs:8:1 - | LL | / fn want_hrtb() LL | | where T : for<'a> Foo<&'a isize> LL | | { LL | | } - | |_^ + | |_- required by `want_hrtb` +... +LL | want_hrtb::() + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `StaticInt` + | + = help: the following implementations were found: + > error[E0277]: the trait bound `for<'a> &'a u32: Foo<&'a isize>` is not satisfied --> $DIR/hrtb-just-for-static.rs:30:5 | -LL | want_hrtb::<&'a u32>() - | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32` - | - = help: the following implementations were found: - <&'a u32 as Foo<&'a isize>> -note: required by `want_hrtb` - --> $DIR/hrtb-just-for-static.rs:8:1 - | LL | / fn want_hrtb() LL | | where T : for<'a> Foo<&'a isize> LL | | { LL | | } - | |_^ + | |_- required by `want_hrtb` +... +LL | want_hrtb::<&'a u32>() + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Foo<&'a isize>` is not implemented for `&'a u32` + | + = help: the following implementations were found: + <&'a u32 as Foo<&'a isize>> error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/issue-46989.stderr b/src/test/ui/hrtb/issue-46989.stderr index b308291d5c0eb..57eaf2aad2bc5 100644 --- a/src/test/ui/hrtb/issue-46989.stderr +++ b/src/test/ui/hrtb/issue-46989.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `for<'r> fn(&'r i32): Foo` is not satisfied --> $DIR/issue-46989.rs:40:5 | +LL | fn assert_foo() {} + | ----------------------- required by `assert_foo` +... LL | assert_foo::(); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `for<'r> fn(&'r i32)` | = help: the following implementations were found: -note: required by `assert_foo` - --> $DIR/issue-46989.rs:37:1 - | -LL | fn assert_foo() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/hygiene/eager-from-opaque-2.rs b/src/test/ui/hygiene/eager-from-opaque-2.rs new file mode 100644 index 0000000000000..220e5526745c3 --- /dev/null +++ b/src/test/ui/hygiene/eager-from-opaque-2.rs @@ -0,0 +1,22 @@ +// Regression test for the issue #63460. + +// check-pass + +#[macro_export] +macro_rules! separator { + () => { "/" }; +} + +#[macro_export] +macro_rules! concat_separator { + ( $e:literal, $($other:literal),+ ) => { + concat!($e, $crate::separator!(), $crate::concat_separator!($($other),+)) + }; + ( $e:literal ) => { + $e + } +} + +fn main() { + println!("{}", concat_separator!(2, 3, 4)) +} diff --git a/src/test/ui/hygiene/eager-from-opaque.rs b/src/test/ui/hygiene/eager-from-opaque.rs new file mode 100644 index 0000000000000..6f3215dd697f3 --- /dev/null +++ b/src/test/ui/hygiene/eager-from-opaque.rs @@ -0,0 +1,20 @@ +// Opaque macro can eagerly expand its input without breaking its resolution. +// Regression test for issue #63685. + +// check-pass + +macro_rules! foo { + () => { + "foo" + }; +} + +macro_rules! bar { + () => { + foo!() + }; +} + +fn main() { + format_args!(bar!()); +} diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/if/if-without-else-as-fn-expr.rs index 15892de83854c..826371be35f45 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.rs +++ b/src/test/ui/if/if-without-else-as-fn-expr.rs @@ -3,7 +3,6 @@ fn foo(bar: usize) -> usize { return 3; } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo2(bar: usize) -> usize { @@ -11,7 +10,6 @@ fn foo2(bar: usize) -> usize { return 3; }; //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] x } @@ -20,7 +18,6 @@ fn foo3(bar: usize) -> usize { 3 } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo_let(bar: usize) -> usize { @@ -28,7 +25,6 @@ fn foo_let(bar: usize) -> usize { return 3; } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } fn foo2_let(bar: usize) -> usize { @@ -36,7 +32,6 @@ fn foo2_let(bar: usize) -> usize { return 3; }; //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] x } @@ -45,7 +40,6 @@ fn foo3_let(bar: usize) -> usize { 3 } //~^^^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } // FIXME(60254): deduplicate first error in favor of second. diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/if/if-without-else-as-fn-expr.stderr index 06600b1cb9aea..b49c2aa6319df 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.stderr +++ b/src/test/ui/if/if-without-else-as-fn-expr.stderr @@ -1,14 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:2:5 - | -LL | / if bar % 5 == 0 { -LL | | return 3; -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause --> $DIR/if-without-else-as-fn-expr.rs:2:5 | @@ -24,20 +13,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:10:20 - | -LL | let x: usize = if bar % 5 == 0 { - | ____________________^ -LL | | return 3; -LL | | }; - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:10:20 + --> $DIR/if-without-else-as-fn-expr.rs:9:20 | LL | let x: usize = if bar % 5 == 0 { | _________-__________^ @@ -52,19 +29,8 @@ LL | | }; = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:19:5 - | -LL | / if bar % 5 == 0 { -LL | | 3 -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:19:5 + --> $DIR/if-without-else-as-fn-expr.rs:17:5 | LL | fn foo3(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -78,19 +44,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:27:5 - | -LL | / if let 0 = 1 { -LL | | return 3; -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:27:5 + --> $DIR/if-without-else-as-fn-expr.rs:24:5 | LL | fn foo_let(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -104,20 +59,8 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:35:20 - | -LL | let x: usize = if let 0 = 1 { - | ____________________^ -LL | | return 3; -LL | | }; - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:35:20 + --> $DIR/if-without-else-as-fn-expr.rs:31:20 | LL | let x: usize = if let 0 = 1 { | _________-__________^ @@ -132,19 +75,8 @@ LL | | }; = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error[E0308]: mismatched types - --> $DIR/if-without-else-as-fn-expr.rs:44:5 - | -LL | / if let 0 = 1 { -LL | | 3 -LL | | } - | |_____^ expected usize, found () - | - = note: expected type `usize` - found type `()` - error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:44:5 + --> $DIR/if-without-else-as-fn-expr.rs:39:5 | LL | fn foo3_let(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -158,7 +90,6 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error: aborting due to 12 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0308, E0317. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 61450d3203cd8..af641a89e7f9c 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -72,16 +72,14 @@ LL | | } error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/auto-trait-leak.rs:15:5 | +LL | fn send(_: T) {} + | ---------------------- required by `send` +... LL | send(cycle2().clone()); | ^^^^ `std::rc::Rc` cannot be sent between threads safely | = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `impl std::clone::Clone` -note: required by `send` - --> $DIR/auto-trait-leak.rs:4:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index 19899ff83f7c3..460af7dedbea8 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,32 +1,28 @@ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:13:5 | +LL | fn send(_: T) {} + | ---------------------- required by `send` +... LL | send(before()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` -note: required by `send` - --> $DIR/auto-trait-leak2.rs:10:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:16:5 | +LL | fn send(_: T) {} + | ---------------------- required by `send` +... LL | send(after()); | ^^^^ `std::rc::Rc>` cannot be sent between threads safely | = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` -note: required by `send` - --> $DIR/auto-trait-leak2.rs:10:1 - | -LL | fn send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index d980d7cccadd5..002b60f9f258d 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -49,6 +49,14 @@ LL | use foo::Bar; error[E0599]: no method named `method` found for type `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | +LL | fn method(&self) {} + | ------ + | | + | the method is available for `std::boxed::Box>>` here + | the method is available for `std::pin::Pin>>` here + | the method is available for `std::sync::Arc>>` here + | the method is available for `std::rc::Rc>>` here +... LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ | diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr index 4554da7b798ea..55523bad6c507 100644 --- a/src/test/ui/inline-asm-bad-operand.stderr +++ b/src/test/ui/inline-asm-bad-operand.stderr @@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr), error[E0669]: invalid value for constraint in inline assembly --> $DIR/inline-asm-bad-operand.rs:56:32 | -LL | "r"("hello e0669")); - | ^^^^^^^^^^^^^ +LL | ... "r"("hello e0669")); + | ^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/issues/issue-1920-1.stderr b/src/test/ui/issues/issue-1920-1.stderr index b3ac05031b00f..c62cbb0cf8b96 100644 --- a/src/test/ui/issues/issue-1920-1.stderr +++ b/src/test/ui/issues/issue-1920-1.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `foo::issue_1920::S: std::clone::Clone` is not satisfied --> $DIR/issue-1920-1.rs:12:5 | +LL | fn assert_clone() where T : Clone { } + | ------------------------------------ required by `assert_clone` +... LL | assert_clone::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `foo::issue_1920::S` - | -note: required by `assert_clone` - --> $DIR/issue-1920-1.rs:9:1 - | -LL | fn assert_clone() where T : Clone { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-2.stderr b/src/test/ui/issues/issue-1920-2.stderr index a000a87302bf7..aad076244699a 100644 --- a/src/test/ui/issues/issue-1920-2.stderr +++ b/src/test/ui/issues/issue-1920-2.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `bar::S: std::clone::Clone` is not satisfied --> $DIR/issue-1920-2.rs:10:5 | +LL | fn assert_clone() where T : Clone { } + | ------------------------------------ required by `assert_clone` +... LL | assert_clone::(); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `bar::S` - | -note: required by `assert_clone` - --> $DIR/issue-1920-2.rs:7:1 - | -LL | fn assert_clone() where T : Clone { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-3.stderr b/src/test/ui/issues/issue-1920-3.stderr index 62e47a6866e63..4378ea49755a7 100644 --- a/src/test/ui/issues/issue-1920-3.stderr +++ b/src/test/ui/issues/issue-1920-3.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `issue_1920::S: std::clone::Clone` is not satisfied --> $DIR/issue-1920-3.rs:14:5 | +LL | fn assert_clone() where T : Clone { } + | ------------------------------------ required by `assert_clone` +... LL | assert_clone::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `issue_1920::S` - | -note: required by `assert_clone` - --> $DIR/issue-1920-3.rs:11:1 - | -LL | fn assert_clone() where T : Clone { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index e271005e74d1d..2754d6bdd8306 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -1,6 +1,9 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/issue-20005.rs:8:5 | +LL | trait From { + | --------------- required by `From` +... LL | / fn to( LL | | self LL | | ) -> >::Result where Dst: From { @@ -11,11 +14,6 @@ LL | | } = help: the trait `std::marker::Sized` is not implemented for `Self` = note: to learn more, visit = help: consider adding a `where Self: std::marker::Sized` bound -note: required by `From` - --> $DIR/issue-20005.rs:1:1 - | -LL | trait From { - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 762816c5a98c4..72a8fe4283b56 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -9,6 +9,9 @@ LL | struct NoData; error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:1 | +LL | trait Foo { + | --------- required by `Foo` +... LL | / impl Foo for T where NoData: Foo { LL | | LL | | fn answer(self) { @@ -146,15 +149,13 @@ LL | | } = note: required because of the requirements on the impl of `Foo` for `NoData>>` = note: required because of the requirements on the impl of `Foo` for `NoData>` = note: required because of the requirements on the impl of `Foo` for `NoData` -note: required by `Foo` - --> $DIR/issue-20413.rs:1:1 - | -LL | trait Foo { - | ^^^^^^^^^ error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:10:3 | +LL | trait Foo { + | --------- required by `Foo` +... LL | / fn answer(self) { LL | | LL | | let val: NoData = NoData; @@ -289,11 +290,6 @@ LL | | } = note: required because of the requirements on the impl of `Foo` for `NoData>>` = note: required because of the requirements on the impl of `Foo` for `NoData>` = note: required because of the requirements on the impl of `Foo` for `NoData` -note: required by `Foo` - --> $DIR/issue-20413.rs:1:1 - | -LL | trait Foo { - | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-21763.stderr b/src/test/ui/issues/issue-21763.stderr index 87c048fdf4c11..99d004a973a26 100644 --- a/src/test/ui/issues/issue-21763.stderr +++ b/src/test/ui/issues/issue-21763.stderr @@ -1,6 +1,9 @@ error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> $DIR/issue-21763.rs:9:5 | +LL | fn foo() {} + | ----------------- required by `foo` +... LL | foo::, Rc<()>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | @@ -9,11 +12,6 @@ LL | foo::, Rc<()>>>(); = note: required because of the requirements on the impl of `std::marker::Send` for `hashbrown::raw::RawTable<(std::rc::Rc<()>, std::rc::Rc<()>)>` = note: required because it appears within the type `hashbrown::map::HashMap, std::rc::Rc<()>, std::collections::hash_map::RandomState>` = note: required because it appears within the type `std::collections::HashMap, std::rc::Rc<()>>` -note: required by `foo` - --> $DIR/issue-21763.rs:6:1 - | -LL | fn foo() {} - | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21837.stderr b/src/test/ui/issues/issue-21837.stderr index 3111d3a47414b..20d02a90315d0 100644 --- a/src/test/ui/issues/issue-21837.stderr +++ b/src/test/ui/issues/issue-21837.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: Bound` is not satisfied --> $DIR/issue-21837.rs:8:9 | +LL | pub struct Foo(T); + | ---------------------------- required by `Foo` +... LL | impl Trait2 for Foo {} | ^^^^^^ the trait `Bound` is not implemented for `T` | = help: consider adding a `where T: Bound` bound -note: required by `Foo` - --> $DIR/issue-21837.rs:2:1 - | -LL | pub struct Foo(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr index 85e59d7bede5f..a6cce7846e81d 100644 --- a/src/test/ui/issues/issue-21974.stderr +++ b/src/test/ui/issues/issue-21974.stderr @@ -1,6 +1,9 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` --> $DIR/issue-21974.rs:10:1 | +LL | trait Foo { + | --------- required by `Foo` +... LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) LL | | where &'a T : Foo, LL | | &'b T : Foo @@ -9,12 +12,6 @@ LL | | x.foo(); LL | | y.foo(); LL | | } | |_^ - | -note: required by `Foo` - --> $DIR/issue-21974.rs:6:1 - | -LL | trait Foo { - | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24204.stderr b/src/test/ui/issues/issue-24204.stderr index 8e04c0ddccea6..eb9aada389f8f 100644 --- a/src/test/ui/issues/issue-24204.stderr +++ b/src/test/ui/issues/issue-24204.stderr @@ -1,16 +1,14 @@ error[E0271]: type mismatch resolving `<::A as MultiDispatch>::O == T` --> $DIR/issue-24204.rs:14:1 | +LL | trait Trait: Sized { + | ------------------ required by `Trait` +... LL | fn test>(b: i32) -> T where T::A: MultiDispatch { T::new(b) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found type parameter | = note: expected type `<::A as MultiDispatch>::O` found type `T` -note: required by `Trait` - --> $DIR/issue-24204.rs:7:1 - | -LL | trait Trait: Sized { - | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr index 4c6ac0180a873..7ff019a30a864 100644 --- a/src/test/ui/issues/issue-24424.stderr +++ b/src/test/ui/issues/issue-24424.stderr @@ -1,14 +1,11 @@ error[E0283]: type annotations required: cannot resolve `T0: Trait0<'l0>` --> $DIR/issue-24424.rs:4:1 | +LL | trait Trait0<'l0> {} + | ----------------- required by `Trait0` +LL | LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: required by `Trait0` - --> $DIR/issue-24424.rs:2:1 - | -LL | trait Trait0<'l0> {} - | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25076.stderr b/src/test/ui/issues/issue-25076.stderr index 435ab13edada5..b583a6b54bf9f 100644 --- a/src/test/ui/issues/issue-25076.stderr +++ b/src/test/ui/issues/issue-25076.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `(): InOut<_>` is not satisfied --> $DIR/issue-25076.rs:10:5 | +LL | fn do_fold>(init: B, f: F) {} + | ------------------------------------------------ required by `do_fold` +... LL | do_fold(bot(), ()); | ^^^^^^^ the trait `InOut<_>` is not implemented for `()` - | -note: required by `do_fold` - --> $DIR/issue-25076.rs:5:1 - | -LL | fn do_fold>(init: B, f: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28105.rs b/src/test/ui/issues/issue-28105.rs index 6026cbb82ae75..1e8d2d6ccf132 100644 --- a/src/test/ui/issues/issue-28105.rs +++ b/src/test/ui/issues/issue-28105.rs @@ -1,8 +1,8 @@ // Make sure that a continue span actually contains the keyword. fn main() { - continue //~ ERROR `continue` outside of loop + continue //~ ERROR `continue` outside of a loop ; - break //~ ERROR `break` outside of loop + break //~ ERROR `break` outside of a loop ; } diff --git a/src/test/ui/issues/issue-28105.stderr b/src/test/ui/issues/issue-28105.stderr index 0e1b90e65209b..42ed838d7c037 100644 --- a/src/test/ui/issues/issue-28105.stderr +++ b/src/test/ui/issues/issue-28105.stderr @@ -1,14 +1,14 @@ -error[E0268]: `continue` outside of loop +error[E0268]: `continue` outside of a loop --> $DIR/issue-28105.rs:4:5 | LL | continue - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `continue` outside of a loop -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-28105.rs:6:5 | LL | break - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr index 3b42186b25138..0dc9b0c9e10cd 100644 --- a/src/test/ui/issues/issue-29147.stderr +++ b/src/test/ui/issues/issue-29147.stderr @@ -1,14 +1,11 @@ error[E0283]: type annotations required: cannot resolve `S5<_>: Foo` --> $DIR/issue-29147.rs:21:13 | +LL | trait Foo { fn xxx(&self); } + | -------------- required by `Foo::xxx` +... LL | let _ = >::xxx; | ^^^^^^^^^^^^ - | -note: required by `Foo::xxx` - --> $DIR/issue-29147.rs:10:13 - | -LL | trait Foo { fn xxx(&self); } - | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr index a31a74a07f46e..2960f4e598997 100644 --- a/src/test/ui/issues/issue-32963.stderr +++ b/src/test/ui/issues/issue-32963.stderr @@ -12,14 +12,11 @@ LL | size_of_copy::(); error[E0277]: the trait bound `dyn Misc: std::marker::Copy` is not satisfied --> $DIR/issue-32963.rs:8:5 | +LL | fn size_of_copy() -> usize { mem::size_of::() } + | ------------------------------------------ required by `size_of_copy` +... LL | size_of_copy::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc` - | -note: required by `size_of_copy` - --> $DIR/issue-32963.rs:5:1 - | -LL | fn size_of_copy() -> usize { mem::size_of::() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-36617.rs b/src/test/ui/issues/issue-36617.rs index 87092689a281d..1102f3c4640a1 100644 --- a/src/test/ui/issues/issue-36617.rs +++ b/src/test/ui/issues/issue-36617.rs @@ -1,3 +1,4 @@ #![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions + //~| ERROR cannot determine resolution for the derive macro `Copy` fn main() {} diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 296fec46d80a6..b5db98f306bd3 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -4,5 +4,13 @@ error: `derive` may only be applied to structs, enums and unions LL | #![derive(Copy)] | ^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Copy)]` -error: aborting due to previous error +error: cannot determine resolution for the derive macro `Copy` + --> $DIR/issue-36617.rs:1:11 + | +LL | #![derive(Copy)] + | ^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-39970.stderr b/src/test/ui/issues/issue-39970.stderr index e4f158706457c..f15f771fa9f6e 100644 --- a/src/test/ui/issues/issue-39970.stderr +++ b/src/test/ui/issues/issue-39970.stderr @@ -1,17 +1,15 @@ error[E0271]: type mismatch resolving `for<'a> <() as Array<'a>>::Element == ()` --> $DIR/issue-39970.rs:19:5 | +LL | fn visit() {} + | ---------- required by `Visit::visit` +... LL | <() as Visit>::visit(); | ^^^^^^^^^^^^^^^^^^^^ expected &(), found () | = note: expected type `&()` found type `()` = note: required because of the requirements on the impl of `Visit` for `()` -note: required by `Visit::visit` - --> $DIR/issue-39970.rs:6:5 - | -LL | fn visit() {} - | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40827.stderr b/src/test/ui/issues/issue-40827.stderr index 96b411bfb1d22..9131120671f4c 100644 --- a/src/test/ui/issues/issue-40827.stderr +++ b/src/test/ui/issues/issue-40827.stderr @@ -1,6 +1,9 @@ error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/issue-40827.rs:14:5 | +LL | fn f(_: T) {} + | ------------------- required by `f` +... LL | f(Foo(Arc::new(Bar::B(None)))); | ^ `std::rc::Rc` cannot be sent between threads safely | @@ -8,15 +11,13 @@ LL | f(Foo(Arc::new(Bar::B(None)))); = note: required because it appears within the type `Bar` = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` = note: required because it appears within the type `Foo` -note: required by `f` - --> $DIR/issue-40827.rs:11:1 - | -LL | fn f(_: T) {} - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc` cannot be shared between threads safely --> $DIR/issue-40827.rs:14:5 | +LL | fn f(_: T) {} + | ------------------- required by `f` +... LL | f(Foo(Arc::new(Bar::B(None)))); | ^ `std::rc::Rc` cannot be shared between threads safely | @@ -24,11 +25,6 @@ LL | f(Foo(Arc::new(Bar::B(None)))); = note: required because it appears within the type `Bar` = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` = note: required because it appears within the type `Foo` -note: required by `f` - --> $DIR/issue-40827.rs:11:1 - | -LL | fn f(_: T) {} - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-43162.stderr b/src/test/ui/issues/issue-43162.stderr index 6d3e8b5ba2323..c729c05ff229e 100644 --- a/src/test/ui/issues/issue-43162.stderr +++ b/src/test/ui/issues/issue-43162.stderr @@ -1,14 +1,14 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-43162.rs:3:5 | LL | break true; - | ^^^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^^^ cannot `break` outside of a loop -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-43162.rs:7:5 | LL | break {}; - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `break` outside of a loop error[E0308]: mismatched types --> $DIR/issue-43162.rs:1:13 diff --git a/src/test/ui/issues/issue-43623.stderr b/src/test/ui/issues/issue-43623.stderr index b5674105f75d2..d843629e8a26f 100644 --- a/src/test/ui/issues/issue-43623.stderr +++ b/src/test/ui/issues/issue-43623.stderr @@ -1,41 +1,31 @@ error[E0631]: type mismatch in function arguments --> $DIR/issue-43623.rs:14:5 | -LL | break_me::; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected signature of `for<'b> fn(>::Assoc) -> _` - | found signature of `fn(_) -> _` - | -note: required by `break_me` - --> $DIR/issue-43623.rs:11:1 - | LL | / pub fn break_me(f: F) LL | | where T: for<'b> Trait<'b>, LL | | F: for<'b> FnMut(>::Assoc) { LL | | break_me::; + | | ^^^^^^^^^^^^^^^^^^^^^^^ + | | | + | | expected signature of `for<'b> fn(>::Assoc) -> _` + | | found signature of `fn(_) -> _` LL | | LL | | LL | | } - | |_^ + | |_- required by `break_me` error[E0271]: type mismatch resolving `for<'b> >::Assoc,)>>::Output == ()` --> $DIR/issue-43623.rs:14:5 | -LL | break_me::; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime - | -note: required by `break_me` - --> $DIR/issue-43623.rs:11:1 - | LL | / pub fn break_me(f: F) LL | | where T: for<'b> Trait<'b>, LL | | F: for<'b> FnMut(>::Assoc) { LL | | break_me::; + | | ^^^^^^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime LL | | LL | | LL | | } - | |_^ + | |_- required by `break_me` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-44415.stderr b/src/test/ui/issues/issue-44415.stderr index df8e804c87a3f..8008e53f65f4d 100644 --- a/src/test/ui/issues/issue-44415.stderr +++ b/src/test/ui/issues/issue-44415.stderr @@ -4,6 +4,11 @@ error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{con LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^ | +note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... + --> $DIR/issue-44415.rs:6:17 + | +LL | bytes: [u8; unsafe { intrinsics::size_of::() }], + | ^^^^^^ note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... --> $DIR/issue-44415.rs:6:26 | @@ -11,11 +16,6 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::() }], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`... -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... - --> $DIR/issue-44415.rs:6:17 - | -LL | bytes: [u8; unsafe { intrinsics::size_of::() }], - | ^^^^^^ = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle note: cycle used when processing `Foo` --> $DIR/issue-44415.rs:5:1 diff --git a/src/test/ui/issues/issue-47706.stderr b/src/test/ui/issues/issue-47706.stderr index fa2e00cde4dff..c47eebb8e5c07 100644 --- a/src/test/ui/issues/issue-47706.stderr +++ b/src/test/ui/issues/issue-47706.stderr @@ -10,21 +10,18 @@ LL | self.foo.map(Foo::new) error[E0593]: function is expected to take 0 arguments, but it takes 1 argument --> $DIR/issue-47706.rs:27:5 | -LL | Bar(i32), - | -------- takes 1 argument +LL | Bar(i32), + | -------- takes 1 argument ... -LL | foo(Qux::Bar); - | ^^^ expected function that takes 0 arguments - | -note: required by `foo` - --> $DIR/issue-47706.rs:20:1 - | LL | / fn foo(f: F) LL | | where LL | | F: Fn(), LL | | { LL | | } - | |_^ + | |_- required by `foo` +... +LL | foo(Qux::Bar); + | ^^^ expected function that takes 0 arguments error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-50576.stderr b/src/test/ui/issues/issue-50576.stderr index 95619eeed9a46..9fea1411080f5 100644 --- a/src/test/ui/issues/issue-50576.stderr +++ b/src/test/ui/issues/issue-50576.stderr @@ -4,17 +4,17 @@ error[E0426]: use of undeclared label `'L` LL | |bool: [u8; break 'L]| 0; | ^^ undeclared label `'L` -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-50576.rs:2:17 | LL | |bool: [u8; break 'L]| 0; - | ^^^^^^^^ cannot break outside of a loop + | ^^^^^^^^ cannot `break` outside of a loop -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-50576.rs:5:16 | LL | Vec::<[u8; break]>::new(); - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs index bf892a8daa27f..f0f1dc6c28667 100644 --- a/src/test/ui/issues/issue-50577.rs +++ b/src/test/ui/issues/issue-50577.rs @@ -2,6 +2,5 @@ fn main() { enum Foo { Drop = assert_eq!(1, 1) //~^ ERROR if may be missing an else clause - //~| ERROR mismatched types [E0308] } } diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/issues/issue-50577.stderr index 413c8c5c80b52..0c3ba2ea4f94d 100644 --- a/src/test/ui/issues/issue-50577.stderr +++ b/src/test/ui/issues/issue-50577.stderr @@ -1,13 +1,3 @@ -error[E0308]: mismatched types - --> $DIR/issue-50577.rs:3:16 - | -LL | Drop = assert_eq!(1, 1) - | ^^^^^^^^^^^^^^^^ expected isize, found () - | - = note: expected type `isize` - found type `()` - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) - error[E0317]: if may be missing an else clause --> $DIR/issue-50577.rs:3:16 | @@ -23,7 +13,6 @@ LL | Drop = assert_eq!(1, 1) = help: consider adding an `else` block that evaluates to the expected type = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0317. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0317`. diff --git a/src/test/ui/issues/issue-50581.stderr b/src/test/ui/issues/issue-50581.stderr index 01a5f9b3c4432..35d6fc49cedc8 100644 --- a/src/test/ui/issues/issue-50581.stderr +++ b/src/test/ui/issues/issue-50581.stderr @@ -1,8 +1,8 @@ -error[E0268]: `break` outside of loop +error[E0268]: `break` outside of a loop --> $DIR/issue-50581.rs:2:14 | LL | |_: [u8; break]| (); - | ^^^^^ cannot break outside of a loop + | ^^^^^ cannot `break` outside of a loop error: aborting due to previous error diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr index a79b1959dca2f..a977ba392769f 100644 --- a/src/test/ui/issues/issue-60283.stderr +++ b/src/test/ui/issues/issue-60283.stderr @@ -1,33 +1,27 @@ error[E0631]: type mismatch in function arguments --> $DIR/issue-60283.rs:14:5 | -LL | foo((), drop) - | ^^^ - | | - | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` - | found signature of `fn(_) -> _` - | -note: required by `foo` - --> $DIR/issue-60283.rs:9:1 - | LL | / pub fn foo(_: T, _: F) LL | | where T: for<'a> Trait<'a>, LL | | F: for<'a> FnMut(>::Item) {} - | |_________________________________________________^ + | |_________________________________________________- required by `foo` +... +LL | foo((), drop) + | ^^^ + | | + | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` + | found signature of `fn(_) -> _` error[E0271]: type mismatch resolving `for<'a> } as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()` --> $DIR/issue-60283.rs:14:5 | -LL | foo((), drop) - | ^^^ expected bound lifetime parameter 'a, found concrete lifetime - | -note: required by `foo` - --> $DIR/issue-60283.rs:9:1 - | LL | / pub fn foo(_: T, _: F) LL | | where T: for<'a> Trait<'a>, LL | | F: for<'a> FnMut(>::Item) {} - | |_________________________________________________^ + | |_________________________________________________- required by `foo` +... +LL | foo((), drop) + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/iterators/bound.stderr b/src/test/ui/iterators/bound.stderr index 14057387c4f40..92a91ff4cb1ba 100644 --- a/src/test/ui/iterators/bound.stderr +++ b/src/test/ui/iterators/bound.stderr @@ -1,16 +1,13 @@ error[E0277]: `u8` is not an iterator --> $DIR/bound.rs:2:10 | +LL | struct S(I); + | ------------------------- required by `S` LL | struct T(S); | ^^^^^ `u8` is not an iterator | = help: the trait `std::iter::Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` -note: required by `S` - --> $DIR/bound.rs:1:1 - | -LL | struct S(I); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs index f9b6bad7c2552..8a420f7203cac 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.rs @@ -1,3 +1,3 @@ fn main() { - let extern = 0; //~ ERROR expected pattern, found keyword `extern` + let extern = 0; //~ ERROR expected identifier, found keyword `extern` } diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr index d7b9ad2abe97a..73ac113f1b1e0 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-pat.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `extern` +error: expected identifier, found keyword `extern` --> $DIR/keyword-extern-as-identifier-pat.rs:2:9 | LL | let extern = 0; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#extern = 0; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 929a807656209..1fe59460e057f 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -1,138 +1,107 @@ error[E0277]: the trait bound `&'static mut isize: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:27:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::<&'static mut isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'static mut isize` | = help: the following implementations were found: -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `&'a mut isize: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:28:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::<&'a mut isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut isize` | = help: the following implementations were found: -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:31:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:32:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::(); | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::vec::Vec: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:33:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy:: >(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::vec::Vec` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::boxed::Box<&'a mut isize>: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:34:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<&'a mut isize>` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:42:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:43:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `&'a mut (dyn Dummy + std::marker::Send + 'a): std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:46:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut (dyn Dummy + std::marker::Send + 'a)` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `MyNoncopyStruct: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:64:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyNoncopyStruct` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied --> $DIR/kindck-copy.rs:67:5 | +LL | fn assert_copy() { } + | ------------------------ required by `assert_copy` +... LL | assert_copy::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` - | -note: required by `assert_copy` - --> $DIR/kindck-copy.rs:5:1 - | -LL | fn assert_copy() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 11 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.stderr b/src/test/ui/kindck/kindck-impl-type-params-2.stderr index bd971c903727b..6d599423d2548 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params-2.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied --> $DIR/kindck-impl-type-params-2.rs:13:5 | +LL | fn take_param(foo: &T) { } + | ----------------------------- required by `take_param` +... LL | take_param(&x); | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` | = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` -note: required by `take_param` - --> $DIR/kindck-impl-type-params-2.rs:9:1 - | -LL | fn take_param(foo: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.stderr index 1e719e2608425..a53063157fc8e 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:18:5 | +LL | fn take_param(foo: &T) { } + | ----------------------------- required by `take_param` +... LL | take_param(&x); | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` | = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` -note: required by `take_param` - --> $DIR/kindck-inherited-copy-bound.rs:14:1 - | -LL | fn take_param(foo: &T) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:24:19 diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index 2aacd2741d388..6d60de888c98d 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -1,16 +1,14 @@ error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/kindck-nonsendable-1.rs:9:5 | +LL | fn bar(_: F) { } + | ------------------------------- required by `bar` +... LL | bar(move|| foo(x)); | ^^^ `std::rc::Rc` cannot be sent between threads safely | = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` -note: required by `bar` - --> $DIR/kindck-nonsendable-1.rs:5:1 - | -LL | fn bar(_: F) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-object.stderr b/src/test/ui/kindck/kindck-send-object.stderr index c9aadd85a53f2..3ca2d730cbae9 100644 --- a/src/test/ui/kindck/kindck-send-object.stderr +++ b/src/test/ui/kindck/kindck-send-object.stderr @@ -1,31 +1,27 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely --> $DIR/kindck-send-object.rs:12:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` -note: required by `assert_send` - --> $DIR/kindck-send-object.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object.rs:17:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` = note: required because it appears within the type `std::boxed::Box` -note: required by `assert_send` - --> $DIR/kindck-send-object.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.nll.stderr b/src/test/ui/kindck/kindck-send-object1.nll.stderr index 998dc90456f14..c7d18cd8b8bb1 100644 --- a/src/test/ui/kindck/kindck-send-object1.nll.stderr +++ b/src/test/ui/kindck/kindck-send-object1.nll.stderr @@ -1,31 +1,27 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely --> $DIR/kindck-send-object1.rs:10:5 | +LL | fn assert_send() { } + | -------------------------------- required by `assert_send` +... LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` -note: required by `assert_send` - --> $DIR/kindck-send-object1.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely --> $DIR/kindck-send-object1.rs:29:5 | +LL | fn assert_send() { } + | -------------------------------- required by `assert_send` +... LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` -note: required by `assert_send` - --> $DIR/kindck-send-object1.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.stderr b/src/test/ui/kindck/kindck-send-object1.stderr index 757b41ab6cb7e..0f5f7e0890b23 100644 --- a/src/test/ui/kindck/kindck-send-object1.stderr +++ b/src/test/ui/kindck/kindck-send-object1.stderr @@ -1,16 +1,14 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be shared between threads safely --> $DIR/kindck-send-object1.rs:10:5 | +LL | fn assert_send() { } + | -------------------------------- required by `assert_send` +... LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` -note: required by `assert_send` - --> $DIR/kindck-send-object1.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0477]: the type `&'a (dyn Dummy + std::marker::Sync + 'a)` does not fulfill the required lifetime --> $DIR/kindck-send-object1.rs:14:5 @@ -23,17 +21,15 @@ LL | assert_send::<&'a (dyn Dummy + Sync)>(); error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely --> $DIR/kindck-send-object1.rs:29:5 | +LL | fn assert_send() { } + | -------------------------------- required by `assert_send` +... LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` -note: required by `assert_send` - --> $DIR/kindck-send-object1.rs:5:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-send-object2.stderr b/src/test/ui/kindck/kindck-send-object2.stderr index c1c9db9da839a..72cd985cc8639 100644 --- a/src/test/ui/kindck/kindck-send-object2.stderr +++ b/src/test/ui/kindck/kindck-send-object2.stderr @@ -1,31 +1,27 @@ error[E0277]: `(dyn Dummy + 'static)` cannot be shared between threads safely --> $DIR/kindck-send-object2.rs:7:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` -note: required by `assert_send` - --> $DIR/kindck-send-object2.rs:3:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object2.rs:12:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` = note: required because it appears within the type `std::boxed::Box` -note: required by `assert_send` - --> $DIR/kindck-send-object2.rs:3:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-owned.stderr b/src/test/ui/kindck/kindck-send-owned.stderr index 75c757dc54646..ee919f02d6537 100644 --- a/src/test/ui/kindck/kindck-send-owned.stderr +++ b/src/test/ui/kindck/kindck-send-owned.stderr @@ -1,17 +1,15 @@ error[E0277]: `*mut u8` cannot be sent between threads safely --> $DIR/kindck-send-owned.rs:12:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `*mut u8` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<*mut u8>` = note: required because it appears within the type `std::boxed::Box<*mut u8>` -note: required by `assert_send` - --> $DIR/kindck-send-owned.rs:3:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-unsafe.stderr b/src/test/ui/kindck/kindck-send-unsafe.stderr index 2fbb07a0df51a..a87e1c7db2a2e 100644 --- a/src/test/ui/kindck/kindck-send-unsafe.stderr +++ b/src/test/ui/kindck/kindck-send-unsafe.stderr @@ -1,15 +1,13 @@ error[E0277]: `*mut &'a isize` cannot be sent between threads safely --> $DIR/kindck-send-unsafe.rs:6:5 | +LL | fn assert_send() { } + | ------------------------ required by `assert_send` +... LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `*mut &'a isize` -note: required by `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:1 - | -LL | fn assert_send() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lang-item-missing-generator.rs b/src/test/ui/lang-item-missing-generator.rs new file mode 100644 index 0000000000000..0c329542928c5 --- /dev/null +++ b/src/test/ui/lang-item-missing-generator.rs @@ -0,0 +1,19 @@ +// error-pattern: requires `generator` lang_item +#![feature(no_core, lang_items, unboxed_closures)] +#![no_core] + +#[lang = "sized"] pub trait Sized { } + +#[lang = "fn_once"] +#[rustc_paren_sugar] +pub trait FnOnce { + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +pub fn abc() -> impl FnOnce(f32) { + |_| {} +} + +fn main() {} diff --git a/src/test/ui/lang-item-missing-generator.stderr b/src/test/ui/lang-item-missing-generator.stderr new file mode 100644 index 0000000000000..fa13bf0b12719 --- /dev/null +++ b/src/test/ui/lang-item-missing-generator.stderr @@ -0,0 +1,8 @@ +error: requires `generator` lang_item + --> $DIR/lang-item-missing-generator.rs:15:17 + | +LL | pub fn abc() -> impl FnOnce(f32) { + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index 45eeffff7a6ac..e1f4b0b34ebaa 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -1,4 +1,5 @@ #![feature(transparent_enums, transparent_unions)] +#![feature(ptr_internals)] #![deny(improper_ctypes)] #![allow(dead_code)] @@ -44,6 +45,7 @@ extern { fn option_ref(x: Option<&'static u8>); fn option_fn(x: Option); fn nonnull(x: Option>); + fn unique(x: Option>); //~ ERROR enum has no representation hint fn nonzero_u8(x: Option); fn nonzero_u16(x: Option); fn nonzero_u32(x: Option); diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 2a60cd12d9936..20e438606642c 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -1,61 +1,69 @@ error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:38:13 + --> $DIR/lint-ctypes-enum.rs:39:13 | LL | fn uf(x: U); | ^ | note: lint level defined here - --> $DIR/lint-ctypes-enum.rs:2:9 + --> $DIR/lint-ctypes-enum.rs:3:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:8:1 + --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum U { A } | ^^^^^^^^^^^^ error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:39:13 + --> $DIR/lint-ctypes-enum.rs:40:13 | LL | fn bf(x: B); | ^ | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:9:1 + --> $DIR/lint-ctypes-enum.rs:10:1 | LL | enum B { C, D } | ^^^^^^^^^^^^^^^ error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:40:13 + --> $DIR/lint-ctypes-enum.rs:41:13 | LL | fn tf(x: T); | ^ | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum note: type defined here - --> $DIR/lint-ctypes-enum.rs:10:1 + --> $DIR/lint-ctypes-enum.rs:11:1 | LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ +error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint + --> $DIR/lint-ctypes-enum.rs:48:17 + | +LL | fn unique(x: Option>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI - --> $DIR/lint-ctypes-enum.rs:51:23 + --> $DIR/lint-ctypes-enum.rs:53:23 | LL | fn nonzero_u128(x: Option); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI - --> $DIR/lint-ctypes-enum.rs:58:23 + --> $DIR/lint-ctypes-enum.rs:60:23 | LL | fn nonzero_i128(x: Option); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:63:28 + --> $DIR/lint-ctypes-enum.rs:65:28 | LL | fn transparent_union(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +71,7 @@ LL | fn transparent_union(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:65:20 + --> $DIR/lint-ctypes-enum.rs:67:20 | LL | fn repr_rust(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,12 +79,12 @@ LL | fn repr_rust(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:66:20 + --> $DIR/lint-ctypes-enum.rs:68:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/lint/lint-dead-code-const-and-self.rs b/src/test/ui/lint/lint-dead-code-const-and-self.rs new file mode 100644 index 0000000000000..1a7b3f43cda14 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-const-and-self.rs @@ -0,0 +1,35 @@ +// check-pass + +#![deny(dead_code)] + +const TLC: usize = 4; + +trait Tr { fn doit(&self); } + +impl Tr for [usize; TLC] { + fn doit(&self) { + println!("called 4"); + } +} + +struct X; +struct Y; +struct Z; + +trait Foo { + type Ty; + fn foo() -> Self::Ty; +} + +impl Foo for X { + type Ty = Z; + fn foo() -> Self::Ty { + unimplemented!() + } +} + +fn main() { + let s = [0,1,2,3]; + s.doit(); + X::foo(); +} diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs new file mode 100644 index 0000000000000..15b04496ba7b1 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum-pub.rs @@ -0,0 +1,6 @@ +// build-pass +#![deny(unused)] + +pub enum E {} + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs b/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs new file mode 100644 index 0000000000000..834681d77e613 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum.rs @@ -0,0 +1,5 @@ +#![deny(unused)] + +enum E {} //~ ERROR enum is never used + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr b/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr new file mode 100644 index 0000000000000..4e3bebfc48bde --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-empty-unused-enum.stderr @@ -0,0 +1,15 @@ +error: enum is never used: `E` + --> $DIR/lint-dead-code-empty-unused-enum.rs:3:1 + | +LL | enum E {} + | ^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-empty-unused-enum.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-dead-code-unused-enum.rs b/src/test/ui/lint/lint-dead-code-unused-enum.rs new file mode 100644 index 0000000000000..e57fac259c5d5 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-enum.rs @@ -0,0 +1,11 @@ +#![deny(unused)] + +struct F; //~ ERROR struct is never constructed +struct B; //~ ERROR struct is never constructed + +enum E { //~ ERROR enum is never used + Foo(F), + Bar(B), +} + +fn main() {} diff --git a/src/test/ui/lint/lint-dead-code-unused-enum.stderr b/src/test/ui/lint/lint-dead-code-unused-enum.stderr new file mode 100644 index 0000000000000..ea711e7b05ee6 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-enum.stderr @@ -0,0 +1,27 @@ +error: struct is never constructed: `F` + --> $DIR/lint-dead-code-unused-enum.rs:3:1 + | +LL | struct F; + | ^^^^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-unused-enum.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: struct is never constructed: `B` + --> $DIR/lint-dead-code-unused-enum.rs:4:1 + | +LL | struct B; + | ^^^^^^^^^ + +error: enum is never used: `E` + --> $DIR/lint-dead-code-unused-enum.rs:6:1 + | +LL | enum E { + | ^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs new file mode 100644 index 0000000000000..3a9061340eb81 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant-pub.rs @@ -0,0 +1,14 @@ +// build-pass +#![deny(unused)] + +pub struct F; +pub struct B; + +pub enum E { + Foo(F), + Bar(B), +} + +fn main() { + let _ = E::Foo(F); +} diff --git a/src/test/ui/lint/lint-dead-code-unused-variant.rs b/src/test/ui/lint/lint-dead-code-unused-variant.rs new file mode 100644 index 0000000000000..69ab29042e5a4 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant.rs @@ -0,0 +1,13 @@ +#![deny(unused)] + +struct F; +struct B; + +enum E { + Foo(F), + Bar(B), //~ ERROR variant is never constructed +} + +fn main() { + let _ = E::Foo(F); +} diff --git a/src/test/ui/lint/lint-dead-code-unused-variant.stderr b/src/test/ui/lint/lint-dead-code-unused-variant.stderr new file mode 100644 index 0000000000000..919996ec30020 --- /dev/null +++ b/src/test/ui/lint/lint-dead-code-unused-variant.stderr @@ -0,0 +1,15 @@ +error: variant is never constructed: `Bar` + --> $DIR/lint-dead-code-unused-variant.rs:8:5 + | +LL | Bar(B), + | ^^^^^^ + | +note: lint level defined here + --> $DIR/lint-dead-code-unused-variant.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(dead_code)]` implied by `#[deny(unused)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index 8132a66df8a0f..62380135b333b 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -67,14 +67,14 @@ LL | deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:57:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:59:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct': text --> $DIR/lint-stability-deprecated.rs:106:17 @@ -181,14 +181,14 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:155:9 | -LL | Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Trait::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:157:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedTrait': text --> $DIR/lint-stability-deprecated.rs:185:10 @@ -421,20 +421,20 @@ LL | ::trait_deprecated_unstable(&foo); warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:53:13 | -LL | foo.method_deprecated_unstable_text(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... foo.method_deprecated_unstable_text(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:54:9 | -LL | Foo::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... Foo::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:55:9 | -LL | ::method_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::method_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:56:13 @@ -445,8 +445,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:58:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text --> $DIR/lint-stability-deprecated.rs:107:13 @@ -505,8 +505,8 @@ LL | foo.trait_deprecated_unstable_text(); warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text --> $DIR/lint-stability-deprecated.rs:156:9 | -LL | ::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ... ::trait_deprecated_unstable_text(&foo); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text --> $DIR/lint-stability-deprecated.rs:173:13 diff --git a/src/test/ui/lto-duplicate-symbols.stderr b/src/test/ui/lto-duplicate-symbols.stderr index 5760cb9a8fdb6..b7a930b61cc96 100644 --- a/src/test/ui/lto-duplicate-symbols.stderr +++ b/src/test/ui/lto-duplicate-symbols.stderr @@ -1,6 +1,6 @@ warning: Linking globals named 'foo': symbol multiply defined! -error: failed to load bc of "lto_duplicate_symbols1.3a1fbbbh-cgu.0": +error: failed to load bc of "lto_duplicate_symbols2.3a1fbbbh-cgu.0": error: aborting due to previous error diff --git a/src/test/ui/macros/auxiliary/proc_macro_sequence.rs b/src/test/ui/macros/auxiliary/proc_macro_sequence.rs index b50ed7ca92ad5..c460db36f1aa3 100644 --- a/src/test/ui/macros/auxiliary/proc_macro_sequence.rs +++ b/src/test/ui/macros/auxiliary/proc_macro_sequence.rs @@ -6,7 +6,7 @@ extern crate proc_macro; -use proc_macro::{quote, Span, TokenStream}; +use proc_macro::{quote, Span, TokenStream, TokenTree}; fn assert_same_span(a: Span, b: Span) { assert_eq!(a.start(), b.start()); @@ -24,12 +24,22 @@ pub fn make_foo(_: TokenStream) -> TokenStream { }; // Check that all spans are equal. - let mut span = None; + // FIXME: `quote!` gives def-site spans to idents and literals, + // but leaves (default) call-site spans on groups and punctuation. + let mut span_call = None; + let mut span_def = None; for tt in result.clone() { - match span { - None => span = Some(tt.span()), - Some(span) => assert_same_span(tt.span(), span), + match tt { + TokenTree::Ident(..) | TokenTree::Literal(..) => match span_def { + None => span_def = Some(tt.span()), + Some(span) => assert_same_span(tt.span(), span), + } + TokenTree::Punct(..) | TokenTree::Group(..) => match span_call { + None => span_call = Some(tt.span()), + Some(span) => assert_same_span(tt.span(), span), + } } + } result diff --git a/src/test/ui/macros/derive-in-eager-expansion-hang.stderr b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr index 1ef9427666bc5..5ca4088e585db 100644 --- a/src/test/ui/macros/derive-in-eager-expansion-hang.stderr +++ b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr @@ -8,6 +8,9 @@ LL | | LL | | "" LL | | } | |_____^ +... +LL | format_args!(hang!()); + | ------- in this macro invocation help: you might be missing a string literal to format with | LL | format_args!("{}", hang!()); diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index a21e4cd201a4f..34529cdaa64f1 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -25,7 +25,7 @@ macro_rules! foo_26444 { } fn test_26444() { - assert_eq!("a , b , c , d , e", foo_26444!(a, b; c; d, e)); + assert_eq!("a, b, c, d, e", foo_26444!(a, b; c; d, e)); assert_eq!("f", foo_26444!(; f ;)); } diff --git a/src/test/ui/macros/macro-in-fn.rs b/src/test/ui/macros/macro-in-fn.rs new file mode 100644 index 0000000000000..d354fe4a7dbfa --- /dev/null +++ b/src/test/ui/macros/macro-in-fn.rs @@ -0,0 +1,8 @@ +// run-pass +#![feature(decl_macro)] + +pub fn moo() { + pub macro ABC() {{}} +} + +fn main() {} diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr index 250773a1853ec..0eef4a2a678b6 100644 --- a/src/test/ui/macros/same-sequence-span.stderr +++ b/src/test/ui/macros/same-sequence-span.stderr @@ -17,11 +17,15 @@ LL | $(= $z:tt)* error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments --> $DIR/same-sequence-span.rs:20:1 | -LL | proc_macro_sequence::make_foo!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | proc_macro_sequence::make_foo!(); + | ^-------------------------------- + | | + | _in this macro invocation | | - | not allowed after `expr` fragments - | in this macro invocation +LL | | +LL | | +LL | | fn main() {} +... | | = note: allowed there are: `=>`, `,` or `;` diff --git a/src/test/ui/malformed/malformed-regressions.stderr b/src/test/ui/malformed/malformed-regressions.stderr index eebb6f0623fbf..164668f562ce0 100644 --- a/src/test/ui/malformed/malformed-regressions.stderr +++ b/src/test/ui/malformed/malformed-regressions.stderr @@ -26,8 +26,7 @@ LL | #[inline = ""] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...")]` +warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...")]` --> $DIR/malformed-regressions.rs:6:1 | LL | #[link] @@ -36,8 +35,7 @@ LL | #[link] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", - /*opt*/ cfg = "...")]` +warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...")]` --> $DIR/malformed-regressions.rs:7:1 | LL | #[link = ""] diff --git a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr index f4a52a65af6aa..4e79fbdeadc5c 100644 --- a/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr +++ b/src/test/ui/marker_trait_attr/overlap-marker-trait.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied --> $DIR/overlap-marker-trait.rs:27:5 | +LL | fn is_marker() { } + | ------------------------- required by `is_marker` +... LL | is_marker::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` - | -note: required by `is_marker` - --> $DIR/overlap-marker-trait.rs:15:1 - | -LL | fn is_marker() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index 8662bb7795382..319eb86480af5 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -1,60 +1,48 @@ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:7:5 | +LL | fn foo(_: F) {} + | -------------------------- required by `foo` +... LL | foo(|_: isize| {}); | ^^^ ---------- found signature of `fn(isize) -> _` | | | expected signature of `fn(usize) -> _` - | -note: required by `foo` - --> $DIR/E0631.rs:3:1 - | -LL | fn foo(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:8:5 | +LL | fn bar>(_: F) {} + | -------------------------- required by `bar` +... LL | bar(|_: isize| {}); | ^^^ ---------- found signature of `fn(isize) -> _` | | | expected signature of `fn(usize) -> _` - | -note: required by `bar` - --> $DIR/E0631.rs:4:1 - | -LL | fn bar>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:9:5 | +LL | fn foo(_: F) {} + | -------------------------- required by `foo` +... LL | fn f(_: u64) {} | ------------ found signature of `fn(u64) -> _` ... LL | foo(f); | ^^^ expected signature of `fn(usize) -> _` - | -note: required by `foo` - --> $DIR/E0631.rs:3:1 - | -LL | fn foo(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:10:5 | +LL | fn bar>(_: F) {} + | -------------------------- required by `bar` +LL | fn main() { LL | fn f(_: u64) {} | ------------ found signature of `fn(u64) -> _` ... LL | bar(f); | ^^^ expected signature of `fn(usize) -> _` - | -note: required by `bar` - --> $DIR/E0631.rs:4:1 - | -LL | fn bar>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 25d5d25ec1deb..b7b5b50b0b4e4 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -45,16 +45,13 @@ LL | [1, 2, 3].sort_by(|tuple, tuple2| panic!()); error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:13:5 | +LL | fn f>(_: F) {} + | ------------------------ required by `f` +... LL | f(|| panic!()); | ^ -- takes 0 arguments | | | expected closure that takes 1 argument - | -note: required by `f` - --> $DIR/closure-arg-count.rs:3:1 - | -LL | fn f>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the closure to take and ignore the expected argument | LL | f(|_| panic!()); @@ -63,16 +60,13 @@ LL | f(|_| panic!()); error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:15:5 | +LL | fn f>(_: F) {} + | ------------------------ required by `f` +... LL | f( move || panic!()); | ^ ---------- takes 0 arguments | | | expected closure that takes 1 argument - | -note: required by `f` - --> $DIR/closure-arg-count.rs:3:1 - | -LL | fn f>(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the closure to take and ignore the expected argument | LL | f( move |_| panic!()); @@ -148,14 +142,10 @@ error[E0593]: function is expected to take 0 arguments, but it takes 1 argument LL | call(Foo); | ^^^^ expected function that takes 0 arguments ... +LL | fn call(_: F) where F: FnOnce() -> R {} + | ------------------------------------------ required by `call` LL | struct Foo(u8); | --------------- takes 1 argument - | -note: required by `call` - --> $DIR/closure-arg-count.rs:42:1 - | -LL | fn call(_: F) where F: FnOnce() -> R {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index d4ccf8d451c12..2a65759dd17f8 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -25,29 +25,23 @@ LL | a.iter().map(|_: (u16, u16)| 45); error[E0631]: type mismatch in function arguments --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | ------------------------------ required by `baz` +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); | ^^^ | | | expected signature of `for<'r> fn(*mut &'r u32) -> _` | found signature of `fn(*mut &'a u32) -> _` - | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 - | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0271]: type mismatch resolving `for<'r> >::Output == ()` --> $DIR/closure-arg-type-mismatch.rs:10:5 | +LL | fn baz(_: F) {} + | ------------------------------ required by `baz` +LL | fn _test<'a>(f: fn(*mut &'a u32)) { LL | baz(f); | ^^^ expected bound lifetime parameter, found concrete lifetime - | -note: required by `baz` - --> $DIR/closure-arg-type-mismatch.rs:8:1 - | -LL | fn baz(_: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index 7161f6979087a..0fe4909eaa778 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -1,30 +1,26 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.rs:8:9: 8:15] as std::ops::FnOnce<(&'r (),)>>::Output == ()` --> $DIR/closure-mismatch.rs:8:5 | +LL | fn baz(_: T) {} + | -------------------- required by `baz` +... LL | baz(|_| ()); | ^^^ expected bound lifetime parameter, found concrete lifetime | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:5:1 - | -LL | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in closure arguments --> $DIR/closure-mismatch.rs:8:5 | +LL | fn baz(_: T) {} + | -------------------- required by `baz` +... LL | baz(|_| ()); | ^^^ ------ found signature of `fn(_) -> _` | | | expected signature of `for<'r> fn(&'r ()) -> _` | = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:8:9: 8:15]` -note: required by `baz` - --> $DIR/closure-mismatch.rs:5:1 - | -LL | fn baz(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/fn-variance-1.stderr b/src/test/ui/mismatched_types/fn-variance-1.stderr index c15d6620e18da..d4db7bda06e7e 100644 --- a/src/test/ui/mismatched_types/fn-variance-1.stderr +++ b/src/test/ui/mismatched_types/fn-variance-1.stderr @@ -3,15 +3,12 @@ error[E0631]: type mismatch in function arguments | LL | fn takes_mut(x: &mut isize) { } | --------------------------- found signature of `for<'r> fn(&'r mut isize) -> _` +LL | +LL | fn apply(t: T, f: F) where F: FnOnce(T) { + | --------------------------------------------- required by `apply` ... LL | apply(&3, takes_mut); | ^^^^^ expected signature of `fn(&{integer}) -> _` - | -note: required by `apply` - --> $DIR/fn-variance-1.rs:5:1 - | -LL | fn apply(t: T, f: F) where F: FnOnce(T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0631]: type mismatch in function arguments --> $DIR/fn-variance-1.rs:15:5 @@ -19,14 +16,11 @@ error[E0631]: type mismatch in function arguments LL | fn takes_imm(x: &isize) { } | ----------------------- found signature of `for<'r> fn(&'r isize) -> _` ... +LL | fn apply(t: T, f: F) where F: FnOnce(T) { + | --------------------------------------------- required by `apply` +... LL | apply(&mut 3, takes_imm); | ^^^^^ expected signature of `fn(&mut {integer}) -> _` - | -note: required by `apply` - --> $DIR/fn-variance-1.rs:5:1 - | -LL | fn apply(t: T, f: F) where F: FnOnce(T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index 47aa3c21f5301..53c9fcd70a23d 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -1,17 +1,14 @@ error[E0631]: type mismatch in closure arguments --> $DIR/unboxed-closures-vtable-mismatch.rs:15:13 | +LL | fn call_itisize>(y: isize, mut f: F) -> isize { + | -------------------------------------------------------------------- required by `call_it` +... LL | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); | ----------------------------- found signature of `fn(usize, isize) -> _` LL | LL | let z = call_it(3, f); | ^^^^^^^ expected signature of `fn(isize, isize) -> _` - | -note: required by `call_it` - --> $DIR/unboxed-closures-vtable-mismatch.rs:7:1 - | -LL | fn call_itisize>(y: isize, mut f: F) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mut/mutable-enum-indirect.stderr b/src/test/ui/mut/mutable-enum-indirect.stderr index 1268e487f333d..4efb10b56290e 100644 --- a/src/test/ui/mut/mutable-enum-indirect.stderr +++ b/src/test/ui/mut/mutable-enum-indirect.stderr @@ -1,17 +1,15 @@ error[E0277]: `NoSync` cannot be shared between threads safely --> $DIR/mutable-enum-indirect.rs:17:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(&x); | ^^^ `NoSync` cannot be shared between threads safely | = help: within `&Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` = note: required because it appears within the type `&Foo` -note: required by `bar` - --> $DIR/mutable-enum-indirect.rs:13:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mutexguard-sync.stderr b/src/test/ui/mutexguard-sync.stderr index d1f7d13937578..4a93c9f09b788 100644 --- a/src/test/ui/mutexguard-sync.stderr +++ b/src/test/ui/mutexguard-sync.stderr @@ -1,16 +1,14 @@ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/mutexguard-sync.rs:11:5 | +LL | fn test_sync(_t: T) {} + | ---------------------------- required by `test_sync` +... LL | test_sync(guard); | ^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` = note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::MutexGuard<'_, std::cell::Cell>` -note: required by `test_sync` - --> $DIR/mutexguard-sync.rs:5:1 - | -LL | fn test_sync(_t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index ef2d0d87f09d5..39aaddb390caa 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -69,530 +69,398 @@ LL | use namespace_mix::xm8::V; error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:33:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m1::S{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::S: Impossible` is not satisfied --> $DIR/namespace-mix.rs:35:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m2::S{}); | ^^^^^ the trait `Impossible` is not implemented for `c::S` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:36:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m2::S); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:39:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm1::S{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::S: Impossible` is not satisfied --> $DIR/namespace-mix.rs:41:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm2::S{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::S` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:42:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm2::S); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:55:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m3::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `fn() -> c::TS {c::TS}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:56:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m3::TS); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::TS: Impossible` is not satisfied --> $DIR/namespace-mix.rs:57:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m4::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `c::TS` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:58:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m4::TS); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:61:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm3::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:62:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm3::TS); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::TS: Impossible` is not satisfied --> $DIR/namespace-mix.rs:63:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm4::TS{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::TS` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:64:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm4::TS); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:77:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m5::US{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:78:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m5::US); | ^^^^^ the trait `Impossible` is not implemented for `c::US` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:79:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m6::US{}); | ^^^^^ the trait `Impossible` is not implemented for `c::US` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:80:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m6::US); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:83:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm5::US{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:84:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm5::US); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:85:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm6::US{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::US` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:86:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm6::US); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:99:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m7::V{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:101:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m8::V{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:102:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m8::V); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:105:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm7::V{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:107:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm8::V{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:108:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm8::V); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:121:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m9::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `fn() -> c::E {c::E::TV}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:122:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(m9::TV); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:123:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mA::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:124:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mA::TV); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:127:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm9::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}: Impossible` is not satisfied --> $DIR/namespace-mix.rs:128:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xm9::TV); | ^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:129:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmA::TV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:130:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmA::TV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:143:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mB::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:144:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mB::UV); | ^^^^^ the trait `Impossible` is not implemented for `c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:145:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mC::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:146:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(mC::UV); | ^^^^^ the trait `Impossible` is not implemented for `c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:149:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmB::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:150:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmB::UV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:151:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmC::UV{}); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::E` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `namespace_mix::c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:152:5 | +LL | fn check(_: T) {} + | ----------------------------- required by `check` +... LL | check(xmC::UV); | ^^^^^ the trait `Impossible` is not implemented for `namespace_mix::c::Item` - | -note: required by `check` - --> $DIR/namespace-mix.rs:21:1 - | -LL | fn check(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 48 previous errors diff --git a/src/test/ui/nll/self-assign-ref-mut.rs b/src/test/ui/nll/self-assign-ref-mut.rs new file mode 100644 index 0000000000000..1ca4cf3a775ca --- /dev/null +++ b/src/test/ui/nll/self-assign-ref-mut.rs @@ -0,0 +1,20 @@ +// Check that `*y` isn't borrowed after `y = y`. + +// check-pass + +fn main() { + let mut x = 1; + { + let mut y = &mut x; + y = y; + y; + } + x; + { + let mut y = &mut x; + y = y; + y = y; + y; + } + x; +} diff --git a/src/test/ui/no_send-enum.stderr b/src/test/ui/no_send-enum.stderr index 71e3aee919431..d1f3398ff9027 100644 --- a/src/test/ui/no_send-enum.stderr +++ b/src/test/ui/no_send-enum.stderr @@ -1,16 +1,14 @@ error[E0277]: `NoSend` cannot be sent between threads safely --> $DIR/no_send-enum.rs:16:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(x); | ^^^ `NoSend` cannot be sent between threads safely | = help: within `Foo`, the trait `std::marker::Send` is not implemented for `NoSend` = note: required because it appears within the type `Foo` -note: required by `bar` - --> $DIR/no_send-enum.rs:12:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no_send-rc.stderr b/src/test/ui/no_send-rc.stderr index 2028cf77374f1..eaf3103060eff 100644 --- a/src/test/ui/no_send-rc.stderr +++ b/src/test/ui/no_send-rc.stderr @@ -1,15 +1,13 @@ error[E0277]: `std::rc::Rc<{integer}>` cannot be sent between threads safely --> $DIR/no_send-rc.rs:7:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(x); | ^^^ `std::rc::Rc<{integer}>` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc<{integer}>` -note: required by `bar` - --> $DIR/no_send-rc.rs:3:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no_send-struct.stderr b/src/test/ui/no_send-struct.stderr index ca4ae054fd0f9..1808cef45f184 100644 --- a/src/test/ui/no_send-struct.stderr +++ b/src/test/ui/no_send-struct.stderr @@ -1,15 +1,13 @@ error[E0277]: `Foo` cannot be sent between threads safely --> $DIR/no_send-struct.rs:15:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(x); | ^^^ `Foo` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `Foo` -note: required by `bar` - --> $DIR/no_send-struct.rs:11:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no_share-enum.stderr b/src/test/ui/no_share-enum.stderr index 64d791d02623e..5a9b7cae0b9f6 100644 --- a/src/test/ui/no_share-enum.stderr +++ b/src/test/ui/no_share-enum.stderr @@ -1,16 +1,14 @@ error[E0277]: `NoSync` cannot be shared between threads safely --> $DIR/no_share-enum.rs:14:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(x); | ^^^ `NoSync` cannot be shared between threads safely | = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` -note: required by `bar` - --> $DIR/no_share-enum.rs:10:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no_share-struct.stderr b/src/test/ui/no_share-struct.stderr index fc4bcfb5b3e7e..c12ee7c5eae85 100644 --- a/src/test/ui/no_share-struct.stderr +++ b/src/test/ui/no_share-struct.stderr @@ -1,15 +1,13 @@ error[E0277]: `Foo` cannot be shared between threads safely --> $DIR/no_share-struct.rs:12:5 | +LL | fn bar(_: T) {} + | --------------------- required by `bar` +... LL | bar(x); | ^^^ `Foo` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `Foo` -note: required by `bar` - --> $DIR/no_share-struct.rs:8:1 - | -LL | fn bar(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/non-interger-atomic.rs b/src/test/ui/non-integer-atomic.rs similarity index 100% rename from src/test/ui/non-interger-atomic.rs rename to src/test/ui/non-integer-atomic.rs diff --git a/src/test/ui/non-interger-atomic.stderr b/src/test/ui/non-integer-atomic.stderr similarity index 83% rename from src/test/ui/non-interger-atomic.stderr rename to src/test/ui/non-integer-atomic.stderr index 7d1130d238e2c..b3cf788d834d8 100644 --- a/src/test/ui/non-interger-atomic.stderr +++ b/src/test/ui/non-integer-atomic.stderr @@ -1,95 +1,95 @@ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `bool` - --> $DIR/non-interger-atomic.rs:13:5 + --> $DIR/non-integer-atomic.rs:13:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `bool` - --> $DIR/non-interger-atomic.rs:18:5 + --> $DIR/non-integer-atomic.rs:18:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `bool` - --> $DIR/non-interger-atomic.rs:23:5 + --> $DIR/non-integer-atomic.rs:23:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `bool` - --> $DIR/non-interger-atomic.rs:28:5 + --> $DIR/non-integer-atomic.rs:28:5 | LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `Foo` - --> $DIR/non-interger-atomic.rs:33:5 + --> $DIR/non-integer-atomic.rs:33:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `Foo` - --> $DIR/non-interger-atomic.rs:38:5 + --> $DIR/non-integer-atomic.rs:38:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `Foo` - --> $DIR/non-interger-atomic.rs:43:5 + --> $DIR/non-integer-atomic.rs:43:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `Foo` - --> $DIR/non-interger-atomic.rs:48:5 + --> $DIR/non-integer-atomic.rs:48:5 | LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` - --> $DIR/non-interger-atomic.rs:53:5 + --> $DIR/non-integer-atomic.rs:53:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` - --> $DIR/non-interger-atomic.rs:58:5 + --> $DIR/non-integer-atomic.rs:58:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` - --> $DIR/non-interger-atomic.rs:63:5 + --> $DIR/non-integer-atomic.rs:63:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` - --> $DIR/non-interger-atomic.rs:68:5 + --> $DIR/non-integer-atomic.rs:68:5 | LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `[u8; 100]` - --> $DIR/non-interger-atomic.rs:73:5 + --> $DIR/non-integer-atomic.rs:73:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `[u8; 100]` - --> $DIR/non-interger-atomic.rs:78:5 + --> $DIR/non-integer-atomic.rs:78:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `[u8; 100]` - --> $DIR/non-interger-atomic.rs:83:5 + --> $DIR/non-integer-atomic.rs:83:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `[u8; 100]` - --> $DIR/non-interger-atomic.rs:88:5 + --> $DIR/non-integer-atomic.rs:88:5 | LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/not-panic/not-panic-safe-2.stderr b/src/test/ui/not-panic/not-panic-safe-2.stderr index 4db127a463932..5bacf0bbc6b45 100644 --- a/src/test/ui/not-panic/not-panic-safe-2.stderr +++ b/src/test/ui/not-panic/not-panic-safe-2.stderr @@ -1,21 +1,22 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` -note: required by `assert` - --> $DIR/not-panic-safe-2.rs:7:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | @@ -23,11 +24,6 @@ LL | assert::>>(); = note: required because it appears within the type `std::cell::Cell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` -note: required by `assert` - --> $DIR/not-panic-safe-2.rs:7:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-3.stderr b/src/test/ui/not-panic/not-panic-safe-3.stderr index 1f87f20f2e284..6d2a450115dff 100644 --- a/src/test/ui/not-panic/not-panic-safe-3.stderr +++ b/src/test/ui/not-panic/not-panic-safe-3.stderr @@ -1,21 +1,22 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` -note: required by `assert` - --> $DIR/not-panic-safe-3.rs:7:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | @@ -23,11 +24,6 @@ LL | assert::>>(); = note: required because it appears within the type `std::cell::Cell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` -note: required by `assert` - --> $DIR/not-panic-safe-3.rs:7:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-4.stderr b/src/test/ui/not-panic/not-panic-safe-4.stderr index 24f649002960c..e28f169b72b6c 100644 --- a/src/test/ui/not-panic/not-panic-safe-4.stderr +++ b/src/test/ui/not-panic/not-panic-safe-4.stderr @@ -1,21 +1,22 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<&RefCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` -note: required by `assert` - --> $DIR/not-panic-safe-4.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<&RefCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | @@ -23,11 +24,6 @@ LL | assert::<&RefCell>(); = note: required because it appears within the type `std::cell::Cell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` -note: required by `assert` - --> $DIR/not-panic-safe-4.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-5.stderr b/src/test/ui/not-panic/not-panic-safe-5.stderr index a603acb2f1fed..f8c4fe68dde7b 100644 --- a/src/test/ui/not-panic/not-panic-safe-5.stderr +++ b/src/test/ui/not-panic/not-panic-safe-5.stderr @@ -1,16 +1,14 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-5.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<*const UnsafeCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*const std::cell::UnsafeCell` -note: required by `assert` - --> $DIR/not-panic-safe-5.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/not-panic/not-panic-safe-6.stderr b/src/test/ui/not-panic/not-panic-safe-6.stderr index a4c75ec7c6188..2cd780590729c 100644 --- a/src/test/ui/not-panic/not-panic-safe-6.stderr +++ b/src/test/ui/not-panic/not-panic-safe-6.stderr @@ -1,21 +1,22 @@ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<*mut RefCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` -note: required by `assert` - --> $DIR/not-panic-safe-6.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<*mut RefCell>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | @@ -23,11 +24,6 @@ LL | assert::<*mut RefCell>(); = note: required because it appears within the type `std::cell::Cell` = note: required because it appears within the type `std::cell::RefCell` = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` -note: required by `assert` - --> $DIR/not-panic-safe-6.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index 2d12e697d5a7a..315ea17971aa9 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -1,15 +1,13 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary --> $DIR/not-panic-safe.rs:9:5 | +LL | fn assert() {} + | ----------------------------------- required by `assert` +... LL | assert::<&mut i32>(); | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32` -note: required by `assert` - --> $DIR/not-panic-safe.rs:6:1 - | -LL | fn assert() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/not-sync.stderr b/src/test/ui/not-sync.stderr index d102528bc6e92..57f1122be2b35 100644 --- a/src/test/ui/not-sync.stderr +++ b/src/test/ui/not-sync.stderr @@ -1,80 +1,68 @@ error[E0277]: `std::cell::Cell` cannot be shared between threads safely --> $DIR/not-sync.rs:8:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::RefCell` cannot be shared between threads safely --> $DIR/not-sync.rs:10:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc` cannot be shared between threads safely --> $DIR/not-sync.rs:13:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^ `std::rc::Rc` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Weak` cannot be shared between threads safely --> $DIR/not-sync.rs:15:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^^^ `std::rc::Weak` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::rc::Weak` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error[E0277]: `std::sync::mpsc::Receiver` cannot be shared between threads safely --> $DIR/not-sync.rs:18:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^^^^^^^ `std::sync::mpsc::Receiver` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error[E0277]: `std::sync::mpsc::Sender` cannot be shared between threads safely --> $DIR/not-sync.rs:20:5 | +LL | fn test() {} + | ------------------ required by `test` +... LL | test::>(); | ^^^^^^^^^^^^^^^^^^^ `std::sync::mpsc::Sender` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender` -note: required by `test` - --> $DIR/not-sync.rs:5:1 - | -LL | fn test() {} - | ^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/object-does-not-impl-trait.stderr b/src/test/ui/object-does-not-impl-trait.stderr index 288ce9682c209..d3add6398bd98 100644 --- a/src/test/ui/object-does-not-impl-trait.stderr +++ b/src/test/ui/object-does-not-impl-trait.stderr @@ -1,14 +1,10 @@ error[E0277]: the trait bound `std::boxed::Box: Foo` is not satisfied --> $DIR/object-does-not-impl-trait.rs:6:35 | +LL | fn take_foo(f: F) {} + | ------------------------ required by `take_foo` LL | fn take_object(f: Box) { take_foo(f); } | ^^^^^^^^ the trait `Foo` is not implemented for `std::boxed::Box` - | -note: required by `take_foo` - --> $DIR/object-does-not-impl-trait.rs:5:1 - | -LL | fn take_foo(f: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr index 5d5db21f7263c..b286265bf01c0 100644 --- a/src/test/ui/on-unimplemented/multiple-impls.stderr +++ b/src/test/ui/on-unimplemented/multiple-impls.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 | +LL | fn index(&self, index: Idx) -> &Self::Output; + | --------------------------------------------- required by `Index::index` +... LL | Index::index(&[] as &[i32], 2u32); | ^^^^^^^^^^^^ trait message | = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:12:5 - | -LL | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/multiple-impls.rs:33:5 @@ -22,15 +20,13 @@ LL | Index::index(&[] as &[i32], 2u32); error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:5 | +LL | fn index(&self, index: Idx) -> &Self::Output; + | --------------------------------------------- required by `Index::index` +... LL | Index::index(&[] as &[i32], Foo(2u32)); | ^^^^^^^^^^^^ on impl for Foo | = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:12:5 - | -LL | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:36:5 @@ -43,15 +39,13 @@ LL | Index::index(&[] as &[i32], Foo(2u32)); error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:5 | +LL | fn index(&self, index: Idx) -> &Self::Output; + | --------------------------------------------- required by `Index::index` +... LL | Index::index(&[] as &[i32], Bar(2u32)); | ^^^^^^^^^^^^ on impl for Bar | = help: the trait `Index>` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/multiple-impls.rs:12:5 - | -LL | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index>` is not satisfied --> $DIR/multiple-impls.rs:39:5 diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr index 79cf22f609c79..78dc9a53761c5 100644 --- a/src/test/ui/on-unimplemented/on-impl.stderr +++ b/src/test/ui/on-unimplemented/on-impl.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:22:5 | +LL | fn index(&self, index: Idx) -> &Self::Output; + | --------------------------------------------- required by `Index::index` +... LL | Index::::index(&[1, 2, 3] as &[i32], 2u32); | ^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice | = help: the trait `Index` is not implemented for `[i32]` -note: required by `Index::index` - --> $DIR/on-impl.rs:9:5 - | -LL | fn index(&self, index: Idx) -> &Self::Output; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `[i32]: Index` is not satisfied --> $DIR/on-impl.rs:22:5 diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index ece8dee0afe97..992f53b1da6b6 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -1,28 +1,24 @@ error[E0277]: the trait bound `std::option::Option>: MyFromIterator<&u8>` is not satisfied --> $DIR/on-trait.rs:28:30 | +LL | fn collect, B: MyFromIterator>(it: I) -> B { + | -------------------------------------------------------------------- required by `collect` +... LL | let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect() | ^^^^^^^ a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` | = help: the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` -note: required by `collect` - --> $DIR/on-trait.rs:22:1 - | -LL | fn collect, B: MyFromIterator>(it: I) -> B { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied --> $DIR/on-trait.rs:31:21 | +LL | fn foobar>() -> T { + | ---------------------------------------------- required by `foobar` +... LL | let x: String = foobar(); | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` | = help: the trait `Bar::Foo` is not implemented for `std::string::String` -note: required by `foobar` - --> $DIR/on-trait.rs:12:1 - | -LL | fn foobar>() -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs new file mode 100644 index 0000000000000..de8e1bba5576c --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + for | A in 0 {} //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/feature-gate/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr similarity index 75% rename from src/test/ui/feature-gate/feature-gate-or_patterns.stderr rename to src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr index aaabb54c1f017..f520409e8bad6 100644 --- a/src/test/ui/feature-gate/feature-gate-or_patterns.stderr +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-for.stderr @@ -1,8 +1,8 @@ error[E0658]: or-patterns syntax is experimental - --> $DIR/feature-gate-or_patterns.rs:5:14 + --> $DIR/feature-gate-or_patterns-leading-for.rs:7:9 | -LL | Some(0 | 1 | 2) => {} - | ^^^^^^^^^ +LL | for | A in 0 {} + | ^ | = note: for more information, see https://github.com/rust-lang/rust/issues/54883 = help: add `#![feature(or_patterns)]` to the crate attributes to enable diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs new file mode 100644 index 0000000000000..a4ea4e25d861e --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.rs @@ -0,0 +1,8 @@ +// Test feature gating for a sole leading `|` in `let`. + +fn main() {} + +#[cfg(FALSE)] +fn gated_leading_vert_in_let() { + let | A; //~ ERROR or-patterns syntax is experimental +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr new file mode 100644 index 0000000000000..30fd6a1a95eff --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns-leading-let.stderr @@ -0,0 +1,12 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns-leading-let.rs:7:9 + | +LL | let | A; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.rs b/src/test/ui/or-patterns/feature-gate-or_patterns.rs new file mode 100644 index 0000000000000..e638838147a4d --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.rs @@ -0,0 +1,52 @@ +fn main() {} + +pub fn example(x: Option) { + match x { + Some(0 | 1 | 2) => {} + //~^ ERROR: or-patterns syntax is experimental + _ => {} + } +} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!((p | q)); //~ ERROR or-patterns syntax is experimental +accept_pat!((p | q,)); //~ ERROR or-patterns syntax is experimental +accept_pat!(TS(p | q)); //~ ERROR or-patterns syntax is experimental +accept_pat!(NS { f: p | q }); //~ ERROR or-patterns syntax is experimental +accept_pat!([p | q]); //~ ERROR or-patterns syntax is experimental + +// Non-macro tests: + +#[cfg(FALSE)] +fn or_patterns() { + // Gated: + + let | A | B; //~ ERROR or-patterns syntax is experimental + let A | B; //~ ERROR or-patterns syntax is experimental + for | A | B in 0 {} //~ ERROR or-patterns syntax is experimental + for A | B in 0 {} //~ ERROR or-patterns syntax is experimental + fn fun((A | B): _) {} //~ ERROR or-patterns syntax is experimental + let _ = |(A | B): u8| (); //~ ERROR or-patterns syntax is experimental + let (A | B); //~ ERROR or-patterns syntax is experimental + let (A | B,); //~ ERROR or-patterns syntax is experimental + let A(B | C); //~ ERROR or-patterns syntax is experimental + let E::V(B | C); //~ ERROR or-patterns syntax is experimental + let S { f1: B | C, f2 }; //~ ERROR or-patterns syntax is experimental + let E::V { f1: B | C, f2 }; //~ ERROR or-patterns syntax is experimental + let [A | B]; //~ ERROR or-patterns syntax is experimental + + // Top level of `while`, `if`, and `match` arms are allowed: + + while let | A = 0 {} + while let A | B = 0 {} + if let | A = 0 {} + if let A | B = 0 {} + match 0 { + | A => {}, + A | B => {}, + } +} diff --git a/src/test/ui/or-patterns/feature-gate-or_patterns.stderr b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr new file mode 100644 index 0000000000000..aae6644dac2e0 --- /dev/null +++ b/src/test/ui/or-patterns/feature-gate-or_patterns.stderr @@ -0,0 +1,174 @@ +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:5:14 + | +LL | Some(0 | 1 | 2) => {} + | ^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:28:11 + | +LL | let | A | B; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:29:9 + | +LL | let A | B; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:30:11 + | +LL | for | A | B in 0 {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:31:9 + | +LL | for A | B in 0 {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:32:13 + | +LL | fn fun((A | B): _) {} + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:33:15 + | +LL | let _ = |(A | B): u8| (); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:34:10 + | +LL | let (A | B); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:35:10 + | +LL | let (A | B,); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:36:11 + | +LL | let A(B | C); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:37:14 + | +LL | let E::V(B | C); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:38:17 + | +LL | let S { f1: B | C, f2 }; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:39:20 + | +LL | let E::V { f1: B | C, f2 }; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:40:10 + | +LL | let [A | B]; + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:16:14 + | +LL | accept_pat!((p | q)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:17:14 + | +LL | accept_pat!((p | q,)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:18:16 + | +LL | accept_pat!(TS(p | q)); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:19:21 + | +LL | accept_pat!(NS { f: p | q }); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error[E0658]: or-patterns syntax is experimental + --> $DIR/feature-gate-or_patterns.rs:20:14 + | +LL | accept_pat!([p | q]); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54883 + = help: add `#![feature(or_patterns)]` to the crate attributes to enable + +error: aborting due to 19 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.fixed b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed new file mode 100644 index 0000000000000..08730fe8b07b7 --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.fixed @@ -0,0 +1,14 @@ +// Test the suggestion to wrap an or-pattern as a function parameter in parens. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +enum E { A, B } +use E::*; + +#[cfg(FALSE)] +fn fun1((A | B): E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.rs b/src/test/ui/or-patterns/fn-param-wrap-parens.rs new file mode 100644 index 0000000000000..ed667e0e66067 --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.rs @@ -0,0 +1,14 @@ +// Test the suggestion to wrap an or-pattern as a function parameter in parens. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +enum E { A, B } +use E::*; + +#[cfg(FALSE)] +fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis diff --git a/src/test/ui/or-patterns/fn-param-wrap-parens.stderr b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr new file mode 100644 index 0000000000000..2c6e4d9838ddc --- /dev/null +++ b/src/test/ui/or-patterns/fn-param-wrap-parens.stderr @@ -0,0 +1,8 @@ +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/fn-param-wrap-parens.rs:14:9 + | +LL | fn fun1(A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + +error: aborting due to previous error + diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.rs b/src/test/ui/or-patterns/multiple-pattern-typo.rs new file mode 100644 index 0000000000000..e308c0adb4eb8 --- /dev/null +++ b/src/test/ui/or-patterns/multiple-pattern-typo.rs @@ -0,0 +1,45 @@ +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash + +fn main() { + let x = 3; + + match x { + 1 | 2 || 3 => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match x { + (1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match (x,) { + (1 | 2 || 3,) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + struct TS(u8); + + match TS(x) { + TS(1 | 2 || 3) => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + struct NS { f: u8 } + + match (NS { f: x }) { + NS { f: 1 | 2 || 3 } => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match [x] { + [1 | 2 || 3] => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } + + match x { + || 1 | 2 | 3 => (), //~ ERROR unexpected token `||` after pattern + _ => (), + } +} diff --git a/src/test/ui/or-patterns/multiple-pattern-typo.stderr b/src/test/ui/or-patterns/multiple-pattern-typo.stderr new file mode 100644 index 0000000000000..c61b5cb208251 --- /dev/null +++ b/src/test/ui/or-patterns/multiple-pattern-typo.stderr @@ -0,0 +1,52 @@ +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:8:15 + | +LL | 1 | 2 || 3 => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:13:16 + | +LL | (1 | 2 || 3) => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:18:16 + | +LL | (1 | 2 || 3,) => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:25:18 + | +LL | TS(1 | 2 || 3) => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:32:23 + | +LL | NS { f: 1 | 2 || 3 } => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:37:16 + | +LL | [1 | 2 || 3] => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +error: unexpected token `||` after pattern + --> $DIR/multiple-pattern-typo.rs:42:9 + | +LL | || 1 | 2 | 3 => (), + | ^^ help: use a single `|` to separate multiple alternative patterns: `|` + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/multiple-pattern-typo.rs:1:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/or-pattern-mismatch.rs b/src/test/ui/or-patterns/or-pattern-mismatch.rs similarity index 100% rename from src/test/ui/or-pattern-mismatch.rs rename to src/test/ui/or-patterns/or-pattern-mismatch.rs diff --git a/src/test/ui/or-pattern-mismatch.stderr b/src/test/ui/or-patterns/or-pattern-mismatch.stderr similarity index 100% rename from src/test/ui/or-pattern-mismatch.stderr rename to src/test/ui/or-patterns/or-pattern-mismatch.stderr diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs new file mode 100644 index 0000000000000..b676ea851a3ba --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.rs @@ -0,0 +1,53 @@ +// Test some cases where or-patterns may ostensibly be allowed but are in fact not. +// This is not a semantic test. We only test parsing. + +#![feature(or_patterns)] +//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!(p | q); //~ ERROR no rules expected the token `|` +accept_pat!(| p | q); //~ ERROR no rules expected the token `|` + +// Non-macro tests: + +enum E { A, B } +use E::*; + +fn no_top_level_or_patterns() { + // We do *not* allow or-patterns at the top level of lambdas... + let _ = |A | B: E| (); //~ ERROR binary operation `|` cannot be applied to type `E` + // -------- This looks like an or-pattern but is in fact `|A| (B: E | ())`. + + // ...and for now neither do we allow or-patterns at the top level of functions. + fn fun1(A | B: E) {} //~ ERROR an or-pattern parameter must be wrapped in parenthesis + + fn fun2(| A | B: E) {} + //~^ ERROR a leading `|` is not allowed in a parameter pattern + //~| ERROR an or-pattern parameter must be wrapped in parenthesis +} + +// We also do not allow a leading `|` when not in a top level position: + +fn no_leading_inner() { + struct TS(E); + struct NS { f: E } + + let ( | A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( | A | B,) = (E::B,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ | A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( | A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: | A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let ( || A | B) = E::A; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ || A | B ] = [E::A]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( || A | B ); //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: || A | B }; //~ ERROR a leading `|` is only allowed in a top-level pattern + + let recovery_witness: String = 0; //~ ERROR mismatched types +} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr new file mode 100644 index 0000000000000..2a3a6abfb7b62 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -0,0 +1,124 @@ +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/or-patterns-syntactic-fail.rs:28:13 + | +LL | fn fun1(A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/or-patterns-syntactic-fail.rs:30:13 + | +LL | fn fun2(| A | B: E) {} + | ^ help: remove the `|` + +error: an or-pattern parameter must be wrapped in parenthesis + --> $DIR/or-patterns-syntactic-fail.rs:30:15 + | +LL | fn fun2(| A | B: E) {} + | ^^^^^ help: wrap the pattern in parenthesis: `(A | B)` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:41:11 + | +LL | let ( | A | B) = E::A; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:42:11 + | +LL | let ( | A | B,) = (E::B,); + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:43:11 + | +LL | let [ | A | B ] = [E::A]; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:44:13 + | +LL | let TS( | A | B ); + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:45:17 + | +LL | let NS { f: | A | B }; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:47:11 + | +LL | let ( || A | B) = E::A; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:48:11 + | +LL | let [ || A | B ] = [E::A]; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:49:13 + | +LL | let TS( || A | B ); + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/or-patterns-syntactic-fail.rs:50:17 + | +LL | let NS { f: || A | B }; + | ^^ help: remove the `||` + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail.rs:14:15 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(p | q); + | ^ no rules expected this token in macro call + +error: no rules expected the token `|` + --> $DIR/or-patterns-syntactic-fail.rs:15:13 + | +LL | macro_rules! accept_pat { + | ----------------------- when calling this macro +... +LL | accept_pat!(| p | q); + | ^ no rules expected this token in macro call + +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/or-patterns-syntactic-fail.rs:4:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0369]: binary operation `|` cannot be applied to type `E` + --> $DIR/or-patterns-syntactic-fail.rs:24:22 + | +LL | let _ = |A | B: E| (); + | ----^ -- () + | | + | E + | + = note: an implementation of `std::ops::BitOr` might be missing for `E` + +error[E0308]: mismatched types + --> $DIR/or-patterns-syntactic-fail.rs:52:36 + | +LL | let recovery_witness: String = 0; + | ^ + | | + | expected struct `std::string::String`, found integer + | help: try using a conversion method: `0.to_string()` + | + = note: expected type `std::string::String` + found type `{integer}` + +error: aborting due to 16 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs new file mode 100644 index 0000000000000..5fe72caf9c1ff --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -0,0 +1,78 @@ +// Here we test all the places `|` is *syntactically* allowed. +// This is not a semantic test. We only test parsing. + +// check-pass + +#![feature(or_patterns)] + +fn main() {} + +// Test the `pat` macro fragment parser: +macro_rules! accept_pat { + ($p:pat) => {} +} + +accept_pat!((p | q)); +accept_pat!((p | q,)); +accept_pat!(TS(p | q)); +accept_pat!(NS { f: p | q }); +accept_pat!([p | q]); + +// Non-macro tests: + +#[cfg(FALSE)] +fn or_patterns() { + // Top level of `let`: + let | A | B; + let A | B; + let A | B: u8; + let A | B = 0; + let A | B: u8 = 0; + + // Top level of `for`: + for | A | B in 0 {} + for A | B in 0 {} + + // Top level of `while`: + while let | A | B = 0 {} + while let A | B = 0 {} + + // Top level of `if`: + if let | A | B = 0 {} + if let A | B = 0 {} + + // Top level of `match` arms: + match 0 { + | A | B => {}, + A | B => {}, + } + + // Functions: + fn fun((A | B): _) {} + + // Lambdas: + let _ = |(A | B): u8| (); + + // Parenthesis and tuple patterns: + let (A | B); + let (A | B,); + + // Tuple struct patterns: + let A(B | C); + let E::V(B | C); + + // Struct patterns: + let S { f1: B | C, f2 }; + let E::V { f1: B | C, f2 }; + + // Slice patterns: + let [A | B, .. | ..]; + + // These bind as `(prefix p) | q` as opposed to `prefix (p | q)`: + let box 0 | 1; // Unstable; we *can* the precedence if we want. + let &0 | 1; + let &mut 0 | 1; + let x @ 0 | 1; + let ref x @ 0 | 1; + let ref mut x @ 0 | 1; +} diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr new file mode 100644 index 0000000000000..3145a2e9f2a6e --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr @@ -0,0 +1,8 @@ +warning: the feature `or_patterns` is incomplete and may cause the compiler to crash + --> $DIR/or-patterns-syntactic-pass.rs:6:12 + | +LL | #![feature(or_patterns)] + | ^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/or-patterns/remove-leading-vert.fixed b/src/test/ui/or-patterns/remove-leading-vert.fixed new file mode 100644 index 0000000000000..e96d76061ac28 --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.fixed @@ -0,0 +1,23 @@ +// Test the suggestion to remove a leading `|`. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +#[cfg(FALSE)] +fn leading_vert() { + fn fun1( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + fn fun2( A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + let ( A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.rs b/src/test/ui/or-patterns/remove-leading-vert.rs new file mode 100644 index 0000000000000..3790b17553fe3 --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.rs @@ -0,0 +1,23 @@ +// Test the suggestion to remove a leading `|`. + +// run-rustfix + +#![feature(or_patterns)] +#![allow(warnings)] + +fn main() {} + +#[cfg(FALSE)] +fn leading_vert() { + fn fun1( | A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + fn fun2( || A: E) {} //~ ERROR a leading `|` is not allowed in a parameter pattern + let ( | A): E; //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( || A): (E); //~ ERROR a leading `|` is only allowed in a top-level pattern + let ( | A,): (E,); //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ | A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let [ || A ]: [E; 1]; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( | A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let TS( || A ): TS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: | A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern + let NS { f: || A }: NS; //~ ERROR a leading `|` is only allowed in a top-level pattern +} diff --git a/src/test/ui/or-patterns/remove-leading-vert.stderr b/src/test/ui/or-patterns/remove-leading-vert.stderr new file mode 100644 index 0000000000000..cbe06f997296a --- /dev/null +++ b/src/test/ui/or-patterns/remove-leading-vert.stderr @@ -0,0 +1,68 @@ +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/remove-leading-vert.rs:12:14 + | +LL | fn fun1( | A: E) {} + | ^ help: remove the `|` + +error: a leading `|` is not allowed in a parameter pattern + --> $DIR/remove-leading-vert.rs:13:14 + | +LL | fn fun2( || A: E) {} + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:14:11 + | +LL | let ( | A): E; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:15:11 + | +LL | let ( || A): (E); + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:16:11 + | +LL | let ( | A,): (E,); + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:17:11 + | +LL | let [ | A ]: [E; 1]; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:18:11 + | +LL | let [ || A ]: [E; 1]; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:19:13 + | +LL | let TS( | A ): TS; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:20:13 + | +LL | let TS( || A ): TS; + | ^^ help: remove the `||` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:21:17 + | +LL | let NS { f: | A }: NS; + | ^ help: remove the `|` + +error: a leading `|` is only allowed in a top-level pattern + --> $DIR/remove-leading-vert.rs:22:17 + | +LL | let NS { f: || A }: NS; + | ^^ help: remove the `||` + +error: aborting due to 11 previous errors + diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs new file mode 100644 index 0000000000000..b9bfb8638b2ce --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.rs @@ -0,0 +1,9 @@ +// Test the parser for the "while parsing this or-pattern..." label here. + +fn main() { + match Some(42) { + Some(42) | .=. => {} //~ ERROR expected pattern, found `.` + //~^ while parsing this or-pattern starting here + //~| NOTE expected pattern + } +} diff --git a/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr new file mode 100644 index 0000000000000..7ad62ff99ee73 --- /dev/null +++ b/src/test/ui/or-patterns/while-parsing-this-or-pattern.stderr @@ -0,0 +1,10 @@ +error: expected pattern, found `.` + --> $DIR/while-parsing-this-or-pattern.rs:5:20 + | +LL | Some(42) | .=. => {} + | -------- ^ expected pattern + | | + | while parsing this or-pattern starting here + +error: aborting due to previous error + diff --git a/src/test/ui/overlap-marker-trait.stderr b/src/test/ui/overlap-marker-trait.stderr index a59af8dcdbcf7..a66e3990e8bd9 100644 --- a/src/test/ui/overlap-marker-trait.stderr +++ b/src/test/ui/overlap-marker-trait.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied --> $DIR/overlap-marker-trait.rs:30:5 | +LL | fn is_marker() { } + | ------------------------- required by `is_marker` +... LL | is_marker::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` - | -note: required by `is_marker` - --> $DIR/overlap-marker-trait.rs:18:1 - | -LL | fn is_marker() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/bad-match.rs b/src/test/ui/parser/bad-match.rs index 79bc7eec3113e..04100d1701ddb 100644 --- a/src/test/ui/parser/bad-match.rs +++ b/src/test/ui/parser/bad-match.rs @@ -1,4 +1,4 @@ fn main() { - let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `x` + let isize x = 5; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `x` match x; } diff --git a/src/test/ui/parser/bad-match.stderr b/src/test/ui/parser/bad-match.stderr index 2f29b978e9c91..d5baaf5e93b35 100644 --- a/src/test/ui/parser/bad-match.stderr +++ b/src/test/ui/parser/bad-match.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `x` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `x` --> $DIR/bad-match.rs:2:13 | LL | let isize x = 5; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/bad-name.stderr b/src/test/ui/parser/bad-name.stderr index 15e61cf06cae9..dce4dabedf5c8 100644 --- a/src/test/ui/parser/bad-name.stderr +++ b/src/test/ui/parser/bad-name.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `.` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/bad-name.rs:4:8 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index f06b951041731..d6efc8be072bd 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -2,29 +2,29 @@ struct S; impl S { fn foo(&self, &str bar) {} - //~^ ERROR expected one of `:` or `@` + //~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : } fn baz(S quux, xyzzy: i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : fn one(i32 a b) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` fn pattern((i32, i32) (a, b)) {} -//~^ ERROR expected `:` +//~^ ERROR expected one of `:` fn fizz(i32) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP if this was a parameter name, give it a type //~| HELP if this is a type, explicitly ignore the parameter name fn missing_colon(quux S) {} -//~^ ERROR expected one of `:` or `@` +//~^ ERROR expected one of `:`, `@` //~| HELP declare the type after the parameter binding //~| SUGGESTION : diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index fb48bd1fe9383..2bda4460031a0 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -1,38 +1,38 @@ -error: expected one of `:` or `@`, found `bar` +error: expected one of `:`, `@`, or `|`, found `bar` --> $DIR/inverted-parameters.rs:4:24 | LL | fn foo(&self, &str bar) {} | -----^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `quux` +error: expected one of `:`, `@`, or `|`, found `quux` --> $DIR/inverted-parameters.rs:10:10 | LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` -error: expected one of `:` or `@`, found `a` +error: expected one of `:`, `@`, or `|`, found `a` --> $DIR/inverted-parameters.rs:15:12 | LL | fn one(i32 a b) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected `:`, found `(` +error: expected one of `:` or `|`, found `(` --> $DIR/inverted-parameters.rs:18:23 | LL | fn pattern((i32, i32) (a, b)) {} - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/inverted-parameters.rs:21:12 | LL | fn fizz(i32) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -44,13 +44,13 @@ help: if this is a type, explicitly ignore the parameter name LL | fn fizz(_: i32) {} | ^^^^^^ -error: expected one of `:` or `@`, found `S` +error: expected one of `:`, `@`, or `|`, found `S` --> $DIR/inverted-parameters.rs:26:23 | LL | fn missing_colon(quux S) {} | -----^ | | | - | | expected one of `:` or `@` here + | | expected one of `:`, `@`, or `|` here | help: declare the type after the parameter binding: `: ` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/issue-22647.rs b/src/test/ui/parser/issue-22647.rs index 25cd7ffce5a97..a6861410682cb 100644 --- a/src/test/ui/parser/issue-22647.rs +++ b/src/test/ui/parser/issue-22647.rs @@ -1,5 +1,5 @@ fn main() { - let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` where F: Fn() -> i32 { let x = f(); diff --git a/src/test/ui/parser/issue-22647.stderr b/src/test/ui/parser/issue-22647.stderr index 2dc56a5eca3a6..4b1ef4f3dfc78 100644 --- a/src/test/ui/parser/issue-22647.stderr +++ b/src/test/ui/parser/issue-22647.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22647.rs:2:15 | LL | let caller = |f: F| - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22712.rs b/src/test/ui/parser/issue-22712.rs index b03d578e3d638..774de9c7e6448 100644 --- a/src/test/ui/parser/issue-22712.rs +++ b/src/test/ui/parser/issue-22712.rs @@ -3,7 +3,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` + let Foo> //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `<` } fn main() {} diff --git a/src/test/ui/parser/issue-22712.stderr b/src/test/ui/parser/issue-22712.stderr index 167eaf962e0f4..d9e83144b367a 100644 --- a/src/test/ui/parser/issue-22712.stderr +++ b/src/test/ui/parser/issue-22712.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `<` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22712.rs:6:12 | LL | let Foo> - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24197.rs b/src/test/ui/parser/issue-24197.rs index 005ff9fa2e0ec..aaf5137461fa6 100644 --- a/src/test/ui/parser/issue-24197.rs +++ b/src/test/ui/parser/issue-24197.rs @@ -1,3 +1,3 @@ fn main() { - let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/issue-24197.stderr b/src/test/ui/parser/issue-24197.stderr index 2dfb31432bc99..24818db622ad4 100644 --- a/src/test/ui/parser/issue-24197.stderr +++ b/src/test/ui/parser/issue-24197.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/issue-24197.rs:2:12 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32501.rs b/src/test/ui/parser/issue-32501.rs index 9c01a5c6d20e3..500242030c655 100644 --- a/src/test/ui/parser/issue-32501.rs +++ b/src/test/ui/parser/issue-32501.rs @@ -4,5 +4,6 @@ fn main() { let _ = 0; let mut b = 0; let mut _b = 0; - let mut _ = 0; //~ ERROR expected identifier, found reserved identifier `_` + let mut _ = 0; + //~^ ERROR `mut` must be followed by a named binding } diff --git a/src/test/ui/parser/issue-32501.stderr b/src/test/ui/parser/issue-32501.stderr index 97efb89593579..d53302449a806 100644 --- a/src/test/ui/parser/issue-32501.stderr +++ b/src/test/ui/parser/issue-32501.stderr @@ -1,8 +1,10 @@ -error: expected identifier, found reserved identifier `_` - --> $DIR/issue-32501.rs:7:13 +error: `mut` must be followed by a named binding + --> $DIR/issue-32501.rs:7:9 | LL | let mut _ = 0; - | ^ expected identifier, found reserved identifier + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33413.rs b/src/test/ui/parser/issue-33413.rs index 2ec86958174a4..22f80a8aae866 100644 --- a/src/test/ui/parser/issue-33413.rs +++ b/src/test/ui/parser/issue-33413.rs @@ -2,7 +2,7 @@ struct S; impl S { fn f(*, a: u8) -> u8 {} - //~^ ERROR expected argument name, found `*` + //~^ ERROR expected parameter name, found `*` } fn main() {} diff --git a/src/test/ui/parser/issue-33413.stderr b/src/test/ui/parser/issue-33413.stderr index f6f096b1b9a44..9e1178e8ac1f3 100644 --- a/src/test/ui/parser/issue-33413.stderr +++ b/src/test/ui/parser/issue-33413.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `*` +error: expected parameter name, found `*` --> $DIR/issue-33413.rs:4:10 | LL | fn f(*, a: u8) -> u8 {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.rs b/src/test/ui/parser/issue-63135.rs index d5f5f1469f35a..a5a8de85466bb 100644 --- a/src/test/ui/parser/issue-63135.rs +++ b/src/test/ui/parser/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 6 previous errors +// error-pattern: aborting due to 5 previous errors fn i(n{...,f # diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index c0286d90af744..a077ad454a9df 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -28,17 +28,11 @@ error: expected `[`, found `}` LL | fn i(n{...,f # | ^ expected `[` -error: expected `:`, found `)` +error: expected one of `:` or `|`, found `)` --> $DIR/issue-63135.rs:3:15 | LL | fn i(n{...,f # - | ^ expected `:` + | ^ expected one of `:` or `|` here -error: expected one of `->`, `where`, or `{`, found `` - --> $DIR/issue-63135.rs:3:15 - | -LL | fn i(n{...,f # - | ^ expected one of `->`, `where`, or `{` here - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/keyword-abstract.rs b/src/test/ui/parser/keyword-abstract.rs index 890802ac134a0..570206575ab07 100644 --- a/src/test/ui/parser/keyword-abstract.rs +++ b/src/test/ui/parser/keyword-abstract.rs @@ -1,3 +1,3 @@ fn main() { - let abstract = (); //~ ERROR expected pattern, found reserved keyword `abstract` + let abstract = (); //~ ERROR expected identifier, found reserved keyword `abstract` } diff --git a/src/test/ui/parser/keyword-abstract.stderr b/src/test/ui/parser/keyword-abstract.stderr index 2c79598a81b18..eb2c810099e16 100644 --- a/src/test/ui/parser/keyword-abstract.stderr +++ b/src/test/ui/parser/keyword-abstract.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `abstract` +error: expected identifier, found reserved keyword `abstract` --> $DIR/keyword-abstract.rs:2:9 | LL | let abstract = (); - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#abstract = (); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-as-as-identifier.rs b/src/test/ui/parser/keyword-as-as-identifier.rs index 23ff259db3048..cd47c8a3907d9 100644 --- a/src/test/ui/parser/keyword-as-as-identifier.rs +++ b/src/test/ui/parser/keyword-as-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py as' fn main() { - let as = "foo"; //~ error: expected pattern, found keyword `as` + let as = "foo"; //~ error: expected identifier, found keyword `as` } diff --git a/src/test/ui/parser/keyword-as-as-identifier.stderr b/src/test/ui/parser/keyword-as-as-identifier.stderr index ef466488ad061..5648652be9bca 100644 --- a/src/test/ui/parser/keyword-as-as-identifier.stderr +++ b/src/test/ui/parser/keyword-as-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `as` +error: expected identifier, found keyword `as` --> $DIR/keyword-as-as-identifier.rs:4:9 | LL | let as = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#as = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-break-as-identifier.rs b/src/test/ui/parser/keyword-break-as-identifier.rs index 5ee111d38c9c3..04b25a7aaf613 100644 --- a/src/test/ui/parser/keyword-break-as-identifier.rs +++ b/src/test/ui/parser/keyword-break-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py break' fn main() { - let break = "foo"; //~ error: expected pattern, found keyword `break` + let break = "foo"; //~ error: expected identifier, found keyword `break` } diff --git a/src/test/ui/parser/keyword-break-as-identifier.stderr b/src/test/ui/parser/keyword-break-as-identifier.stderr index 690bd84221a94..820193db70b0f 100644 --- a/src/test/ui/parser/keyword-break-as-identifier.stderr +++ b/src/test/ui/parser/keyword-break-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `break` +error: expected identifier, found keyword `break` --> $DIR/keyword-break-as-identifier.rs:4:9 | LL | let break = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#break = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-const-as-identifier.rs b/src/test/ui/parser/keyword-const-as-identifier.rs index 48fc142cf64b1..6a2d926bf5796 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.rs +++ b/src/test/ui/parser/keyword-const-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py const' fn main() { - let const = "foo"; //~ error: expected pattern, found keyword `const` + let const = "foo"; //~ error: expected identifier, found keyword `const` } diff --git a/src/test/ui/parser/keyword-const-as-identifier.stderr b/src/test/ui/parser/keyword-const-as-identifier.stderr index 6da47f88d04e3..95b536c99c75a 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.stderr +++ b/src/test/ui/parser/keyword-const-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `const` +error: expected identifier, found keyword `const` --> $DIR/keyword-const-as-identifier.rs:4:9 | LL | let const = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#const = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-continue-as-identifier.rs b/src/test/ui/parser/keyword-continue-as-identifier.rs index 06315a48349ff..cfdd62a2d1bce 100644 --- a/src/test/ui/parser/keyword-continue-as-identifier.rs +++ b/src/test/ui/parser/keyword-continue-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py continue' fn main() { - let continue = "foo"; //~ error: expected pattern, found keyword `continue` + let continue = "foo"; //~ error: expected identifier, found keyword `continue` } diff --git a/src/test/ui/parser/keyword-continue-as-identifier.stderr b/src/test/ui/parser/keyword-continue-as-identifier.stderr index 4b0a659f9ad7e..6b24422a5557e 100644 --- a/src/test/ui/parser/keyword-continue-as-identifier.stderr +++ b/src/test/ui/parser/keyword-continue-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `continue` +error: expected identifier, found keyword `continue` --> $DIR/keyword-continue-as-identifier.rs:4:9 | LL | let continue = "foo"; - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#continue = "foo"; + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-else-as-identifier.rs b/src/test/ui/parser/keyword-else-as-identifier.rs index 0c69105cf9457..f12dac3ff75eb 100644 --- a/src/test/ui/parser/keyword-else-as-identifier.rs +++ b/src/test/ui/parser/keyword-else-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py else' fn main() { - let else = "foo"; //~ error: expected pattern, found keyword `else` + let else = "foo"; //~ error: expected identifier, found keyword `else` } diff --git a/src/test/ui/parser/keyword-else-as-identifier.stderr b/src/test/ui/parser/keyword-else-as-identifier.stderr index bec7b7ba01e12..f28635cd08cd6 100644 --- a/src/test/ui/parser/keyword-else-as-identifier.stderr +++ b/src/test/ui/parser/keyword-else-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `else` +error: expected identifier, found keyword `else` --> $DIR/keyword-else-as-identifier.rs:4:9 | LL | let else = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#else = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-enum-as-identifier.rs b/src/test/ui/parser/keyword-enum-as-identifier.rs index d1675800a2791..fe66230d02830 100644 --- a/src/test/ui/parser/keyword-enum-as-identifier.rs +++ b/src/test/ui/parser/keyword-enum-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py enum' fn main() { - let enum = "foo"; //~ error: expected pattern, found keyword `enum` + let enum = "foo"; //~ error: expected identifier, found keyword `enum` } diff --git a/src/test/ui/parser/keyword-enum-as-identifier.stderr b/src/test/ui/parser/keyword-enum-as-identifier.stderr index 51a834f797c32..fc54dce1b68f4 100644 --- a/src/test/ui/parser/keyword-enum-as-identifier.stderr +++ b/src/test/ui/parser/keyword-enum-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `enum` +error: expected identifier, found keyword `enum` --> $DIR/keyword-enum-as-identifier.rs:4:9 | LL | let enum = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#enum = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-final.rs b/src/test/ui/parser/keyword-final.rs index e1cecd0e8e07a..a79a11032a018 100644 --- a/src/test/ui/parser/keyword-final.rs +++ b/src/test/ui/parser/keyword-final.rs @@ -1,3 +1,3 @@ fn main() { - let final = (); //~ ERROR expected pattern, found reserved keyword `final` + let final = (); //~ ERROR expected identifier, found reserved keyword `final` } diff --git a/src/test/ui/parser/keyword-final.stderr b/src/test/ui/parser/keyword-final.stderr index e8372643be6b7..291710d05cbfd 100644 --- a/src/test/ui/parser/keyword-final.stderr +++ b/src/test/ui/parser/keyword-final.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `final` +error: expected identifier, found reserved keyword `final` --> $DIR/keyword-final.rs:2:9 | LL | let final = (); - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#final = (); + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-fn-as-identifier.rs b/src/test/ui/parser/keyword-fn-as-identifier.rs index bca2d5996a54b..f30e115f7947e 100644 --- a/src/test/ui/parser/keyword-fn-as-identifier.rs +++ b/src/test/ui/parser/keyword-fn-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py fn' fn main() { - let fn = "foo"; //~ error: expected pattern, found keyword `fn` + let fn = "foo"; //~ error: expected identifier, found keyword `fn` } diff --git a/src/test/ui/parser/keyword-fn-as-identifier.stderr b/src/test/ui/parser/keyword-fn-as-identifier.stderr index a071a40a70e0d..692f195b2888d 100644 --- a/src/test/ui/parser/keyword-fn-as-identifier.stderr +++ b/src/test/ui/parser/keyword-fn-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `fn` +error: expected identifier, found keyword `fn` --> $DIR/keyword-fn-as-identifier.rs:4:9 | LL | let fn = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#fn = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-for-as-identifier.rs b/src/test/ui/parser/keyword-for-as-identifier.rs index ce49fd90d9101..9e8a2ad53420c 100644 --- a/src/test/ui/parser/keyword-for-as-identifier.rs +++ b/src/test/ui/parser/keyword-for-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py for' fn main() { - let for = "foo"; //~ error: expected pattern, found keyword `for` + let for = "foo"; //~ error: expected identifier, found keyword `for` } diff --git a/src/test/ui/parser/keyword-for-as-identifier.stderr b/src/test/ui/parser/keyword-for-as-identifier.stderr index 090046cebdc56..bcaf421286e76 100644 --- a/src/test/ui/parser/keyword-for-as-identifier.stderr +++ b/src/test/ui/parser/keyword-for-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `for` +error: expected identifier, found keyword `for` --> $DIR/keyword-for-as-identifier.rs:4:9 | LL | let for = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#for = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-if-as-identifier.rs b/src/test/ui/parser/keyword-if-as-identifier.rs index a1302970689c4..0bd5756afce7f 100644 --- a/src/test/ui/parser/keyword-if-as-identifier.rs +++ b/src/test/ui/parser/keyword-if-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py if' fn main() { - let if = "foo"; //~ error: expected pattern, found keyword `if` + let if = "foo"; //~ error: expected identifier, found keyword `if` } diff --git a/src/test/ui/parser/keyword-if-as-identifier.stderr b/src/test/ui/parser/keyword-if-as-identifier.stderr index 98bfdb46e9770..43fbcd7148a1d 100644 --- a/src/test/ui/parser/keyword-if-as-identifier.stderr +++ b/src/test/ui/parser/keyword-if-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `if` +error: expected identifier, found keyword `if` --> $DIR/keyword-if-as-identifier.rs:4:9 | LL | let if = "foo"; - | ^^ expected pattern + | ^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#if = "foo"; + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-impl-as-identifier.rs b/src/test/ui/parser/keyword-impl-as-identifier.rs index 95a34483ad21a..df529bae07214 100644 --- a/src/test/ui/parser/keyword-impl-as-identifier.rs +++ b/src/test/ui/parser/keyword-impl-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py impl' fn main() { - let impl = "foo"; //~ error: expected pattern, found keyword `impl` + let impl = "foo"; //~ error: expected identifier, found keyword `impl` } diff --git a/src/test/ui/parser/keyword-impl-as-identifier.stderr b/src/test/ui/parser/keyword-impl-as-identifier.stderr index 2672959b7c68e..01886eb45cb6d 100644 --- a/src/test/ui/parser/keyword-impl-as-identifier.stderr +++ b/src/test/ui/parser/keyword-impl-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `impl` +error: expected identifier, found keyword `impl` --> $DIR/keyword-impl-as-identifier.rs:4:9 | LL | let impl = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#impl = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-let-as-identifier.rs b/src/test/ui/parser/keyword-let-as-identifier.rs index 07c0ddf8ce573..9b1183501b28d 100644 --- a/src/test/ui/parser/keyword-let-as-identifier.rs +++ b/src/test/ui/parser/keyword-let-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py let' fn main() { - let let = "foo"; //~ error: expected pattern, found keyword `let` + let let = "foo"; //~ error: expected identifier, found keyword `let` } diff --git a/src/test/ui/parser/keyword-let-as-identifier.stderr b/src/test/ui/parser/keyword-let-as-identifier.stderr index 99dbc0530f3fe..f6c39077be23b 100644 --- a/src/test/ui/parser/keyword-let-as-identifier.stderr +++ b/src/test/ui/parser/keyword-let-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `let` +error: expected identifier, found keyword `let` --> $DIR/keyword-let-as-identifier.rs:4:9 | LL | let let = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#let = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-loop-as-identifier.rs b/src/test/ui/parser/keyword-loop-as-identifier.rs index 8643ffe434505..46914a19be2bd 100644 --- a/src/test/ui/parser/keyword-loop-as-identifier.rs +++ b/src/test/ui/parser/keyword-loop-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py loop' fn main() { - let loop = "foo"; //~ error: expected pattern, found keyword `loop` + let loop = "foo"; //~ error: expected identifier, found keyword `loop` } diff --git a/src/test/ui/parser/keyword-loop-as-identifier.stderr b/src/test/ui/parser/keyword-loop-as-identifier.stderr index 783507eb35cd7..f0c282faa29f1 100644 --- a/src/test/ui/parser/keyword-loop-as-identifier.stderr +++ b/src/test/ui/parser/keyword-loop-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `loop` +error: expected identifier, found keyword `loop` --> $DIR/keyword-loop-as-identifier.rs:4:9 | LL | let loop = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#loop = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-match-as-identifier.rs b/src/test/ui/parser/keyword-match-as-identifier.rs index 8ef6b6810a56b..d3cecb991b8f9 100644 --- a/src/test/ui/parser/keyword-match-as-identifier.rs +++ b/src/test/ui/parser/keyword-match-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py match' fn main() { - let match = "foo"; //~ error: expected pattern, found keyword `match` + let match = "foo"; //~ error: expected identifier, found keyword `match` } diff --git a/src/test/ui/parser/keyword-match-as-identifier.stderr b/src/test/ui/parser/keyword-match-as-identifier.stderr index e56a115c91636..f1f4397d194f0 100644 --- a/src/test/ui/parser/keyword-match-as-identifier.stderr +++ b/src/test/ui/parser/keyword-match-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `match` +error: expected identifier, found keyword `match` --> $DIR/keyword-match-as-identifier.rs:4:9 | LL | let match = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#match = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-mod-as-identifier.rs b/src/test/ui/parser/keyword-mod-as-identifier.rs index 96bcdccf0a096..b9c7b6c78ed6c 100644 --- a/src/test/ui/parser/keyword-mod-as-identifier.rs +++ b/src/test/ui/parser/keyword-mod-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py mod' fn main() { - let mod = "foo"; //~ error: expected pattern, found keyword `mod` + let mod = "foo"; //~ error: expected identifier, found keyword `mod` } diff --git a/src/test/ui/parser/keyword-mod-as-identifier.stderr b/src/test/ui/parser/keyword-mod-as-identifier.stderr index a8be2ceb037d6..65ae3baa8c21d 100644 --- a/src/test/ui/parser/keyword-mod-as-identifier.stderr +++ b/src/test/ui/parser/keyword-mod-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `mod` +error: expected identifier, found keyword `mod` --> $DIR/keyword-mod-as-identifier.rs:4:9 | LL | let mod = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#mod = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-move-as-identifier.rs b/src/test/ui/parser/keyword-move-as-identifier.rs index 2193af530bd7a..65be02e3c70cf 100644 --- a/src/test/ui/parser/keyword-move-as-identifier.rs +++ b/src/test/ui/parser/keyword-move-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py move' fn main() { - let move = "foo"; //~ error: expected pattern, found keyword `move` + let move = "foo"; //~ error: expected identifier, found keyword `move` } diff --git a/src/test/ui/parser/keyword-move-as-identifier.stderr b/src/test/ui/parser/keyword-move-as-identifier.stderr index e0687e27eb585..216f7c931eea7 100644 --- a/src/test/ui/parser/keyword-move-as-identifier.stderr +++ b/src/test/ui/parser/keyword-move-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `move` +error: expected identifier, found keyword `move` --> $DIR/keyword-move-as-identifier.rs:4:9 | LL | let move = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#move = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-override.rs b/src/test/ui/parser/keyword-override.rs index 948a20095f1ea..009bebd7ddba8 100644 --- a/src/test/ui/parser/keyword-override.rs +++ b/src/test/ui/parser/keyword-override.rs @@ -1,3 +1,3 @@ fn main() { - let override = (); //~ ERROR expected pattern, found reserved keyword `override` + let override = (); //~ ERROR expected identifier, found reserved keyword `override` } diff --git a/src/test/ui/parser/keyword-override.stderr b/src/test/ui/parser/keyword-override.stderr index 1bfc6c9b3858d..3183fa510c2d1 100644 --- a/src/test/ui/parser/keyword-override.stderr +++ b/src/test/ui/parser/keyword-override.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `override` +error: expected identifier, found reserved keyword `override` --> $DIR/keyword-override.rs:2:9 | LL | let override = (); - | ^^^^^^^^ expected pattern + | ^^^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#override = (); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-pub-as-identifier.rs b/src/test/ui/parser/keyword-pub-as-identifier.rs index 2ed8cc6b268ca..2b2bb14118d7d 100644 --- a/src/test/ui/parser/keyword-pub-as-identifier.rs +++ b/src/test/ui/parser/keyword-pub-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py pub' fn main() { - let pub = "foo"; //~ error: expected pattern, found keyword `pub` + let pub = "foo"; //~ error: expected identifier, found keyword `pub` } diff --git a/src/test/ui/parser/keyword-pub-as-identifier.stderr b/src/test/ui/parser/keyword-pub-as-identifier.stderr index 526ddcd6ee0ff..f81078b12bd3c 100644 --- a/src/test/ui/parser/keyword-pub-as-identifier.stderr +++ b/src/test/ui/parser/keyword-pub-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `pub` +error: expected identifier, found keyword `pub` --> $DIR/keyword-pub-as-identifier.rs:4:9 | LL | let pub = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#pub = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-return-as-identifier.rs b/src/test/ui/parser/keyword-return-as-identifier.rs index 920931b00f954..e1a2db5e4d82d 100644 --- a/src/test/ui/parser/keyword-return-as-identifier.rs +++ b/src/test/ui/parser/keyword-return-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py return' fn main() { - let return = "foo"; //~ error: expected pattern, found keyword `return` + let return = "foo"; //~ error: expected identifier, found keyword `return` } diff --git a/src/test/ui/parser/keyword-return-as-identifier.stderr b/src/test/ui/parser/keyword-return-as-identifier.stderr index c0156a63fa9d1..8cc4d12fbbb9a 100644 --- a/src/test/ui/parser/keyword-return-as-identifier.stderr +++ b/src/test/ui/parser/keyword-return-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `return` +error: expected identifier, found keyword `return` --> $DIR/keyword-return-as-identifier.rs:4:9 | LL | let return = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#return = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-static-as-identifier.rs b/src/test/ui/parser/keyword-static-as-identifier.rs index 3ccbfccfc9394..423b9854b8aa1 100644 --- a/src/test/ui/parser/keyword-static-as-identifier.rs +++ b/src/test/ui/parser/keyword-static-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py static' fn main() { - let static = "foo"; //~ error: expected pattern, found keyword `static` + let static = "foo"; //~ error: expected identifier, found keyword `static` } diff --git a/src/test/ui/parser/keyword-static-as-identifier.stderr b/src/test/ui/parser/keyword-static-as-identifier.stderr index 00a65977732f8..7d22bc97d66ae 100644 --- a/src/test/ui/parser/keyword-static-as-identifier.stderr +++ b/src/test/ui/parser/keyword-static-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `static` +error: expected identifier, found keyword `static` --> $DIR/keyword-static-as-identifier.rs:4:9 | LL | let static = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#static = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-struct-as-identifier.rs b/src/test/ui/parser/keyword-struct-as-identifier.rs index 69d8f19065533..18cfe11592aed 100644 --- a/src/test/ui/parser/keyword-struct-as-identifier.rs +++ b/src/test/ui/parser/keyword-struct-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py struct' fn main() { - let struct = "foo"; //~ error: expected pattern, found keyword `struct` + let struct = "foo"; //~ error: expected identifier, found keyword `struct` } diff --git a/src/test/ui/parser/keyword-struct-as-identifier.stderr b/src/test/ui/parser/keyword-struct-as-identifier.stderr index b2d6639e72ecb..b109fa6247dcd 100644 --- a/src/test/ui/parser/keyword-struct-as-identifier.stderr +++ b/src/test/ui/parser/keyword-struct-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `struct` +error: expected identifier, found keyword `struct` --> $DIR/keyword-struct-as-identifier.rs:4:9 | LL | let struct = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#struct = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-trait-as-identifier.rs b/src/test/ui/parser/keyword-trait-as-identifier.rs index f62858442d252..67f81167dbdd3 100644 --- a/src/test/ui/parser/keyword-trait-as-identifier.rs +++ b/src/test/ui/parser/keyword-trait-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py trait' fn main() { - let trait = "foo"; //~ error: expected pattern, found keyword `trait` + let trait = "foo"; //~ error: expected identifier, found keyword `trait` } diff --git a/src/test/ui/parser/keyword-trait-as-identifier.stderr b/src/test/ui/parser/keyword-trait-as-identifier.stderr index b31c0df28c008..ccc675cdb3a7c 100644 --- a/src/test/ui/parser/keyword-trait-as-identifier.stderr +++ b/src/test/ui/parser/keyword-trait-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `trait` +error: expected identifier, found keyword `trait` --> $DIR/keyword-trait-as-identifier.rs:4:9 | LL | let trait = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#trait = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs index 13a938b2e0988..4fa37bdb057b7 100644 --- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs +++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.rs @@ -1,5 +1,5 @@ // compile-flags: --edition 2018 fn main() { - let try = "foo"; //~ error: expected pattern, found reserved keyword `try` + let try = "foo"; //~ error: expected identifier, found reserved keyword `try` } diff --git a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr index c342e3a76fbb4..f71b889a30db5 100644 --- a/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr +++ b/src/test/ui/parser/keyword-try-as-identifier-edition2018.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `try` +error: expected identifier, found reserved keyword `try` --> $DIR/keyword-try-as-identifier-edition2018.rs:4:9 | LL | let try = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#try = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-type-as-identifier.rs b/src/test/ui/parser/keyword-type-as-identifier.rs index 992547e6f59c0..04adddf72c6ff 100644 --- a/src/test/ui/parser/keyword-type-as-identifier.rs +++ b/src/test/ui/parser/keyword-type-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py type' fn main() { - let type = "foo"; //~ error: expected pattern, found keyword `type` + let type = "foo"; //~ error: expected identifier, found keyword `type` } diff --git a/src/test/ui/parser/keyword-type-as-identifier.stderr b/src/test/ui/parser/keyword-type-as-identifier.stderr index b749c708d441d..88099d949a829 100644 --- a/src/test/ui/parser/keyword-type-as-identifier.stderr +++ b/src/test/ui/parser/keyword-type-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `type` +error: expected identifier, found keyword `type` --> $DIR/keyword-type-as-identifier.rs:4:9 | LL | let type = "foo"; - | ^^^^ expected pattern + | ^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#type = "foo"; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-typeof.rs b/src/test/ui/parser/keyword-typeof.rs index 4ef102646ef1c..29dc77d276cbd 100644 --- a/src/test/ui/parser/keyword-typeof.rs +++ b/src/test/ui/parser/keyword-typeof.rs @@ -1,3 +1,3 @@ fn main() { - let typeof = (); //~ ERROR expected pattern, found reserved keyword `typeof` + let typeof = (); //~ ERROR expected identifier, found reserved keyword `typeof` } diff --git a/src/test/ui/parser/keyword-typeof.stderr b/src/test/ui/parser/keyword-typeof.stderr index e7b18023e61a9..4a1b63d5c9357 100644 --- a/src/test/ui/parser/keyword-typeof.stderr +++ b/src/test/ui/parser/keyword-typeof.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `typeof` +error: expected identifier, found reserved keyword `typeof` --> $DIR/keyword-typeof.rs:2:9 | LL | let typeof = (); - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#typeof = (); + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.rs b/src/test/ui/parser/keyword-unsafe-as-identifier.rs index adb20ebe48c79..0ff6d188c6480 100644 --- a/src/test/ui/parser/keyword-unsafe-as-identifier.rs +++ b/src/test/ui/parser/keyword-unsafe-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py unsafe' fn main() { - let unsafe = "foo"; //~ error: expected pattern, found keyword `unsafe` + let unsafe = "foo"; //~ error: expected identifier, found keyword `unsafe` } diff --git a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr index 67935ce43ba04..205bb81df405b 100644 --- a/src/test/ui/parser/keyword-unsafe-as-identifier.stderr +++ b/src/test/ui/parser/keyword-unsafe-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `unsafe` +error: expected identifier, found keyword `unsafe` --> $DIR/keyword-unsafe-as-identifier.rs:4:9 | LL | let unsafe = "foo"; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#unsafe = "foo"; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-use-as-identifier.rs b/src/test/ui/parser/keyword-use-as-identifier.rs index 198444bafc5b8..821bedee08832 100644 --- a/src/test/ui/parser/keyword-use-as-identifier.rs +++ b/src/test/ui/parser/keyword-use-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py use' fn main() { - let use = "foo"; //~ error: expected pattern, found keyword `use` + let use = "foo"; //~ error: expected identifier, found keyword `use` } diff --git a/src/test/ui/parser/keyword-use-as-identifier.stderr b/src/test/ui/parser/keyword-use-as-identifier.stderr index 2c69d0a8744a0..85a0492f5735f 100644 --- a/src/test/ui/parser/keyword-use-as-identifier.stderr +++ b/src/test/ui/parser/keyword-use-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `use` +error: expected identifier, found keyword `use` --> $DIR/keyword-use-as-identifier.rs:4:9 | LL | let use = "foo"; - | ^^^ expected pattern + | ^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#use = "foo"; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-where-as-identifier.rs b/src/test/ui/parser/keyword-where-as-identifier.rs index 5624a8fc46038..56301bd20adfd 100644 --- a/src/test/ui/parser/keyword-where-as-identifier.rs +++ b/src/test/ui/parser/keyword-where-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py where' fn main() { - let where = "foo"; //~ error: expected pattern, found keyword `where` + let where = "foo"; //~ error: expected identifier, found keyword `where` } diff --git a/src/test/ui/parser/keyword-where-as-identifier.stderr b/src/test/ui/parser/keyword-where-as-identifier.stderr index fc01183ca046b..b8b8506907636 100644 --- a/src/test/ui/parser/keyword-where-as-identifier.stderr +++ b/src/test/ui/parser/keyword-where-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `where` +error: expected identifier, found keyword `where` --> $DIR/keyword-where-as-identifier.rs:4:9 | LL | let where = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#where = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/keyword-while-as-identifier.rs b/src/test/ui/parser/keyword-while-as-identifier.rs index c0a539d350764..22026d15dcbfb 100644 --- a/src/test/ui/parser/keyword-while-as-identifier.rs +++ b/src/test/ui/parser/keyword-while-as-identifier.rs @@ -1,5 +1,5 @@ // This file was auto-generated using 'src/etc/generate-keyword-tests.py while' fn main() { - let while = "foo"; //~ error: expected pattern, found keyword `while` + let while = "foo"; //~ error: expected identifier, found keyword `while` } diff --git a/src/test/ui/parser/keyword-while-as-identifier.stderr b/src/test/ui/parser/keyword-while-as-identifier.stderr index f72ac87742099..bb0c0ac668a41 100644 --- a/src/test/ui/parser/keyword-while-as-identifier.stderr +++ b/src/test/ui/parser/keyword-while-as-identifier.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found keyword `while` +error: expected identifier, found keyword `while` --> $DIR/keyword-while-as-identifier.rs:4:9 | LL | let while = "foo"; - | ^^^^^ expected pattern + | ^^^^^ expected identifier, found keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#while = "foo"; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/mut-patterns.rs b/src/test/ui/parser/mut-patterns.rs index a5eb48252394f..d46186a0fea0e 100644 --- a/src/test/ui/parser/mut-patterns.rs +++ b/src/test/ui/parser/mut-patterns.rs @@ -1,6 +1,46 @@ // Can't put mut in non-ident pattern +// edition:2018 + +#![feature(box_patterns)] +#![allow(warnings)] + pub fn main() { + let mut _ = 0; //~ ERROR `mut` must be followed by a named binding + let mut (_, _) = (0, 0); //~ ERROR `mut` must be followed by a named binding + + let mut mut x = 0; + //~^ ERROR `mut` on a binding may not be repeated + //~| remove the additional `mut`s + struct Foo { x: isize } - let mut Foo { x: x } = Foo { x: 3 }; //~ ERROR: expected one of `:`, `;`, `=`, or `@`, found `{` + let mut Foo { x: x } = Foo { x: 3 }; + //~^ ERROR `mut` must be attached to each individual binding + //~| add `mut` to each binding + + let mut Foo { x } = Foo { x: 3 }; + //~^ ERROR `mut` must be attached to each individual binding + //~| add `mut` to each binding + + struct r#yield(u8, u8); + let mut mut yield(become, await) = r#yield(0, 0); + //~^ ERROR `mut` on a binding may not be repeated + //~| ERROR `mut` must be attached to each individual binding + //~| ERROR expected identifier, found reserved keyword `yield` + //~| ERROR expected identifier, found reserved keyword `become` + //~| ERROR expected identifier, found reserved keyword `await` + + struct W(T, U); + struct B { f: Box } + let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) + //~^ ERROR `mut` must be attached to each individual binding + = W(0, W(1, W(2, W(3, B { f: Box::new(4u8) })))); + + // Make sure we don't accidentally allow `mut $p` where `$p:pat`. + macro_rules! foo { + ($p:pat) => { + let mut $p = 0; //~ ERROR expected identifier, found `x` + } + } + foo!(x); } diff --git a/src/test/ui/parser/mut-patterns.stderr b/src/test/ui/parser/mut-patterns.stderr index 286956440ec34..18ffaa5255870 100644 --- a/src/test/ui/parser/mut-patterns.stderr +++ b/src/test/ui/parser/mut-patterns.stderr @@ -1,8 +1,101 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `{` - --> $DIR/mut-patterns.rs:5:17 +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:9:9 + | +LL | let mut _ = 0; + | ^^^^^ help: remove the `mut` prefix: `_` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` must be followed by a named binding + --> $DIR/mut-patterns.rs:10:9 + | +LL | let mut (_, _) = (0, 0); + | ^^^^^^^^^^ help: remove the `mut` prefix: `(_, _)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` on a binding may not be repeated + --> $DIR/mut-patterns.rs:12:13 + | +LL | let mut mut x = 0; + | ^^^ help: remove the additional `mut`s + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:17:9 | LL | let mut Foo { x: x } = Foo { x: 3 }; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { x: mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:21:9 + | +LL | let mut Foo { x } = Foo { x: 3 }; + | ^^^^^^^^^^^^^ help: add `mut` to each binding: `Foo { mut x }` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` on a binding may not be repeated + --> $DIR/mut-patterns.rs:26:13 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^ help: remove the additional `mut`s + +error: expected identifier, found reserved keyword `yield` + --> $DIR/mut-patterns.rs:26:17 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut r#yield(become, await) = r#yield(0, 0); + | ^^^^^^^ + +error: expected identifier, found reserved keyword `become` + --> $DIR/mut-patterns.rs:26:23 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut yield(r#become, await) = r#yield(0, 0); + | ^^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/mut-patterns.rs:26:31 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let mut mut yield(become, r#await) = r#yield(0, 0); + | ^^^^^^^ + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:26:9 + | +LL | let mut mut yield(become, await) = r#yield(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: `mut` must be attached to each individual binding + --> $DIR/mut-patterns.rs:35:9 + | +LL | let mut W(mut a, W(b, W(ref c, W(d, B { box f })))) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `W(mut a, W(mut b, W(ref c, W(mut d, B { box mut f }))))` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` + +error: expected identifier, found `x` + --> $DIR/mut-patterns.rs:42:21 + | +LL | let mut $p = 0; + | ^^ expected identifier +... +LL | foo!(x); + | -------- in this macro invocation -error: aborting due to previous error +error: aborting due to 12 previous errors diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.rs b/src/test/ui/parser/omitted-arg-in-item-fn.rs index 5ee9daf464055..49cbc4d6bf40f 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.rs +++ b/src/test/ui/parser/omitted-arg-in-item-fn.rs @@ -1,4 +1,4 @@ -fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` +fn foo(x) { //~ ERROR expected one of `:`, `@`, or `|`, found `)` } fn main() {} diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index e501f235d6d3b..7feb15592c54f 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/omitted-arg-in-item-fn.rs:1:9 | LL | fn foo(x) { - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/parser/pat-lt-bracket-2.rs b/src/test/ui/parser/pat-lt-bracket-2.rs index 6eb01c1c93337..3a778ed14f637 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.rs +++ b/src/test/ui/parser/pat-lt-bracket-2.rs @@ -1,4 +1,4 @@ fn a(B<) {} - //~^ error: expected one of `:` or `@`, found `<` + //~^ error: expected one of `:`, `@`, or `|`, found `<` fn main() {} diff --git a/src/test/ui/parser/pat-lt-bracket-2.stderr b/src/test/ui/parser/pat-lt-bracket-2.stderr index cce1a17e9e8df..dbc8d0f5865c6 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.stderr +++ b/src/test/ui/parser/pat-lt-bracket-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/pat-lt-bracket-2.rs:1:7 | LL | fn a(B<) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-5.rs b/src/test/ui/parser/pat-lt-bracket-5.rs index c4b9dd469f54c..aaece1f6bd9cb 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.rs +++ b/src/test/ui/parser/pat-lt-bracket-5.rs @@ -1,3 +1,3 @@ fn main() { - let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` + let v[0] = v[1]; //~ ERROR expected one of `:`, `;`, `=`, `@`, or `|`, found `[` } diff --git a/src/test/ui/parser/pat-lt-bracket-5.stderr b/src/test/ui/parser/pat-lt-bracket-5.stderr index ce4cc05db19b2..167314dde0650 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.stderr +++ b/src/test/ui/parser/pat-lt-bracket-5.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, `=`, or `@`, found `[` +error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-5.rs:2:10 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, or `@` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-1.rs b/src/test/ui/parser/pat-ranges-1.rs index ce953b2eb2299..1dafb5a07bb5a 100644 --- a/src/test/ui/parser/pat-ranges-1.rs +++ b/src/test/ui/parser/pat-ranges-1.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` + let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, `=`, or `|`, found `..=` } diff --git a/src/test/ui/parser/pat-ranges-1.stderr b/src/test/ui/parser/pat-ranges-1.stderr index 6e0deccab8ca2..4e2c5d28381d8 100644 --- a/src/test/ui/parser/pat-ranges-1.stderr +++ b/src/test/ui/parser/pat-ranges-1.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `..=` +error: expected one of `:`, `;`, `=`, or `|`, found `..=` --> $DIR/pat-ranges-1.rs:4:21 | LL | let macropus!() ..= 11 = 12; - | ^^^ expected one of `:`, `;`, or `=` here + | ^^^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-2.rs b/src/test/ui/parser/pat-ranges-2.rs index 9f736ed328c5c..1593222acca1b 100644 --- a/src/test/ui/parser/pat-ranges-2.rs +++ b/src/test/ui/parser/pat-ranges-2.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` + let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` } diff --git a/src/test/ui/parser/pat-ranges-2.stderr b/src/test/ui/parser/pat-ranges-2.stderr index d180bb429110a..64df56f5a61b1 100644 --- a/src/test/ui/parser/pat-ranges-2.stderr +++ b/src/test/ui/parser/pat-ranges-2.stderr @@ -1,8 +1,8 @@ -error: expected one of `::`, `:`, `;`, or `=`, found `!` +error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` --> $DIR/pat-ranges-2.rs:4:26 | LL | let 10 ..= makropulos!() = 12; - | ^ expected one of `::`, `:`, `;`, or `=` here + | ^ expected one of `::`, `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-3.rs b/src/test/ui/parser/pat-ranges-3.rs index 65da55e3bda8c..8976dcf0d90f9 100644 --- a/src/test/ui/parser/pat-ranges-3.rs +++ b/src/test/ui/parser/pat-ranges-3.rs @@ -1,5 +1,5 @@ // Parsing of range patterns fn main() { - let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` + let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, `=`, or `|`, found `+` } diff --git a/src/test/ui/parser/pat-ranges-3.stderr b/src/test/ui/parser/pat-ranges-3.stderr index aaa85e3c2ddd8..c32c18d98dce7 100644 --- a/src/test/ui/parser/pat-ranges-3.stderr +++ b/src/test/ui/parser/pat-ranges-3.stderr @@ -1,8 +1,8 @@ -error: expected one of `:`, `;`, or `=`, found `+` +error: expected one of `:`, `;`, `=`, or `|`, found `+` --> $DIR/pat-ranges-3.rs:4:19 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, or `=` here + | ^ expected one of `:`, `;`, `=`, or `|` here error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-4.rs b/src/test/ui/parser/pat-ranges-4.rs index 7f4a5f3239e76..61188976b028c 100644 --- a/src/test/ui/parser/pat-ranges-4.rs +++ b/src/test/ui/parser/pat-ranges-4.rs @@ -2,5 +2,5 @@ fn main() { let 10 - 3 ..= 10 = 8; - //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` + //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` } diff --git a/src/test/ui/parser/pat-ranges-4.stderr b/src/test/ui/parser/pat-ranges-4.stderr index 0a1d7a1f6b8ab..53e38bc670beb 100644 --- a/src/test/ui/parser/pat-ranges-4.stderr +++ b/src/test/ui/parser/pat-ranges-4.stderr @@ -1,8 +1,8 @@ -error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` +error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` --> $DIR/pat-ranges-4.rs:4:12 | LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of `...`, `..=`, `..`, `:`, `;`, or `=` here + | ^ expected one of 7 possible tokens here error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-mode.rs b/src/test/ui/parser/removed-syntax-mode.rs index 23851b5f70b37..a438db3b0c18b 100644 --- a/src/test/ui/parser/removed-syntax-mode.rs +++ b/src/test/ui/parser/removed-syntax-mode.rs @@ -1,4 +1,4 @@ fn f(+x: isize) {} -//~^ ERROR expected argument name, found `+` +//~^ ERROR expected parameter name, found `+` fn main() {} diff --git a/src/test/ui/parser/removed-syntax-mode.stderr b/src/test/ui/parser/removed-syntax-mode.stderr index 5e7139d6bfd85..d0393b379f06d 100644 --- a/src/test/ui/parser/removed-syntax-mode.stderr +++ b/src/test/ui/parser/removed-syntax-mode.stderr @@ -1,8 +1,8 @@ -error: expected argument name, found `+` +error: expected parameter name, found `+` --> $DIR/removed-syntax-mode.rs:1:6 | LL | fn f(+x: isize) {} - | ^ expected argument name + | ^ expected parameter name error: aborting due to previous error diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index ec8b3181bc553..284102a6df028 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -1,6 +1,9 @@ error[E0277]: `T` cannot be shared between threads safely --> $DIR/phantom-oibit.rs:21:5 | +LL | fn is_zen(_: T) {} + | ----------------------- required by `is_zen` +... LL | is_zen(x) | ^^^^^^ `T` cannot be shared between threads safely | @@ -9,15 +12,13 @@ LL | is_zen(x) = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` -note: required by `is_zen` - --> $DIR/phantom-oibit.rs:18:1 - | -LL | fn is_zen(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `T` cannot be shared between threads safely --> $DIR/phantom-oibit.rs:26:5 | +LL | fn is_zen(_: T) {} + | ----------------------- required by `is_zen` +... LL | is_zen(x) | ^^^^^^ `T` cannot be shared between threads safely | @@ -27,11 +28,6 @@ LL | is_zen(x) = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` = note: required because it appears within the type `Nested>` -note: required by `is_zen` - --> $DIR/phantom-oibit.rs:18:1 - | -LL | fn is_zen(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/privacy/union-field-privacy-2.rs b/src/test/ui/privacy/union-field-privacy-2.rs index 48279630c6302..c2458f74bc8f9 100644 --- a/src/test/ui/privacy/union-field-privacy-2.rs +++ b/src/test/ui/privacy/union-field-privacy-2.rs @@ -11,5 +11,5 @@ fn main() { let a = u.a; // OK let b = u.b; // OK - let c = u.c; //~ ERROR field `c` of struct `m::U` is private + let c = u.c; //~ ERROR field `c` of union `m::U` is private } diff --git a/src/test/ui/privacy/union-field-privacy-2.stderr b/src/test/ui/privacy/union-field-privacy-2.stderr index df054b8cff8a6..8789178caac26 100644 --- a/src/test/ui/privacy/union-field-privacy-2.stderr +++ b/src/test/ui/privacy/union-field-privacy-2.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `c` of struct `m::U` is private +error[E0616]: field `c` of union `m::U` is private --> $DIR/union-field-privacy-2.rs:14:13 | LL | let c = u.c; diff --git a/src/test/ui/proc-macro/attributes-on-definitions.rs b/src/test/ui/proc-macro/attributes-on-definitions.rs new file mode 100644 index 0000000000000..055781d2c6048 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-definitions.rs @@ -0,0 +1,12 @@ +// check-pass +// aux-build:attributes-on-definitions.rs + +#![forbid(unsafe_code)] + +extern crate attributes_on_definitions; + +attributes_on_definitions::with_attrs!(); +//~^ WARN use of deprecated item +// No errors about the use of unstable and unsafe code inside the macro. + +fn main() {} diff --git a/src/test/ui/proc-macro/attributes-on-definitions.stderr b/src/test/ui/proc-macro/attributes-on-definitions.stderr new file mode 100644 index 0000000000000..c61e043b22971 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-definitions.stderr @@ -0,0 +1,8 @@ +warning: use of deprecated item 'attributes_on_definitions::with_attrs': test + --> $DIR/attributes-on-definitions.rs:8:1 + | +LL | attributes_on_definitions::with_attrs!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs index d81e16d9d2961..f1de3709b166b 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs @@ -17,7 +17,7 @@ pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string);"); + assert_eq!(item.to_string(), "println!(\"{}\", string);"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string)"); + assert_eq!(item.to_string(), "println!(\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs index 0a82cbedd77ce..d2180def5b760 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs @@ -17,7 +17,7 @@ pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string);"); + assert_eq!(item.to_string(), "println!(\"{}\", string);"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\" , string)"); + assert_eq!(item.to_string(), "println!(\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs new file mode 100644 index 0000000000000..93a339840d621 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/attributes-on-definitions.rs @@ -0,0 +1,23 @@ +// force-host +// no-prefer-dynamic + +#![feature(allow_internal_unsafe)] +#![feature(allow_internal_unstable)] + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +#[allow_internal_unstable(proc_macro_internals)] +#[allow_internal_unsafe] +#[deprecated(since = "1.0.0", note = "test")] +pub fn with_attrs(_: TokenStream) -> TokenStream { + " + extern crate proc_macro; + use ::proc_macro::bridge; + + fn contains_unsafe() { unsafe {} } + ".parse().unwrap() +} diff --git a/src/test/ui/proc-macro/derive-helper-configured.rs b/src/test/ui/proc-macro/derive-helper-configured.rs new file mode 100644 index 0000000000000..243cf685e8145 --- /dev/null +++ b/src/test/ui/proc-macro/derive-helper-configured.rs @@ -0,0 +1,18 @@ +// Derive helpers are resolved successfully inside `cfg_attr`. + +// check-pass +// compile-flats:--cfg TRUE +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +#[cfg_attr(TRUE, empty_helper)] +#[derive(Empty)] +#[cfg_attr(TRUE, empty_helper)] +struct S { + #[cfg_attr(TRUE, empty_helper)] + field: u8, +} + +fn main() {} diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.rs b/src/test/ui/proc-macro/derive-helper-shadowing.rs index 59ba1390e1323..21af4093a037d 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.rs +++ b/src/test/ui/proc-macro/derive-helper-shadowing.rs @@ -19,7 +19,8 @@ struct S { struct U; mod inner { - #[empty_helper] //~ ERROR cannot find attribute macro `empty_helper` in this scope + // FIXME No ambiguity, attributes in non-macro positions are not resolved properly + #[empty_helper] struct V; } diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 149f6eef443c1..2ba517ce29ee7 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -1,9 +1,3 @@ -error: cannot find attribute macro `empty_helper` in this scope - --> $DIR/derive-helper-shadowing.rs:22:15 - | -LL | #[empty_helper] - | ^^^^^^^^^^^^ - error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name) --> $DIR/derive-helper-shadowing.rs:8:3 | @@ -22,6 +16,6 @@ LL | use test_macros::empty_attr as empty_helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use `crate::empty_helper` to refer to this attribute macro unambiguously -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0659`. diff --git a/src/test/ui/proc-macro/multispan.stderr b/src/test/ui/proc-macro/multispan.stderr index a0c1f9cd5c05f..e7f705c7feb67 100644 --- a/src/test/ui/proc-macro/multispan.stderr +++ b/src/test/ui/proc-macro/multispan.stderr @@ -1,8 +1,19 @@ error: hello to you, too! - --> $DIR/multispan.rs:14:5 - | -LL | hello!(hi); - | ^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:14:5 + | +LL | hello!(hi); + | ----------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:14:12 @@ -11,10 +22,21 @@ LL | hello!(hi); | ^^ error: hello to you, too! - --> $DIR/multispan.rs:17:5 - | -LL | hello!(hi hi); - | ^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:17:5 + | +LL | hello!(hi hi); + | -------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:17:12 @@ -23,10 +45,21 @@ LL | hello!(hi hi); | ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:20:5 - | -LL | hello!(hi hi hi); - | ^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:20:5 + | +LL | hello!(hi hi hi); + | ----------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:20:12 @@ -35,10 +68,21 @@ LL | hello!(hi hi hi); | ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:23:5 - | -LL | hello!(hi hey hi yo hi beep beep hi hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:23:5 + | +LL | hello!(hi hey hi yo hi beep beep hi hi); + | ---------------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:23:12 @@ -47,10 +91,21 @@ LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^ ^^ ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:24:5 - | -LL | hello!(hi there, hi how are you? hi... hi.); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:24:5 + | +LL | hello!(hi there, hi how are you? hi... hi.); + | -------------------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:24:12 @@ -59,10 +114,21 @@ LL | hello!(hi there, hi how are you? hi... hi.); | ^^ ^^ ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:25:5 - | -LL | hello!(whoah. hi di hi di ho); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:25:5 + | +LL | hello!(whoah. hi di hi di ho); + | ------------------------------ in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:25:19 @@ -71,10 +137,21 @@ LL | hello!(whoah. hi di hi di ho); | ^^ ^^ error: hello to you, too! - --> $DIR/multispan.rs:26:5 - | -LL | hello!(hi good hi and good bye); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/multispan.rs:31:1 + | +LL | / pub fn hello(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | } +LL | | +LL | | TokenStream::new() +LL | | } + | |_^ + | + ::: $DIR/multispan.rs:26:5 + | +LL | hello!(hi good hi and good bye); + | -------------------------------- in this macro invocation | note: found these 'hi's --> $DIR/multispan.rs:26:12 diff --git a/src/test/ui/proc-macro/resolve-error.stderr b/src/test/ui/proc-macro/resolve-error.stderr index 3c9b2baacbd91..2a5f2b883813d 100644 --- a/src/test/ui/proc-macro/resolve-error.stderr +++ b/src/test/ui/proc-macro/resolve-error.stderr @@ -1,32 +1,26 @@ -error: cannot find derive macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:22:10 - | -LL | #[derive(FooWithLongNan)] - | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` - -error: cannot find attribute macro `attr_proc_macra` in this scope - --> $DIR/resolve-error.rs:27:3 +error: cannot find macro `bang_proc_macrp!` in this scope + --> $DIR/resolve-error.rs:56:5 | -LL | #[attr_proc_macra] - | ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro` +LL | bang_proc_macrp!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro` -error: cannot find attribute macro `FooWithLongNan` in this scope - --> $DIR/resolve-error.rs:31:3 +error: cannot find macro `Dlona!` in this scope + --> $DIR/resolve-error.rs:53:5 | -LL | #[FooWithLongNan] - | ^^^^^^^^^^^^^^ +LL | Dlona!(); + | ^^^^^ -error: cannot find derive macro `Dlone` in this scope - --> $DIR/resolve-error.rs:34:10 +error: cannot find macro `attr_proc_macra!` in this scope + --> $DIR/resolve-error.rs:50:5 | -LL | #[derive(Dlone)] - | ^^^^^ help: a derive macro with a similar name exists: `Clone` +LL | attr_proc_macra!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac` -error: cannot find derive macro `Dlona` in this scope - --> $DIR/resolve-error.rs:38:10 +error: cannot find macro `FooWithLongNama!` in this scope + --> $DIR/resolve-error.rs:47:5 | -LL | #[derive(Dlona)] - | ^^^^^ help: a derive macro with a similar name exists: `Clona` +LL | FooWithLongNama!(); + | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam` error: cannot find derive macro `attr_proc_macra` in this scope --> $DIR/resolve-error.rs:42:10 @@ -34,29 +28,35 @@ error: cannot find derive macro `attr_proc_macra` in this scope LL | #[derive(attr_proc_macra)] | ^^^^^^^^^^^^^^^ -error: cannot find macro `FooWithLongNama!` in this scope - --> $DIR/resolve-error.rs:47:5 +error: cannot find derive macro `Dlona` in this scope + --> $DIR/resolve-error.rs:38:10 | -LL | FooWithLongNama!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `FooWithLongNam` +LL | #[derive(Dlona)] + | ^^^^^ help: a derive macro with a similar name exists: `Clona` -error: cannot find macro `attr_proc_macra!` in this scope - --> $DIR/resolve-error.rs:50:5 +error: cannot find derive macro `Dlone` in this scope + --> $DIR/resolve-error.rs:34:10 | -LL | attr_proc_macra!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `attr_proc_mac` +LL | #[derive(Dlone)] + | ^^^^^ help: a derive macro with a similar name exists: `Clone` -error: cannot find macro `Dlona!` in this scope - --> $DIR/resolve-error.rs:53:5 +error: cannot find attribute macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:31:3 | -LL | Dlona!(); - | ^^^^^ +LL | #[FooWithLongNan] + | ^^^^^^^^^^^^^^ -error: cannot find macro `bang_proc_macrp!` in this scope - --> $DIR/resolve-error.rs:56:5 +error: cannot find attribute macro `attr_proc_macra` in this scope + --> $DIR/resolve-error.rs:27:3 | -LL | bang_proc_macrp!(); - | ^^^^^^^^^^^^^^^ help: a macro with a similar name exists: `bang_proc_macro` +LL | #[attr_proc_macra] + | ^^^^^^^^^^^^^^^ help: an attribute macro with a similar name exists: `attr_proc_macro` + +error: cannot find derive macro `FooWithLongNan` in this scope + --> $DIR/resolve-error.rs:22:10 + | +LL | #[derive(FooWithLongNan)] + | ^^^^^^^^^^^^^^ help: a derive macro with a similar name exists: `FooWithLongName` error: aborting due to 10 previous errors diff --git a/src/test/ui/proc-macro/three-equals.stderr b/src/test/ui/proc-macro/three-equals.stderr index 0a6cbe13098a8..0698b0f475424 100644 --- a/src/test/ui/proc-macro/three-equals.stderr +++ b/src/test/ui/proc-macro/three-equals.stderr @@ -1,8 +1,19 @@ error: found 2 equal signs, need exactly 3 - --> $DIR/three-equals.rs:15:5 - | -LL | three_equals!(==); - | ^^^^^^^^^^^^^^^^^^ in this macro invocation + --> $DIR/auxiliary/three-equals.rs:42:1 + | +LL | / pub fn three_equals(input: TokenStream) -> TokenStream { +LL | | if let Err(diag) = parse(input) { +LL | | diag.emit(); +LL | | return TokenStream::new(); +... | +LL | | "3".parse().unwrap() +LL | | } + | |_^ + | + ::: $DIR/three-equals.rs:15:5 + | +LL | three_equals!(==); + | ------------------ in this macro invocation | = help: input must be: `===` diff --git a/src/test/ui/recursion/recursive-requirements.stderr b/src/test/ui/recursion/recursive-requirements.stderr index b3041902acac3..9846c938ba90b 100644 --- a/src/test/ui/recursion/recursive-requirements.stderr +++ b/src/test/ui/recursion/recursive-requirements.stderr @@ -1,20 +1,21 @@ error[E0277]: `*const Bar` cannot be shared between threads safely --> $DIR/recursive-requirements.rs:16:12 | +LL | struct AssertSync(PhantomData); + | ------------------------------------------- required by `AssertSync` +... LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely | = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `*const Bar` = note: required because it appears within the type `Foo` -note: required by `AssertSync` - --> $DIR/recursive-requirements.rs:3:1 - | -LL | struct AssertSync(PhantomData); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*const Foo` cannot be shared between threads safely --> $DIR/recursive-requirements.rs:16:12 | +LL | struct AssertSync(PhantomData); + | ------------------------------------------- required by `AssertSync` +... LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely | @@ -22,11 +23,6 @@ LL | let _: AssertSync = unimplemented!(); = note: required because it appears within the type `Bar` = note: required because it appears within the type `std::marker::PhantomData` = note: required because it appears within the type `Foo` -note: required by `AssertSync` - --> $DIR/recursive-requirements.rs:3:1 - | -LL | struct AssertSync(PhantomData); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-name-undeclared.stderr b/src/test/ui/regions/regions-name-undeclared.stderr index 4840d751f7f57..5f6a48a35f368 100644 --- a/src/test/ui/regions/regions-name-undeclared.stderr +++ b/src/test/ui/regions/regions-name-undeclared.stderr @@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize, error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:42:36 | -LL | &'b isize, - | ^^ undeclared lifetime +LL | ... &'b isize, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'b` --> $DIR/regions-name-undeclared.rs:45:36 | -LL | &'b isize)>, - | ^^ undeclared lifetime +LL | ... &'b isize)>, + | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` --> $DIR/regions-name-undeclared.rs:46:17 diff --git a/src/test/ui/reify-intrinsic.rs b/src/test/ui/reify-intrinsic.rs new file mode 100644 index 0000000000000..09baa059e5567 --- /dev/null +++ b/src/test/ui/reify-intrinsic.rs @@ -0,0 +1,15 @@ +// check-fail + +#![feature(intrinsics)] + +fn a() { + let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + //~^ ERROR cannot coerce +} + +fn b() { + let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + //~^ ERROR casting +} + +fn main() {} diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr new file mode 100644 index 0000000000000..4a1bd77cf7ee9 --- /dev/null +++ b/src/test/ui/reify-intrinsic.stderr @@ -0,0 +1,22 @@ +error[E0308]: cannot coerce intrinsics to function pointers + --> $DIR/reify-intrinsic.rs:6:64 + | +LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + | ^^^^^^^^^^^^^^^^^^^ + | | + | cannot coerce intrinsics to function pointers + | help: use parentheses to call this function: `std::mem::transmute(...)` + | + = note: expected type `unsafe extern "rust-intrinsic" fn(isize) -> usize` + found type `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + +error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid + --> $DIR/reify-intrinsic.rs:11:13 + | +LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0606. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/reserved/reserved-become.rs b/src/test/ui/reserved/reserved-become.rs index 2279a05e6b2db..56645255ee5f6 100644 --- a/src/test/ui/reserved/reserved-become.rs +++ b/src/test/ui/reserved/reserved-become.rs @@ -1,4 +1,4 @@ fn main() { let become = 0; - //~^ ERROR expected pattern, found reserved keyword `become` + //~^ ERROR expected identifier, found reserved keyword `become` } diff --git a/src/test/ui/reserved/reserved-become.stderr b/src/test/ui/reserved/reserved-become.stderr index f9fe78e18b393..3ce9fb33c289e 100644 --- a/src/test/ui/reserved/reserved-become.stderr +++ b/src/test/ui/reserved/reserved-become.stderr @@ -1,8 +1,12 @@ -error: expected pattern, found reserved keyword `become` +error: expected identifier, found reserved keyword `become` --> $DIR/reserved-become.rs:2:9 | LL | let become = 0; - | ^^^^^^ expected pattern + | ^^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | let r#become = 0; + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs index e900ccab4fd83..d71711336b06e 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.rs @@ -3,6 +3,6 @@ #![feature(param_attrs)] trait Trait2015 { fn foo(#[allow(C)] i32); } -//~^ ERROR expected one of `:` or `@`, found `)` +//~^ ERROR expected one of `:`, `@`, or `|`, found `)` fn main() {} diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index d0ed65f288011..26b414e426805 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -1,8 +1,8 @@ -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/param-attrs-2018.rs:5:41 | LL | trait Trait2015 { fn foo(#[allow(C)] i32); } - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.rs b/src/test/ui/self/point-at-arbitrary-self-type-method.rs new file mode 100644 index 0000000000000..0f7deeacad292 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.rs @@ -0,0 +1,9 @@ +struct A; + +impl A { + fn foo(self: Box) {} +} + +fn main() { + A.foo(); //~ ERROR E0599 +} diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr new file mode 100644 index 0000000000000..06dad7caa6735 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `foo` found for type `A` in the current scope + --> $DIR/point-at-arbitrary-self-type-method.rs:8:7 + | +LL | struct A; + | --------- method `foo` not found for this +... +LL | fn foo(self: Box) {} + | --- the method is available for `std::boxed::Box` here +... +LL | A.foo(); + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs new file mode 100644 index 0000000000000..53d992771186f --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.rs @@ -0,0 +1,10 @@ +trait B { fn foo(self: Box); } +struct A; + +impl B for A { + fn foo(self: Box) {} +} + +fn main() { + A.foo() //~ ERROR E0599 +} diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr new file mode 100644 index 0000000000000..90cd3b8074580 --- /dev/null +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -0,0 +1,18 @@ +error[E0599]: no method named `foo` found for type `A` in the current scope + --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7 + | +LL | trait B { fn foo(self: Box); } + | --- the method is available for `std::boxed::Box` here +LL | struct A; + | --------- method `foo` not found for this +... +LL | A.foo() + | ^^^ + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `foo`, perhaps you need to implement it: + candidate #1: `B` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/self/self_type_keyword.rs b/src/test/ui/self/self_type_keyword.rs index 01b3309fcacb1..844f13c2f896a 100644 --- a/src/test/ui/self/self_type_keyword.rs +++ b/src/test/ui/self/self_type_keyword.rs @@ -14,7 +14,8 @@ pub fn main() { ref Self => (), //~^ ERROR expected identifier, found keyword `Self` mut Self => (), - //~^ ERROR expected identifier, found keyword `Self` + //~^ ERROR `mut` must be followed by a named binding + //~| ERROR cannot find unit struct/variant or constant `Self` ref mut Self => (), //~^ ERROR expected identifier, found keyword `Self` Self!() => (), diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index b63de98b8e702..bb631194bf3df 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -10,38 +10,40 @@ error: expected identifier, found keyword `Self` LL | ref Self => (), | ^^^^ expected identifier, found keyword -error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:16:13 +error: `mut` must be followed by a named binding + --> $DIR/self_type_keyword.rs:16:9 | LL | mut Self => (), - | ^^^^ expected identifier, found keyword + | ^^^^^^^^ help: remove the `mut` prefix: `Self` + | + = note: `mut` may be followed by `variable` and `variable @ pattern` error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:18:17 + --> $DIR/self_type_keyword.rs:19:17 | LL | ref mut Self => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:22:15 + --> $DIR/self_type_keyword.rs:23:15 | LL | Foo { Self } => (), | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:28:26 + --> $DIR/self_type_keyword.rs:29:26 | LL | extern crate core as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:33:32 + --> $DIR/self_type_keyword.rs:34:32 | LL | use std::option::Option as Self; | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `Self` - --> $DIR/self_type_keyword.rs:38:11 + --> $DIR/self_type_keyword.rs:39:11 | LL | trait Self {} | ^^^^ expected identifier, found keyword @@ -53,11 +55,21 @@ LL | struct Bar<'Self>; | ^^^^^ error: cannot find macro `Self!` in this scope - --> $DIR/self_type_keyword.rs:20:9 + --> $DIR/self_type_keyword.rs:21:9 | LL | Self!() => (), | ^^^^ +error[E0531]: cannot find unit struct/variant or constant `Self` in this scope + --> $DIR/self_type_keyword.rs:16:13 + | +LL | mut Self => (), + | ^^^^ not found in this scope +help: possible candidate is found in another module, you can import it into scope + | +LL | use foo::Self; + | + error[E0392]: parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12 | @@ -66,6 +78,6 @@ LL | struct Bar<'Self>; | = help: consider removing `'Self` or using a marker such as `std::marker::PhantomData` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/span/issue-29595.stderr b/src/test/ui/span/issue-29595.stderr index 24dfdf8ebc299..1d3e33e4b0503 100644 --- a/src/test/ui/span/issue-29595.stderr +++ b/src/test/ui/span/issue-29595.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `u8: Tr` is not satisfied --> $DIR/issue-29595.rs:6:17 | +LL | const C: Self; + | -------------- required by `Tr::C` +... LL | let a: u8 = Tr::C; | ^^^^^ the trait `Tr` is not implemented for `u8` - | -note: required by `Tr::C` - --> $DIR/issue-29595.rs:2:5 - | -LL | const C: Self; - | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 5dd9895c6e4f4..cc0eccd37a26f 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -1,14 +1,14 @@ -error: expected one of `:` or `@`, found `<` +error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here -error: expected one of `:` or `@`, found `)` +error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 | LL | fn foo(Option, String) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -20,11 +20,11 @@ help: if this is a type, explicitly ignore the parameter name LL | fn foo(Option, _: String) {} | ^^^^^^^^^ -error: expected one of `:` or `@`, found `,` +error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/issue-34264.rs:3:9 | LL | fn bar(x, y: usize) {} - | ^ expected one of `:` or `@` here + | ^ expected one of `:`, `@`, or `|` here | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 04c2870d83297..30c9adb1dce72 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,10 +1,10 @@ error[E0282]: type annotations needed for `std::option::Option<_>` - --> $DIR/issue-42234-unknown-receiver-type.rs:7:5 + --> $DIR/issue-42234-unknown-receiver-type.rs:7:7 | LL | let x: Option<_> = None; | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified LL | x.unwrap().method_that_could_exist_on_some_type(); - | ^^^^^^^^^^ cannot infer type for `T` + | ^^^^^^ cannot infer type for `T` | = note: type must be known at this point diff --git a/src/test/ui/span/type-annotations-needed-expr.rs b/src/test/ui/span/type-annotations-needed-expr.rs new file mode 100644 index 0000000000000..f64dab4d7bc68 --- /dev/null +++ b/src/test/ui/span/type-annotations-needed-expr.rs @@ -0,0 +1,3 @@ +fn main() { + let _ = (vec![1,2,3]).into_iter().sum() as f64; //~ ERROR E0282 +} diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr new file mode 100644 index 0000000000000..e32a542bb7a8c --- /dev/null +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -0,0 +1,11 @@ +error[E0282]: type annotations needed + --> $DIR/type-annotations-needed-expr.rs:2:39 + | +LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; + | ^^^ cannot infer type for `S` + | + = note: type must be known at this point + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/specialization/issue-63716-parse-async.rs b/src/test/ui/specialization/issue-63716-parse-async.rs new file mode 100644 index 0000000000000..c3764ffaab83f --- /dev/null +++ b/src/test/ui/specialization/issue-63716-parse-async.rs @@ -0,0 +1,14 @@ +// Ensure that `default async fn` will parse. +// See issue #63716 for details. + +// check-pass +// edition:2018 + +#![feature(specialization)] + +fn main() {} + +#[cfg(FALSE)] +impl Foo for Bar { + default async fn baz() {} +} diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index beb2272452363..08baa478b8bfa 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -1,16 +1,14 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/str-mut-idx.rs:4:15 | +LL | fn bot() -> T { loop {} } + | ---------------- required by `bot` +... LL | s[1..2] = bot(); | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit -note: required by `bot` - --> $DIR/str-mut-idx.rs:1:1 - | -LL | fn bot() -> T { loop {} } - | ^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/str-mut-idx.rs:4:5 diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr index 70eb2610ea5d2..1c2c205e01c1b 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.stderr +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied --> $DIR/struct-path-alias-bounds.rs:9:13 | +LL | struct S { a: T } + | ------------------ required by `S` +... LL | let s = A { a: NoClone }; | ^ the trait `std::clone::Clone` is not implemented for `NoClone` - | -note: required by `S` - --> $DIR/struct-path-alias-bounds.rs:3:1 - | -LL | struct S { a: T } - | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index b3b879ef9acbe..4a8c99cdef3f5 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -61,17 +61,15 @@ LL | let x: () = foo::<'static>; error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/substs-ppaux.rs:49:5 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- required by `Foo::bar` +... LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str` -note: required by `Foo::bar` - --> $DIR/substs-ppaux.rs:7:5 - | -LL | fn bar<'a, T>() where T: 'a {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index 363018db232d8..3314eb60cdea6 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -61,17 +61,15 @@ LL | let x: () = foo::<'static>; error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/substs-ppaux.rs:49:5 | +LL | fn bar<'a, T>() where T: 'a {} + | --------------------------- required by `Foo::bar` +... LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str` -note: required by `Foo::bar` - --> $DIR/substs-ppaux.rs:7:5 - | -LL | fn bar<'a, T>() where T: 'a {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs new file mode 100644 index 0000000000000..a2d2ba145bc5e --- /dev/null +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs @@ -0,0 +1,10 @@ +// edition:2018 +use std::future::Future; + +async fn foo() {} + +fn bar(f: impl Future) {} + +fn main() { + bar(foo); //~ERROR E0277 +} diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr new file mode 100644 index 0000000000000..3141b1b65f9ba --- /dev/null +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `fn() -> impl std::future::Future {foo}: std::future::Future` is not satisfied + --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:9:5 + | +LL | fn bar(f: impl Future) {} + | --------------------------------- required by `bar` +... +LL | bar(foo); + | ^^^ the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` + | + = help: use parentheses to call the function: `foo()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs new file mode 100644 index 0000000000000..acd149c5854e8 --- /dev/null +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs @@ -0,0 +1,18 @@ +// edition:2018 +trait T { + type O; +} + +struct S; + +impl T for S { + type O = (); +} + +fn foo() -> impl T { S } + +fn bar(f: impl T) {} + +fn main() { + bar(foo); //~ERROR E0277 +} diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr new file mode 100644 index 0000000000000..2cc4653fabe2d --- /dev/null +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `fn() -> impl T {foo}: T` is not satisfied + --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:17:5 + | +LL | fn bar(f: impl T) {} + | ----------------------- required by `bar` +... +LL | bar(foo); + | ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}` + | + = help: use parentheses to call the function: `foo()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs index 9b6b10748172b..dd5af3e344cab 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.rs @@ -42,4 +42,6 @@ fn main() { let _: usize = X::bal; //~ ERROR mismatched types let _: usize = X.ban; //~ ERROR attempted to take value of method let _: usize = X.bal; //~ ERROR attempted to take value of method + let closure = || 42; + let _: usize = closure; //~ ERROR mismatched types } diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 0686b56f97ded..28b331bdbdcbc 100644 --- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -214,7 +214,21 @@ error[E0615]: attempted to take value of method `bal` on type `X` LL | let _: usize = X.bal; | ^^^ help: use parentheses to call the method: `bal()` -error: aborting due to 16 previous errors +error[E0308]: mismatched types + --> $DIR/fn-or-tuple-struct-without-args.rs:46:20 + | +LL | let closure = || 42; + | -- closure defined here +LL | let _: usize = closure; + | ^^^^^^^ + | | + | expected usize, found closure + | help: use parentheses to call this closure: `closure()` + | + = note: expected type `usize` + found type `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:24]` + +error: aborting due to 17 previous errors Some errors have detailed explanations: E0308, E0423, E0615. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed new file mode 100644 index 0000000000000..5109511f95a6b --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +trait Foo {} + +trait Bar { + fn hello(&self) {} +} + +struct S; + +impl Foo for S {} +impl Bar for S {} + +fn test(foo: impl Foo + Bar) { + foo.hello(); //~ ERROR E0599 +} + +fn main() { + test(S); +} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs new file mode 100644 index 0000000000000..cd05b77386192 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.rs @@ -0,0 +1,20 @@ +// run-rustfix + +trait Foo {} + +trait Bar { + fn hello(&self) {} +} + +struct S; + +impl Foo for S {} +impl Bar for S {} + +fn test(foo: impl Foo) { + foo.hello(); //~ ERROR E0599 +} + +fn main() { + test(S); +} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr new file mode 100644 index 0000000000000..48c2503e8eb32 --- /dev/null +++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `hello` found for type `impl Foo` in the current scope + --> $DIR/impl-trait-with-missing-trait-bounds-in-arg.rs:15:9 + | +LL | foo.hello(); + | ^^^^^ + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it: + | +LL | fn test(foo: impl Foo + Bar) { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index 3e28700ce9552..da5aeb63b909a 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `&str: std::convert::From` is not satisfied --> $DIR/into-str.rs:4:5 | +LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} + | ------------------------------------------- required by `foo` +... LL | foo(String::new()); | ^^^ the trait `std::convert::From` is not implemented for `&str` | = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` -note: required by `foo` - --> $DIR/into-str.rs:1:1 - | -LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/mismatched-types-numeric-from.rs b/src/test/ui/suggestions/mismatched-types-numeric-from.rs new file mode 100644 index 0000000000000..56549da9c7358 --- /dev/null +++ b/src/test/ui/suggestions/mismatched-types-numeric-from.rs @@ -0,0 +1,3 @@ +fn main() { + let _: u32 = i32::from(0_u8); //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/mismatched-types-numeric-from.stderr b/src/test/ui/suggestions/mismatched-types-numeric-from.stderr new file mode 100644 index 0000000000000..223b6747322c1 --- /dev/null +++ b/src/test/ui/suggestions/mismatched-types-numeric-from.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/mismatched-types-numeric-from.rs:2:18 + | +LL | let _: u32 = i32::from(0_u8); + | ^^^^^^^^^^^^^^^ expected u32, found i32 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/opaque-type-error.rs b/src/test/ui/suggestions/opaque-type-error.rs new file mode 100644 index 0000000000000..979bb60d48c12 --- /dev/null +++ b/src/test/ui/suggestions/opaque-type-error.rs @@ -0,0 +1,24 @@ +// edition:2018 +use core::future::Future; + +async fn base_thing() -> Result<(), ()> { + Ok(()) +} + +fn thing_one() -> impl Future> { + base_thing() +} + +fn thing_two() -> impl Future> { + base_thing() +} + +async fn thing() -> Result<(), ()> { + if true { + thing_one() + } else { + thing_two() //~ ERROR if and else have incompatible types + }.await +} + +fn main() {} diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr new file mode 100644 index 0000000000000..3c9ea05aeceb2 --- /dev/null +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -0,0 +1,20 @@ +error[E0308]: if and else have incompatible types + --> $DIR/opaque-type-error.rs:20:9 + | +LL | / if true { +LL | | thing_one() + | | ----------- expected because of this +LL | | } else { +LL | | thing_two() + | | ^^^^^^^^^^^ expected opaque type, found a different opaque type +LL | | }.await + | |_____- if and else have incompatible types + | + = note: expected type `impl std::future::Future` (opaque type) + found type `impl std::future::Future` (opaque type) + = note: distinct uses of `impl Trait` result in different opaque types + = help: if both `Future`s have the same `Output` type, consider `.await`ing on both of them + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs new file mode 100644 index 0000000000000..abd9e189a7537 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _: usize = 4; let _: usize = 5; let _: usize = 6; let _: usize = 7; let _: usize = 8; let _: usize = 9; let _: usize = 10; let _: usize = 11; let _: usize = 12; let _: usize = 13; let _: usize = 14; let _: usize = 15; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr new file mode 100644 index 0000000000000..bf1699f5cabbb --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-2.rs:4:311 + | +LL | ...; let _: usize = 14; let _: usize = 15; let _: () = 42; let _: usize = 0; let _: usize = 1; let _: usize = 2; let _: usize = 3; let _:... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs new file mode 100644 index 0000000000000..8d4d1b1627940 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr new file mode 100644 index 0000000000000..b56b1948d9e07 --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-unicode.rs:4:415 + | +LL | ...♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/terminal-width/non-whitespace-trimming.rs new file mode 100644 index 0000000000000..f6c8d345c652e --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/terminal-width/non-whitespace-trimming.stderr new file mode 100644 index 0000000000000..622713eb5f6fc --- /dev/null +++ b/src/test/ui/terminal-width/non-whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming.rs:4:241 + | +LL | ...) = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ()... + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/terminal-width/whitespace-trimming-2.rs new file mode 100644 index 0000000000000..c68f678aab349 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength + +fn foo() -> usize { + () +//~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.stderr b/src/test/ui/terminal-width/whitespace-trimming-2.stderr new file mode 100644 index 0000000000000..38df5a9e9a01f --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming-2.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming-2.rs:4:187 + | +LL | ...-> usize { + | ----- expected `usize` because of return type +LL | ... () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/terminal-width/whitespace-trimming.rs new file mode 100644 index 0000000000000..f747bcf17e0b4 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength + +fn main() { + let _: () = 42; +//~^ ERROR mismatched types +} diff --git a/src/test/ui/terminal-width/whitespace-trimming.stderr b/src/test/ui/terminal-width/whitespace-trimming.stderr new file mode 100644 index 0000000000000..45a804b9f6a46 --- /dev/null +++ b/src/test/ui/terminal-width/whitespace-trimming.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/whitespace-trimming.rs:4:193 + | +LL | ... let _: () = 42; + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/tool-attributes/diagnostic_item.rs b/src/test/ui/tool-attributes/diagnostic_item.rs new file mode 100644 index 0000000000000..1d35422ed6241 --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item.rs @@ -0,0 +1,2 @@ +#[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting +struct Foomp; diff --git a/src/test/ui/tool-attributes/diagnostic_item.stderr b/src/test/ui/tool-attributes/diagnostic_item.stderr new file mode 100644 index 0000000000000..deff4da6b8052 --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item.stderr @@ -0,0 +1,17 @@ +error[E0658]: diagnostic items compiler internal support for linting + --> $DIR/diagnostic_item.rs:1:1 + | +LL | #[rustc_diagnostic_item = "foomp"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable + +error[E0601]: `main` function not found in crate `diagnostic_item` + | + = note: consider adding a `main` function to `$DIR/diagnostic_item.rs` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0601, E0658. +For more information about an error, try `rustc --explain E0601`. diff --git a/src/test/ui/tool-attributes/diagnostic_item2.rs b/src/test/ui/tool-attributes/diagnostic_item2.rs new file mode 100644 index 0000000000000..b32a66b16be18 --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item2.rs @@ -0,0 +1,6 @@ +// check-pass + +#[clippy::diagnostic_item = "mep"] +struct Mep; + +fn main() {} diff --git a/src/test/ui/tool-attributes/diagnostic_item3.rs b/src/test/ui/tool-attributes/diagnostic_item3.rs new file mode 100644 index 0000000000000..c1a236ed1cc32 --- /dev/null +++ b/src/test/ui/tool-attributes/diagnostic_item3.rs @@ -0,0 +1,7 @@ +// check-pass +#![feature(rustc_attrs)] + +#[rustc_diagnostic_item = "foomp"] +struct Foomp; + +fn main() {} diff --git a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr index 972d213ac8f8f..8403b2ebaca10 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr @@ -1,28 +1,24 @@ error[E0277]: `std::rc::Rc` cannot be sent between threads safely --> $DIR/trait-alias-cross-crate.rs:14:5 | +LL | fn use_alias() {} + | --------------------------- required by `use_alias` +... LL | use_alias::>(); | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` -note: required by `use_alias` - --> $DIR/trait-alias-cross-crate.rs:10:1 - | -LL | fn use_alias() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::rc::Rc` cannot be shared between threads safely --> $DIR/trait-alias-cross-crate.rs:14:5 | +LL | fn use_alias() {} + | --------------------------- required by `use_alias` +... LL | use_alias::>(); | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` -note: required by `use_alias` - --> $DIR/trait-alias-cross-crate.rs:10:1 - | -LL | fn use_alias() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr index ee2dd5b24afed..ca6d058471667 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-wf.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr @@ -1,15 +1,12 @@ error[E0277]: the trait bound `T: Foo` is not satisfied --> $DIR/trait-alias-wf.rs:5:1 | +LL | trait A {} + | --------------- required by `A` LL | trait B = A; | ^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` | = help: consider adding a `where T: Foo` bound -note: required by `A` - --> $DIR/trait-alias-wf.rs:4:1 - | -LL | trait A {} - | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-fns.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-fns.stderr index 6fdd2ceaaac9c..3c68d461f80d6 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-fns.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-fns.stderr @@ -1,26 +1,20 @@ error[E0277]: the trait bound `u32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-in-fns.rs:13:1 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | fn explode(x: Foo) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u32` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums-in-fns.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `f32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-in-fns.rs:16:1 | +LL | enum Bar { + | ----------------- required by `Bar` +... LL | fn kaboom(y: Bar) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `f32` - | -note: required by `Bar` - --> $DIR/trait-bounds-on-structs-and-enums-in-fns.rs:7:1 - | -LL | enum Bar { - | ^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-impls.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-impls.stderr index 15441b583cef2..7e8db610fe233 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-impls.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-in-impls.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `u16: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-in-impls.rs:20:6 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | impl PolyTrait> for Struct { | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u16` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums-in-impls.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-locals.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-locals.stderr index cdcfff97bd020..070b7b013e5cc 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-locals.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-locals.stderr @@ -1,26 +1,20 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-locals.rs:15:14 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | let baz: Foo = loop { }; | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums-locals.rs:5:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-locals.rs:10:15 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | let foo = Foo { | ^^^ the trait `Trait` is not implemented for `{integer}` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums-locals.rs:5:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-static.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-static.stderr index b019c2979202f..722f01750cb66 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-static.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-static.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-static.rs:9:11 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | static X: Foo = Foo { | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums-static.rs:5:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr index 9a4cc90f3a5e0..bd76df8071a53 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr @@ -1,89 +1,71 @@ error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:13:9 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | impl Foo { | ^^^^^^ the trait `Trait` is not implemented for `T` | = help: consider adding a `where T: Trait` bound -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `isize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | a: Foo, | ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10 | +LL | enum Bar { + | ----------------- required by `Bar` +... LL | Quux(Bar), | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -note: required by `Bar` - --> $DIR/trait-bounds-on-structs-and-enums.rs:7:1 - | -LL | enum Bar { - | ^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `U: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | b: Foo, | ^^^^^^^^^ the trait `Trait` is not implemented for `U` | = help: consider adding a `where U: Trait` bound -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `V: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:31:21 | +LL | enum Bar { + | ----------------- required by `Bar` +... LL | EvenMoreBadness(Bar), | ^^^^^^ the trait `Trait` is not implemented for `V` | = help: consider adding a `where V: Trait` bound -note: required by `Bar` - --> $DIR/trait-bounds-on-structs-and-enums.rs:7:1 - | -LL | enum Bar { - | ^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:35:5 | +LL | struct Foo { + | ------------------- required by `Foo` +... LL | Foo, | ^^^^^^^^ the trait `Trait` is not implemented for `i32` - | -note: required by `Foo` - --> $DIR/trait-bounds-on-structs-and-enums.rs:3:1 - | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `u8: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22 | +LL | enum Bar { + | ----------------- required by `Bar` +... LL | DictionaryLike { field: Bar }, | ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8` - | -note: required by `Bar` - --> $DIR/trait-bounds-on-structs-and-enums.rs:7:1 - | -LL | enum Bar { - | ^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index de699a69fa8bc..ce2919c8e7741 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -17,6 +17,13 @@ error[E0599]: no method named `b` found for type `S` in the current scope LL | struct S; | --------- method `b` not found for this ... +LL | fn b(&self) { } + | - + | | + | the method is available for `std::boxed::Box` here + | the method is available for `std::sync::Arc` here + | the method is available for `std::rc::Rc` here +... LL | S.b(); | ^ | diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr index 390d21c4a699e..a99536d31ef84 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.stderr +++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr @@ -1,14 +1,11 @@ error[E0283]: type annotations required: cannot resolve `_: base::HasNew` --> $DIR/trait-static-method-generic-inference.rs:24:25 | +LL | fn new() -> T; + | -------------- required by `base::HasNew::new` +... LL | let _f: base::Foo = base::HasNew::new(); | ^^^^^^^^^^^^^^^^^ - | -note: required by `base::HasNew::new` - --> $DIR/trait-static-method-generic-inference.rs:8:9 - | -LL | fn new() -> T; - | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/traits-inductive-overflow-simultaneous.stderr b/src/test/ui/traits/traits-inductive-overflow-simultaneous.stderr index cd8501e4df421..b29d726fbba94 100644 --- a/src/test/ui/traits/traits-inductive-overflow-simultaneous.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-simultaneous.stderr @@ -1,15 +1,13 @@ error[E0275]: overflow evaluating the requirement `{integer}: Tweedledum` --> $DIR/traits-inductive-overflow-simultaneous.rs:18:5 | +LL | fn is_ee(t: T) { + | ------------------------ required by `is_ee` +... LL | is_ee(4); | ^^^^^ | = note: required because of the requirements on the impl of `Combo` for `{integer}` -note: required by `is_ee` - --> $DIR/traits-inductive-overflow-simultaneous.rs:13:1 - | -LL | fn is_ee(t: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index 87e7ba3e7efcf..0b543616d7c9a 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -7,15 +7,13 @@ LL | auto trait Magic: Copy {} error[E0277]: the trait bound `NoClone: std::marker::Copy` is not satisfied --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:15:18 | +LL | fn copy(x: T) -> (T, T) { (x, x) } + | --------------------------------- required by `copy` +... LL | let (a, b) = copy(NoClone); | ^^^^ the trait `std::marker::Copy` is not implemented for `NoClone` | = note: required because of the requirements on the impl of `Magic` for `NoClone` -note: required by `copy` - --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:9:1 - | -LL | fn copy(x: T) -> (T, T) { (x, x) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr index 769582a778bcf..92747be7d2c6b 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait.stderr @@ -1,15 +1,13 @@ error[E0275]: overflow evaluating the requirement `NoClone: Magic` --> $DIR/traits-inductive-overflow-supertrait.rs:13:18 | +LL | fn copy(x: T) -> (T, T) { (x, x) } + | --------------------------------- required by `copy` +... LL | let (a, b) = copy(NoClone); | ^^^^ | = note: required because of the requirements on the impl of `Magic` for `NoClone` -note: required by `copy` - --> $DIR/traits-inductive-overflow-supertrait.rs:7:1 - | -LL | fn copy(x: T) -> (T, T) { (x, x) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr index 61adbf00f7188..58d7fcd56c71e 100644 --- a/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-two-traits.stderr @@ -1,14 +1,11 @@ error[E0275]: overflow evaluating the requirement `*mut (): Magic` --> $DIR/traits-inductive-overflow-two-traits.rs:19:5 | +LL | fn wizard() { check::<::X>(); } + | --------------------- required by `wizard` +... LL | wizard::<*mut ()>(); | ^^^^^^^^^^^^^^^^^ - | -note: required by `wizard` - --> $DIR/traits-inductive-overflow-two-traits.rs:16:1 - | -LL | fn wizard() { check::<::X>(); } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/traits-negative-impls.stderr b/src/test/ui/traits/traits-negative-impls.stderr index 1bdd73eb6f9b1..23bd334a3e776 100644 --- a/src/test/ui/traits/traits-negative-impls.stderr +++ b/src/test/ui/traits/traits-negative-impls.stderr @@ -1,74 +1,67 @@ error[E0277]: `dummy::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:23:5 | +LL | struct Outer(T); + | ------------------------- required by `Outer` +... LL | Outer(TestType); | ^^^^^ `dummy::TestType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` -note: required by `Outer` - --> $DIR/traits-negative-impls.rs:10:1 - | -LL | struct Outer(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dummy::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:23:5 | +LL | struct Outer(T); + | ------------------------- required by `Outer` +... LL | Outer(TestType); | ^^^^^^^^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` -note: required by `Outer` - --> $DIR/traits-negative-impls.rs:10:1 - | -LL | struct Outer(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dummy1b::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:32:5 | +LL | fn is_send(_: T) {} + | ------------------------- required by `is_send` +... LL | is_send(TestType); | ^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dummy1b::TestType` -note: required by `is_send` - --> $DIR/traits-negative-impls.rs:16:1 - | -LL | fn is_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dummy1c::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:40:5 | +LL | fn is_send(_: T) {} + | ------------------------- required by `is_send` +... LL | is_send((8, TestType)); | ^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely | = help: within `({integer}, dummy1c::TestType)`, the trait `std::marker::Send` is not implemented for `dummy1c::TestType` = note: required because it appears within the type `({integer}, dummy1c::TestType)` -note: required by `is_send` - --> $DIR/traits-negative-impls.rs:16:1 - | -LL | fn is_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dummy2::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:48:5 | +LL | fn is_send(_: T) {} + | ------------------------- required by `is_send` +... LL | is_send(Box::new(TestType)); | ^^^^^^^ `dummy2::TestType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `dummy2::TestType` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` = note: required because it appears within the type `std::boxed::Box` -note: required by `is_send` - --> $DIR/traits-negative-impls.rs:16:1 - | -LL | fn is_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:56:5 | +LL | fn is_send(_: T) {} + | ------------------------- required by `is_send` +... LL | is_send(Box::new(Outer2(TestType))); | ^^^^^^^ `dummy3::TestType` cannot be sent between threads safely | @@ -76,25 +69,18 @@ LL | is_send(Box::new(Outer2(TestType))); = note: required because it appears within the type `Outer2` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique>` = note: required because it appears within the type `std::boxed::Box>` -note: required by `is_send` - --> $DIR/traits-negative-impls.rs:16:1 - | -LL | fn is_send(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/traits-negative-impls.rs:66:5 | +LL | fn is_sync(_: T) {} + | ------------------------- required by `is_sync` +... LL | is_sync(Outer2(TestType)); | ^^^^^^^ `main::TestType` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `main::TestType` = note: required because of the requirements on the impl of `std::marker::Sync` for `Outer2` -note: required by `is_sync` - --> $DIR/traits-negative-impls.rs:17:1 - | -LL | fn is_sync(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr index 5d1c91376868f..db77e82adbd00 100644 --- a/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr +++ b/src/test/ui/traits/traits-repeated-supertrait-ambig.stderr @@ -15,27 +15,22 @@ LL | c.same_as(22) error[E0277]: the trait bound `dyn CompareToInts: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:34:5 | +LL | fn same_as(&self, t: T) -> bool; + | -------------------------------- required by `CompareTo::same_as` +... LL | CompareToInts::same_as(c, 22) | ^^^^^^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `dyn CompareToInts` - | -note: required by `CompareTo::same_as` - --> $DIR/traits-repeated-supertrait-ambig.rs:9:5 - | -LL | fn same_as(&self, t: T) -> bool; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `C: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:38:5 | +LL | fn same_as(&self, t: T) -> bool; + | -------------------------------- required by `CompareTo::same_as` +... LL | CompareTo::same_as(c, 22) | ^^^^^^^^^^^^^^^^^^ the trait `CompareTo` is not implemented for `C` | = help: consider adding a `where C: CompareTo` bound -note: required by `CompareTo::same_as` - --> $DIR/traits-repeated-supertrait-ambig.rs:9:5 - | -LL | fn same_as(&self, t: T) -> bool; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `i64: CompareTo` is not satisfied --> $DIR/traits-repeated-supertrait-ambig.rs:42:23 diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index 46b4b2a878492..f0f048159ec73 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -21,26 +21,20 @@ LL | 3i32.test(); error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:25:5 | +LL | fn test(&self); + | --------------- required by `Foo::test` +... LL | Foo::test(&4i32); | ^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `Foo::test` - --> $DIR/trivial-bounds-leak.rs:5:5 - | -LL | fn test(&self); - | ^^^^^^^^^^^^^^^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/trivial-bounds-leak.rs:26:5 | LL | generic_function(5i32); | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32` - | -note: required by `generic_function` - --> $DIR/trivial-bounds-leak.rs:29:1 - | +... LL | fn generic_function(t: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | --------------------------------- required by `generic_function` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index 9f120e009485e..6878cd80629bc 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -21,12 +21,9 @@ error[E0277]: the trait bound `(): std::ops::Try` is not satisfied | LL | try_trait_generic::<()>(); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Try` is not implemented for `()` - | -note: required by `try_trait_generic` - --> $DIR/try-operator-on-main.rs:20:1 - | +... LL | fn try_trait_generic() -> T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------------------------- required by `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` --> $DIR/try-operator-on-main.rs:22:5 diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 92ae9746b150b..1dd2aafeb62fa 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -1,14 +1,11 @@ error[E0283]: type annotations required: cannot resolve `_: std::convert::Into` --> $DIR/type-annotation-needed.rs:5:5 | +LL | fn foo>(x: i32) {} + | ------------------------------- required by `foo` +... LL | foo(42); | ^^^ - | -note: required by `foo` - --> $DIR/type-annotation-needed.rs:1:1 - | -LL | fn foo>(x: i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index a46d79ec3183e..42cca76451fd1 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -1,90 +1,71 @@ error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:6:19 | +LL | struct Foo>(T, U); + | ---------------------------------------- required by `Foo` LL | struct WellFormed>(Z); | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` -note: required by `Foo` - --> $DIR/type-check-defaults.rs:5:1 - | -LL | struct Foo>(T, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: a collection of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:8:27 | +LL | struct Foo>(T, U); + | ---------------------------------------- required by `Foo` +... LL | struct WellFormedNoBounds>(Z); | ^ a collection of type `i32` cannot be built from `std::iter::Iterator` | = help: the trait `std::iter::FromIterator` is not implemented for `i32` -note: required by `Foo` - --> $DIR/type-check-defaults.rs:5:1 - | -LL | struct Foo>(T, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:11:1 | -LL | struct Bounds(T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `Bounds` - --> $DIR/type-check-defaults.rs:11:1 - | LL | struct Bounds(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `std::marker::Copy` is not implemented for `std::string::String` + | required by `Bounds` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:14:1 | -LL | struct WhereClause(T) where T: Copy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `WhereClause` - --> $DIR/type-check-defaults.rs:14:1 - | LL | struct WhereClause(T) where T: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the trait `std::marker::Copy` is not implemented for `std::string::String` + | required by `WhereClause` error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:17:1 | LL | trait TraitBound {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` - | -note: required by `TraitBound` - --> $DIR/type-check-defaults.rs:17:1 - | -LL | trait TraitBound {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | -------------------------------^^^ + | | + | the trait `std::marker::Copy` is not implemented for `std::string::String` + | required by `TraitBound` error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/type-check-defaults.rs:21:1 | +LL | trait Super { } + | -------------------- required by `Super` LL | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `Super` - --> $DIR/type-check-defaults.rs:20:1 - | -LL | trait Super { } - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:1 | LL | trait ProjectionPred> where T::Item : Add {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` + | ------------------------------------------------------------------------^^^ + | | + | no implementation for `i32 + u8` + | required by `ProjectionPred` | = help: the trait `std::ops::Add` is not implemented for `i32` -note: required by `ProjectionPred` - --> $DIR/type-check-defaults.rs:24:1 - | -LL | trait ProjectionPred> where T::Item : Add {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr index 254875fcaab3a..732a81c8a244a 100644 --- a/src/test/ui/type/type-check/issue-40294.stderr +++ b/src/test/ui/type/type-check/issue-40294.stderr @@ -1,6 +1,9 @@ error[E0283]: type annotations required: cannot resolve `&'a T: Foo` --> $DIR/issue-40294.rs:5:1 | +LL | trait Foo: Sized { + | ---------------- required by `Foo` +... LL | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) LL | | where &'a T : Foo, LL | | &'b T : Foo @@ -9,12 +12,6 @@ LL | | x.foo(); LL | | y.foo(); LL | | } | |_^ - | -note: required by `Foo` - --> $DIR/issue-40294.rs:1:1 - | -LL | trait Foo: Sized { - | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/type/type-params-in-different-spaces-2.stderr b/src/test/ui/type/type-params-in-different-spaces-2.stderr index 15db94ef1e3c3..7d4bbc813c09c 100644 --- a/src/test/ui/type/type-params-in-different-spaces-2.stderr +++ b/src/test/ui/type/type-params-in-different-spaces-2.stderr @@ -1,28 +1,24 @@ error[E0277]: the trait bound `Self: Tr` is not satisfied --> $DIR/type-params-in-different-spaces-2.rs:10:9 | +LL | fn op(_: T) -> Self; + | -------------------- required by `Tr::op` +... LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` | = help: consider adding a `where Self: Tr` bound -note: required by `Tr::op` - --> $DIR/type-params-in-different-spaces-2.rs:5:5 - | -LL | fn op(_: T) -> Self; - | ^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `Self: Tr` is not satisfied --> $DIR/type-params-in-different-spaces-2.rs:16:9 | +LL | fn op(_: T) -> Self; + | -------------------- required by `Tr::op` +... LL | Tr::op(u) | ^^^^^^ the trait `Tr` is not implemented for `Self` | = help: consider adding a `where Self: Tr` bound -note: required by `Tr::op` - --> $DIR/type-params-in-different-spaces-2.rs:5:5 - | -LL | fn op(_: T) -> Self; - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index a31ee83ae1ccc..7fb3731be23e6 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -3,14 +3,12 @@ error[E0277]: `::AssocType` cannot be sent between threads safely | LL | is_send::(); | ^^^^^^^^^^^^^^^^^^^^^^^ `::AssocType` cannot be sent between threads safely +... +LL | fn is_send() { + | -------------------- required by `is_send` | = help: the trait `std::marker::Send` is not implemented for `::AssocType` = help: consider adding a `where ::AssocType: std::marker::Send` bound -note: required by `is_send` - --> $DIR/typeck-default-trait-impl-assoc-type.rs:12:1 - | -LL | fn is_send() { - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr index db1d7d8c0b74b..8389356fdd6f6 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)` --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:16:5 | +LL | fn is_mytrait() {} + | --------------------------- required by `is_mytrait` +... LL | is_mytrait::<(MyS2, MyS)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` | = help: the following implementations were found: = note: required because it appears within the type `(MyS2, MyS)` -note: required by `is_mytrait` - --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:11:1 - | -LL | fn is_mytrait() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr index 0f90518964340..eee186feea67d 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied --> $DIR/typeck-default-trait-impl-constituent-types.rs:20:5 | +LL | fn is_mytrait() {} + | --------------------------- required by `is_mytrait` +... LL | is_mytrait::(); | ^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `MyS2` | = help: the following implementations were found: -note: required by `is_mytrait` - --> $DIR/typeck-default-trait-impl-constituent-types.rs:15:1 - | -LL | fn is_mytrait() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr index 8442f47e82c48..1e6adeb430998 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr @@ -1,15 +1,13 @@ error[E0277]: `MyNotSendable` cannot be sent between threads safely --> $DIR/typeck-default-trait-impl-negation-send.rs:19:5 | +LL | fn is_send() {} + | --------------------- required by `is_send` +... LL | is_send::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `MyNotSendable` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `MyNotSendable` -note: required by `is_send` - --> $DIR/typeck-default-trait-impl-negation-send.rs:15:1 - | -LL | fn is_send() {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index 4d435bf4e8b24..d4f8f5ad82c9e 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -1,43 +1,37 @@ error[E0277]: `MyNotSync` cannot be shared between threads safely --> $DIR/typeck-default-trait-impl-negation-sync.rs:33:5 | +LL | fn is_sync() {} + | --------------------- required by `is_sync` +... LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^ `MyNotSync` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `MyNotSync` -note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 - | -LL | fn is_sync() {} - | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-default-trait-impl-negation-sync.rs:36:5 | +LL | fn is_sync() {} + | --------------------- required by `is_sync` +... LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely | = help: within `MyTypeWUnsafe`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `MyTypeWUnsafe` -note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 - | -LL | fn is_sync() {} - | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `Managed` cannot be shared between threads safely --> $DIR/typeck-default-trait-impl-negation-sync.rs:39:5 | +LL | fn is_sync() {} + | --------------------- required by `is_sync` +... LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | = help: within `MyTypeManaged`, the trait `std::marker::Sync` is not implemented for `Managed` = note: required because it appears within the type `MyTypeManaged` -note: required by `is_sync` - --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:1 - | -LL | fn is_sync() {} - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr index 751083d0358b6..e993098b2deed 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr @@ -1,30 +1,26 @@ error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied --> $DIR/typeck-default-trait-impl-negation.rs:21:5 | +LL | fn is_my_trait() {} + | ---------------------------- required by `is_my_trait` +... LL | is_my_trait::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait` | = help: the following implementations were found: -note: required by `is_my_trait` - --> $DIR/typeck-default-trait-impl-negation.rs:16:1 - | -LL | fn is_my_trait() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied --> $DIR/typeck-default-trait-impl-negation.rs:24:5 | +LL | fn is_my_unsafe_trait() {} + | ----------------------------------------- required by `is_my_unsafe_trait` +... LL | is_my_unsafe_trait::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait` | = help: the following implementations were found: -note: required by `is_my_unsafe_trait` - --> $DIR/typeck-default-trait-impl-negation.rs:17:1 - | -LL | fn is_my_unsafe_trait() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr index d45cbb27a5f16..d87a6384e5c01 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied --> $DIR/typeck-default-trait-impl-precedence.rs:18:5 | +LL | fn is_defaulted() { } + | ------------------------------ required by `is_defaulted` +... LL | is_defaulted::<&'static u32>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32` | = note: required because of the requirements on the impl of `Defaulted` for `&'static u32` -note: required by `is_defaulted` - --> $DIR/typeck-default-trait-impl-precedence.rs:11:1 - | -LL | fn is_defaulted() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index a850cc7b377d0..5f3a5bc6e0054 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -3,14 +3,12 @@ error[E0277]: `T` cannot be sent between threads safely | LL | is_send::() | ^^^^^^^^^^^^ `T` cannot be sent between threads safely +... +LL | fn is_send() { + | -------------------- required by `is_send` | = help: the trait `std::marker::Send` is not implemented for `T` = help: consider adding a `where T: std::marker::Send` bound -note: required by `is_send` - --> $DIR/typeck-default-trait-impl-send-param.rs:8:1 - | -LL | fn is_send() { - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-unsafe-always-share.stderr b/src/test/ui/typeck/typeck-unsafe-always-share.stderr index ff351afdcaedf..7ed85a14259aa 100644 --- a/src/test/ui/typeck/typeck-unsafe-always-share.stderr +++ b/src/test/ui/typeck/typeck-unsafe-always-share.stderr @@ -1,55 +1,47 @@ error[E0277]: `std::cell::UnsafeCell>` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:19:5 | +LL | fn test(s: T) {} + | ---------------------- required by `test` +... LL | test(us); | ^^^^ `std::cell::UnsafeCell>` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell>` -note: required by `test` - --> $DIR/typeck-unsafe-always-share.rs:15:1 - | -LL | fn test(s: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:23:5 | +LL | fn test(s: T) {} + | ---------------------- required by `test` +... LL | test(uns); | ^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` -note: required by `test` - --> $DIR/typeck-unsafe-always-share.rs:15:1 - | -LL | fn test(s: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:27:5 | +LL | fn test(s: T) {} + | ---------------------- required by `test` +... LL | test(ms); | ^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely | = help: within `MySync`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` = note: required because it appears within the type `MySync` -note: required by `test` - --> $DIR/typeck-unsafe-always-share.rs:15:1 - | -LL | fn test(s: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `NoSync` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:30:5 | +LL | fn test(s: T) {} + | ---------------------- required by `test` +... LL | test(NoSync); | ^^^^ `NoSync` cannot be shared between threads safely | = help: the trait `std::marker::Sync` is not implemented for `NoSync` -note: required by `test` - --> $DIR/typeck-unsafe-always-share.rs:15:1 - | -LL | fn test(s: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr index fd5ef4b9df15a..dd024b76c3ba7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-default.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `dyn Foo<(isize,), isize, Output = ()>: Eq>` is not satisfied --> $DIR/unboxed-closure-sugar-default.rs:21:5 | +LL | fn eq() where A : Eq { } + | -------------------------------------------- required by `eq` +... LL | eq::, dyn Foo(isize)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq>` is not implemented for `dyn Foo<(isize,), isize, Output = ()>` - | -note: required by `eq` - --> $DIR/unboxed-closure-sugar-default.rs:14:1 - | -LL | fn eq() where A : Eq { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr index 005a86bc2178b..83754bd36ef2a 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-equiv.stderr @@ -1,15 +1,12 @@ error[E0277]: the trait bound `dyn Foo<(char,), Output = ()>: Eq>` is not satisfied --> $DIR/unboxed-closure-sugar-equiv.rs:43:5 | +LL | fn eq>() { } + | ----------------------------------- required by `eq` +... LL | / eq::< dyn Foo<(),Output=()>, LL | | dyn Foo(char) >(); | |_______________________________________________________________________^ the trait `Eq>` is not implemented for `dyn Foo<(char,), Output = ()>` - | -note: required by `eq` - --> $DIR/unboxed-closure-sugar-equiv.rs:16:1 - | -LL | fn eq>() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index fcf11290c81d9..d64e54a548442 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -1,15 +1,13 @@ error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `S` --> $DIR/unboxed-closures-fnmut-as-fn.rs:28:13 | +LL | fn call_itisize>(f: &F, x: isize) -> isize { + | -------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&S, 22); | ^^^^^^^ expected an `Fn<(isize,)>` closure, found `S` | = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `S` -note: required by `call_it` - --> $DIR/unboxed-closures-fnmut-as-fn.rs:23:1 - | -LL | fn call_itisize>(f: &F, x: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index ca0298283661f..3d20b5df1e3f3 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -1,67 +1,57 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:7:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:7:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:8:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:18:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:8:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:24:13 | +LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } + | ----------------------------------------------------------------- required by `call_it_once` +... LL | let z = call_it_once(square, 22); | ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -note: required by `call_it_once` - --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:1 - | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 0abc58aeebfe5..f435a05e04901 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -1,67 +1,57 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:12:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-wrong-abi.rs:7:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:12:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-wrong-abi.rs:7:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:18:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-wrong-abi.rs:8:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:18:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-wrong-abi.rs:8:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:24:13 | +LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } + | ----------------------------------------------------------------- required by `call_it_once` +... LL | let z = call_it_once(square, 22); | ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -note: required by `call_it_once` - --> $DIR/unboxed-closures-wrong-abi.rs:9:1 - | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 19b87ad171a51..efdb2e8efa4e8 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -1,67 +1,57 @@ error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:8:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:13 | +LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } + | --------------------------------------------------------- required by `call_it` +... LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -note: required by `call_it` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:8:1 - | -LL | fn call_itisize>(_: &F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:9:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:19:13 | +LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } + | -------------------------------------------------------------------- required by `call_it_mut` +... LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -note: required by `call_it_mut` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:9:1 - | -LL | fn call_it_mutisize>(_: &mut F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:25:13 | +LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } + | ----------------------------------------------------------------- required by `call_it_once` +... LL | let z = call_it_once(square, 22); | ^^^^^^^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | = help: the trait `std::ops::FnOnce<(&isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -note: required by `call_it_once` - --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:1 - | -LL | fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/unevaluated_fixed_size_array_len.stderr b/src/test/ui/unevaluated_fixed_size_array_len.stderr index be6ed8d56232e..2079f6fd53173 100644 --- a/src/test/ui/unevaluated_fixed_size_array_len.stderr +++ b/src/test/ui/unevaluated_fixed_size_array_len.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `[(); 0]: Foo` is not satisfied --> $DIR/unevaluated_fixed_size_array_len.rs:12:5 | +LL | fn foo(); + | --------- required by `Foo::foo` +... LL | <[(); 0] as Foo>::foo() | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `[(); 0]` | = help: the following implementations were found: <[(); 1] as Foo> -note: required by `Foo::foo` - --> $DIR/unevaluated_fixed_size_array_len.rs:4:5 - | -LL | fn foo(); - | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/union/union-generic.stderr b/src/test/ui/union/union-generic.stderr index 6a3216db64301..f13b2def6db84 100644 --- a/src/test/ui/union/union-generic.stderr +++ b/src/test/ui/union/union-generic.stderr @@ -1,26 +1,20 @@ error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied --> $DIR/union-generic.rs:8:13 | +LL | union U { + | ---------------- required by `U` +... LL | let u = U { a: Rc::new(0u32) }; | ^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` - | -note: required by `U` - --> $DIR/union-generic.rs:3:1 - | -LL | union U { - | ^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied --> $DIR/union-generic.rs:10:13 | +LL | union U { + | ---------------- required by `U` +... LL | let u = U::> { a: Default::default() }; | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` - | -note: required by `U` - --> $DIR/union-generic.rs:3:1 - | -LL | union U { - | ^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index cee1459c7915d..c39c648f661c6 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -1,17 +1,14 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-bare-typaram.rs:2:23 | +LL | fn bar() { } + | ------------------ required by `bar` LL | fn foo() { bar::() } | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound -note: required by `bar` - --> $DIR/unsized-bare-typaram.rs:1:1 - | -LL | fn bar() { } - | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index 20857a1d65e75..dff934834ef2c 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -1,17 +1,15 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-enum.rs:6:36 | +LL | enum Foo { FooSome(U), FooNone } + | ----------- required by `Foo` +LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound -note: required by `Foo` - --> $DIR/unsized-enum.rs:4:1 - | -LL | enum Foo { FooSome(U), FooNone } - | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index 98eecabc84cb8..1a726bb089f6e 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -1,17 +1,15 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized-inherent-impl-self-type.rs:7:17 | +LL | struct S5(Y); + | ---------------- required by `S5` +LL | LL | impl S5 { | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound -note: required by `S5` - --> $DIR/unsized-inherent-impl-self-type.rs:5:1 - | -LL | struct S5(Y); - | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index 7add65c07866b..795115154e72b 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -1,21 +1,22 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-struct.rs:6:36 | +LL | struct Foo { data: T } + | ------------- required by `Foo` +LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound -note: required by `Foo` - --> $DIR/unsized-struct.rs:4:1 - | -LL | struct Foo { data: T } - | ^^^^^^^^^^^^^ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-struct.rs:13:24 | +LL | fn is_sized() { } + | ---------------------- required by `is_sized` +... LL | fn bar2() { is_sized::>() } | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | @@ -23,11 +24,6 @@ LL | fn bar2() { is_sized::>() } = note: to learn more, visit = help: consider adding a `where T: std::marker::Sized` bound = note: required because it appears within the type `Bar` -note: required by `is_sized` - --> $DIR/unsized-struct.rs:1:1 - | -LL | fn is_sized() { } - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index c39f3652b647c..f399f8ded1085 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -1,17 +1,15 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized-trait-impl-self-type.rs:10:17 | +LL | struct S5(Y); + | ---------------- required by `S5` +LL | LL | impl T3 for S5 { | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound -note: required by `S5` - --> $DIR/unsized-trait-impl-self-type.rs:8:1 - | -LL | struct S5(Y); - | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index 2c7b86c5d8284..9064aa14d429f 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -3,34 +3,33 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim | LL | f2::(x); | ^^^^^^^ doesn't have a size known at compile-time +... +LL | fn f2(x: &X) { + | --------------- required by `f2` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound -note: required by `f2` - --> $DIR/unsized3.rs:10:1 - | -LL | fn f2(x: &X) { - | ^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:18:5 | LL | f4::(x); | ^^^^^^^ doesn't have a size known at compile-time +... +LL | fn f4(x: &X) { + | ------------------ required by `f4` | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound -note: required by `f4` - --> $DIR/unsized3.rs:21:1 - | -LL | fn f4(x: &X) { - | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:33:5 | +LL | fn f5(x: &Y) {} + | --------------- required by `f5` +... LL | f5(x1); | ^^ doesn't have a size known at compile-time | @@ -38,11 +37,6 @@ LL | f5(x1); = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` -note: required by `f5` - --> $DIR/unsized3.rs:24:1 - | -LL | fn f5(x: &Y) {} - | ^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:40:5 @@ -72,6 +66,9 @@ LL | f5(&(32, *x1)); error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:45:5 | +LL | fn f5(x: &Y) {} + | --------------- required by `f5` +... LL | f5(&(32, *x1)); | ^^ doesn't have a size known at compile-time | @@ -80,11 +77,6 @@ LL | f5(&(32, *x1)); = help: consider adding a `where X: std::marker::Sized` bound = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` -note: required by `f5` - --> $DIR/unsized3.rs:24:1 - | -LL | fn f5(x: &Y) {} - | ^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/wf/wf-const-type.stderr b/src/test/ui/wf/wf-const-type.stderr index 4df429259ed1f..531aadc25dd2a 100644 --- a/src/test/ui/wf/wf-const-type.stderr +++ b/src/test/ui/wf/wf-const-type.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | +LL | struct IsCopy { t: T } + | --------------------- required by `IsCopy` +... LL | const FOO: IsCopy> = IsCopy { t: None }; | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` | = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` -note: required by `IsCopy` - --> $DIR/wf-const-type.rs:7:1 - | -LL | struct IsCopy { t: T } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr index de28a882f13c3..d5632f4a9c24e 100644 --- a/src/test/ui/wf/wf-enum-bound.stderr +++ b/src/test/ui/wf/wf-enum-bound.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-enum-bound.rs:9:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / enum SomeEnum LL | | where T: ExtraCopy LL | | { @@ -9,11 +12,6 @@ LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-enum-bound.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 6c1267cf7e1b4..51ee23fc5aa6d 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-enum-fields-struct-variant.rs:13:9 | +LL | struct IsCopy { + | --------------------- required by `IsCopy` +... LL | f: IsCopy | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound -note: required by `IsCopy` - --> $DIR/wf-enum-fields-struct-variant.rs:7:1 - | -LL | struct IsCopy { - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr index 9c4eec6c5fbf0..5f4e7c66f54ca 100644 --- a/src/test/ui/wf/wf-enum-fields.stderr +++ b/src/test/ui/wf/wf-enum-fields.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-enum-fields.rs:12:17 | +LL | struct IsCopy { + | --------------------- required by `IsCopy` +... LL | SomeVariant(IsCopy) | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound -note: required by `IsCopy` - --> $DIR/wf-enum-fields.rs:7:1 - | -LL | struct IsCopy { - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index b50e895d8655c..4bc2e370f29fa 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-fn-where-clause.rs:8:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / fn foo() where T: ExtraCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-fn-where-clause.rs:6:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:1 diff --git a/src/test/ui/wf/wf-impl-associated-type-trait.stderr b/src/test/ui/wf/wf-impl-associated-type-trait.stderr index 158b55a3f4165..ceafb4f61578b 100644 --- a/src/test/ui/wf/wf-impl-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-trait.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: MyHash` is not satisfied --> $DIR/wf-impl-associated-type-trait.rs:17:5 | +LL | pub struct MySet { + | -------------------------- required by `MySet` +... LL | type Bar = MySet; | ^^^^^^^^^^^^^^^^^^^^ the trait `MyHash` is not implemented for `T` | = help: consider adding a `where T: MyHash` bound -note: required by `MySet` - --> $DIR/wf-impl-associated-type-trait.rs:8:1 - | -LL | pub struct MySet { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 8635dad851667..e7432f8198734 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-arg.rs:10:1 | +LL | struct MustBeCopy { + | ------------------------- required by `MustBeCopy` +... LL | / fn bar(_: &MustBeCopy) LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-fn-arg.rs:6:1 - | -LL | struct MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr index 3879f7b0a4bf0..005ffe84502de 100644 --- a/src/test/ui/wf/wf-in-fn-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-ret.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-ret.rs:10:1 | +LL | struct MustBeCopy { + | ------------------------- required by `MustBeCopy` +... LL | / fn bar() -> MustBeCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-fn-ret.rs:6:1 - | -LL | struct MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index 40cb4a7050cca..b4cd921040225 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-type-arg.rs:9:5 | +LL | struct MustBeCopy { + | ------------------------- required by `MustBeCopy` +... LL | x: fn(MustBeCopy) | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-fn-type-arg.rs:3:1 - | -LL | struct MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index 059f164e25c28..988fbed8e9107 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-type-ret.rs:9:5 | +LL | struct MustBeCopy { + | ------------------------- required by `MustBeCopy` +... LL | x: fn() -> MustBeCopy | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-fn-type-ret.rs:3:1 - | -LL | struct MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr index 1e732a3341c0b..0af38ddcffea3 100644 --- a/src/test/ui/wf/wf-in-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-in-fn-where-clause.rs:9:1 | +LL | trait MustBeCopy { + | ------------------------ required by `MustBeCopy` +... LL | / fn bar() LL | | where T: MustBeCopy LL | | { @@ -8,11 +11,6 @@ LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-fn-where-clause.rs:6:1 - | -LL | trait MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 2c85dd042e7ba..0f4b4e417ca4f 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-in-obj-type-trait.rs:11:5 | +LL | struct MustBeCopy { + | ------------------------- required by `MustBeCopy` +... LL | x: dyn Object> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `MustBeCopy` - --> $DIR/wf-in-obj-type-trait.rs:5:1 - | -LL | struct MustBeCopy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr index b79093f7d0235..1e258864d0367 100644 --- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-inherent-impl-method-where-clause.rs:12:5 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +... LL | / fn foo(self) where T: ExtraCopy LL | | {} | |______^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-inherent-impl-method-where-clause.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr index f10ff841acbf6..4c389b3ef3ef2 100644 --- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-inherent-impl-where-clause.rs:11:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +... LL | / impl Foo where T: ExtraCopy LL | | { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-inherent-impl-where-clause.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-static-type.stderr b/src/test/ui/wf/wf-static-type.stderr index 4234c7161b1b2..05a628d7c3e19 100644 --- a/src/test/ui/wf/wf-static-type.stderr +++ b/src/test/ui/wf/wf-static-type.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | +LL | struct IsCopy { t: T } + | --------------------- required by `IsCopy` +... LL | static FOO: IsCopy> = IsCopy { t: None }; | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` | = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` -note: required by `IsCopy` - --> $DIR/wf-static-type.rs:7:1 - | -LL | struct IsCopy { t: T } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr index 1fdcced90cc56..2028a0baa17fb 100644 --- a/src/test/ui/wf/wf-struct-bound.stderr +++ b/src/test/ui/wf/wf-struct-bound.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-struct-bound.rs:9:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / struct SomeStruct LL | | where T: ExtraCopy LL | | { @@ -9,11 +12,6 @@ LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-struct-bound.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index e609f93ff700b..d2bff253678ee 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied --> $DIR/wf-struct-field.rs:12:5 | +LL | struct IsCopy { + | --------------------- required by `IsCopy` +... LL | data: IsCopy | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | = help: consider adding a `where A: std::marker::Copy` bound -note: required by `IsCopy` - --> $DIR/wf-struct-field.rs:7:1 - | -LL | struct IsCopy { - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr index 658d41218e483..d5b2b5762a43a 100644 --- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr @@ -1,17 +1,15 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-trait-associated-type-bound.rs:9:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / trait SomeTrait { LL | | type Type1: ExtraCopy; LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-trait-associated-type-bound.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr index 70fabcd4b3074..d8ab955048239 100644 --- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `::Type1: std::marker::Copy` is not satisfied --> $DIR/wf-trait-associated-type-trait.rs:11:5 | +LL | struct IsCopy { x: T } + | --------------------- required by `IsCopy` +... LL | type Type2 = IsCopy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `::Type1` | = help: consider adding a `where ::Type1: std::marker::Copy` bound -note: required by `IsCopy` - --> $DIR/wf-trait-associated-type-trait.rs:7:1 - | -LL | struct IsCopy { x: T } - | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr index 5cc9451bf5cac..85f12b2de5489 100644 --- a/src/test/ui/wf/wf-trait-bound.stderr +++ b/src/test/ui/wf/wf-trait-bound.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied --> $DIR/wf-trait-bound.rs:9:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / trait SomeTrait LL | | where T: ExtraCopy LL | | { @@ -8,11 +11,6 @@ LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `U` | = help: consider adding a `where U: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-trait-bound.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index e713389223654..4d0e1f2f0f4cc 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-arg.rs:11:5 | +LL | struct Bar { value: Box } + | ----------------------- required by `Bar` +... LL | / fn bar(&self, x: &Bar) { LL | | LL | | // @@ -9,11 +12,6 @@ LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-default-fn-arg.rs:8:1 - | -LL | struct Bar { value: Box } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr index 5a310a826dd90..e82b76b61c4a9 100644 --- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-ret.rs:11:5 | +LL | struct Bar { value: Box } + | ----------------------- required by `Bar` +... LL | / fn bar(&self) -> Bar { LL | | LL | | // @@ -10,11 +13,6 @@ LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-default-fn-ret.rs:8:1 - | -LL | struct Bar { value: Box } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr index d5a00be6d3464..6504f6698d9b1 100644 --- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr @@ -1,6 +1,9 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-default-fn-where-clause.rs:11:5 | +LL | trait Bar { } + | ---------------------- required by `Bar` +... LL | / fn bar(&self) where A: Bar { LL | | LL | | // @@ -9,11 +12,6 @@ LL | | } | |_____^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-default-fn-where-clause.rs:8:1 - | -LL | trait Bar { } - | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index 2b26eac9c06b6..0887d4b2fcda2 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-fn-arg.rs:10:5 | +LL | struct Bar { value: Box } + | ----------------------- required by `Bar` +... LL | fn bar(&self, x: &Bar); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-fn-arg.rs:7:1 - | -LL | struct Bar { value: Box } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr index 70f07f02e93ea..5555081498c61 100644 --- a/src/test/ui/wf/wf-trait-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-fn-ret.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-fn-ret.rs:10:5 | +LL | struct Bar { value: Box } + | ----------------------- required by `Bar` +... LL | fn bar(&self) -> &Bar; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-fn-ret.rs:7:1 - | -LL | struct Bar { value: Box } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr index 2d6223e6d9332..5e8fd8982390d 100644 --- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied --> $DIR/wf-trait-fn-where-clause.rs:10:5 | +LL | struct Bar { value: Box } + | ----------------------- required by `Bar` +... LL | fn bar(&self) where Self: Sized, Bar: Copy; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` | = help: consider adding a `where Self: std::cmp::Eq` bound -note: required by `Bar` - --> $DIR/wf-trait-fn-where-clause.rs:7:1 - | -LL | struct Bar { value: Box } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr index a3c4ab58f65f7..377ca640536cf 100644 --- a/src/test/ui/wf/wf-trait-superbound.stderr +++ b/src/test/ui/wf/wf-trait-superbound.stderr @@ -1,16 +1,14 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/wf-trait-superbound.rs:9:1 | +LL | trait ExtraCopy { } + | ----------------------- required by `ExtraCopy` +LL | LL | / trait SomeTrait: ExtraCopy { LL | | } | |_^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `ExtraCopy` - --> $DIR/wf-trait-superbound.rs:7:1 - | -LL | trait ExtraCopy { } - | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr index 125b65b1872e5..f923c6798829f 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:13:9 | +LL | fn require_copy(x: T) {} + | ------------------------------ required by `require_copy` +... LL | require_copy(self.x); | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `require_copy` - --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:1:1 - | -LL | fn require_copy(x: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr index eb555b181f48a..32736836ef8a3 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr @@ -1,15 +1,13 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:18:9 | +LL | fn require_copy(x: T) {} + | ------------------------------ required by `require_copy` +... LL | require_copy(self.x); | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | = help: consider adding a `where T: std::marker::Copy` bound -note: required by `require_copy` - --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:1:1 - | -LL | fn require_copy(x: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr index fb69e2d141129..e59d6089ea539 100644 --- a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr +++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr @@ -1,14 +1,11 @@ error[E0277]: the trait bound `Struct: std::cmp::Eq` is not satisfied --> $DIR/where-clauses-unsatisfied.rs:6:10 | +LL | fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } + | ---------------------------------------------- required by `equal` +... LL | drop(equal(&Struct, &Struct)) | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Struct` - | -note: required by `equal` - --> $DIR/where-clauses-unsatisfied.rs:1:1 - | -LL | fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-for-self-2.stderr b/src/test/ui/where-clauses/where-for-self-2.stderr index dbe68b82c24cb..32dc0e7359cbe 100644 --- a/src/test/ui/where-clauses/where-for-self-2.stderr +++ b/src/test/ui/where-clauses/where-for-self-2.stderr @@ -1,18 +1,16 @@ error[E0277]: the trait bound `for<'a> &'a _: Bar` is not satisfied --> $DIR/where-for-self-2.rs:21:5 | -LL | foo(&X); - | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` - | - = help: the following implementations were found: - <&'static u32 as Bar> -note: required by `foo` - --> $DIR/where-for-self-2.rs:16:1 - | LL | / fn foo(x: &T) LL | | where for<'a> &'a T: Bar LL | | {} - | |__^ + | |__- required by `foo` +... +LL | foo(&X); + | ^^^ the trait `for<'a> Bar` is not implemented for `&'a _` + | + = help: the following implementations were found: + <&'static u32 as Bar> error: aborting due to previous error diff --git a/src/test/ui/wrapping-int-combinations.rs b/src/test/ui/wrapping-int-combinations.rs new file mode 100644 index 0000000000000..f0bc479ee0ff2 --- /dev/null +++ b/src/test/ui/wrapping-int-combinations.rs @@ -0,0 +1,77 @@ +// run-pass + +use std::num::Wrapping; + +macro_rules! wrapping_operation { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + assert_eq!($result, $lhs $op $rhs); + assert_eq!($result, &$lhs $op $rhs); + assert_eq!($result, $lhs $op &$rhs); + assert_eq!($result, &$lhs $op &$rhs); + }; + ($result:expr, $op:tt $expr:expr) => { + assert_eq!($result, $op $expr); + assert_eq!($result, $op &$expr); + }; +} + +macro_rules! wrapping_assignment { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + let mut lhs1 = $lhs; + lhs1 $op $rhs; + assert_eq!($result, lhs1); + + let mut lhs2 = $lhs; + lhs2 $op &$rhs; + assert_eq!($result, lhs2); + }; +} + +macro_rules! wrapping_test { + ($type:ty, $min:expr, $max:expr) => { + let zero: Wrapping<$type> = Wrapping(0); + let one: Wrapping<$type> = Wrapping(1); + let min: Wrapping<$type> = Wrapping($min); + let max: Wrapping<$type> = Wrapping($max); + + wrapping_operation!(min, max + one); + wrapping_assignment!(min, max += one); + wrapping_operation!(max, min - one); + wrapping_assignment!(max, min -= one); + wrapping_operation!(max, max * one); + wrapping_assignment!(max, max *= one); + wrapping_operation!(max, max / one); + wrapping_assignment!(max, max /= one); + wrapping_operation!(zero, max % one); + wrapping_assignment!(zero, max %= one); + wrapping_operation!(zero, zero & max); + wrapping_assignment!(zero, zero &= max); + wrapping_operation!(max, zero | max); + wrapping_assignment!(max, zero |= max); + wrapping_operation!(zero, max ^ max); + wrapping_assignment!(zero, max ^= max); + wrapping_operation!(zero, zero << 1usize); + wrapping_assignment!(zero, zero <<= 1usize); + wrapping_operation!(zero, zero >> 1usize); + wrapping_assignment!(zero, zero >>= 1usize); + wrapping_operation!(zero, -zero); + wrapping_operation!(max, !min); + }; +} + +fn main() { + wrapping_test!(i8, std::i8::MIN, std::i8::MAX); + wrapping_test!(i16, std::i16::MIN, std::i16::MAX); + wrapping_test!(i32, std::i32::MIN, std::i32::MAX); + wrapping_test!(i64, std::i64::MIN, std::i64::MAX); + #[cfg(not(target_os = "emscripten"))] + wrapping_test!(i128, std::i128::MIN, std::i128::MAX); + wrapping_test!(isize, std::isize::MIN, std::isize::MAX); + wrapping_test!(u8, std::u8::MIN, std::u8::MAX); + wrapping_test!(u16, std::u16::MIN, std::u16::MAX); + wrapping_test!(u32, std::u32::MIN, std::u32::MAX); + wrapping_test!(u64, std::u64::MIN, std::u64::MAX); + #[cfg(not(target_os = "emscripten"))] + wrapping_test!(u128, std::u128::MIN, std::u128::MAX); + wrapping_test!(usize, std::usize::MIN, std::usize::MAX); +} diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 63b6399bb9034..c364479d8db13 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Alex Crichton "] edition = "2018" [dependencies] -toml = "0.4" +toml = "0.5" serde = { version = "1.0", features = ["derive"] } diff --git a/src/tools/cargo b/src/tools/cargo index 3f700ec43ce72..22f7dd0495cd7 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 3f700ec43ce72305eb5315cfc710681f3469d4b4 +Subproject commit 22f7dd0495cd72ce2082d318d5a9b4dccb9c5b8c diff --git a/src/tools/clippy b/src/tools/clippy index cd3df6bee0ee0..70e7d075df7b3 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit cd3df6bee0ee07c7dbb562b29576a0b513a4331b +Subproject commit 70e7d075df7b3e11e61fa99b30e1ede26cee6afd diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index bde49ff391c8c..467b7771c152e 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -335,7 +335,7 @@ pub fn parse_config(args: Vec) -> Config { runtool: matches.opt_str("runtool"), host_rustcflags: matches.opt_str("host-rustcflags"), target_rustcflags: matches.opt_str("target-rustcflags"), - target: target, + target, host: opt_str2(matches.opt_str("host")), cdb, gdb, @@ -345,7 +345,7 @@ pub fn parse_config(args: Vec) -> Config { lldb_native_rust, llvm_version: matches.opt_str("llvm-version"), system_llvm: matches.opt_present("system-llvm"), - android_cross_path: android_cross_path, + android_cross_path, adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), adb_device_status: opt_str2(matches.opt_str("target")).contains("android") diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 0bc77c6c502dc..cba51f0065c20 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1603,11 +1603,7 @@ impl<'test> TestCx<'test> { .args(&self.props.compile_flags); if let Some(ref linker) = self.config.linker { - rustdoc - .arg("--linker") - .arg(linker) - .arg("-Z") - .arg("unstable-options"); + rustdoc.arg(format!("-Clinker={}", linker)); } self.compose_and_run_compiler(rustdoc, None) diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index 116be234f3ceb..992af261b8352 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -3,10 +3,14 @@ authors = ["The Rust Project Developers"] name = "error_index_generator" version = "0.0.0" edition = "2018" +build = "build.rs" [dependencies] rustdoc = { path = "../../librustdoc" } +[build-dependencies] +walkdir = "2" + [[bin]] name = "error_index_generator" path = "main.rs" diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs new file mode 100644 index 0000000000000..2ac7351fce469 --- /dev/null +++ b/src/tools/error_index_generator/build.rs @@ -0,0 +1,64 @@ +use walkdir::WalkDir; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() { + // The src directory (we are in src/tools/error_index_generator) + // Note that we could skip one of the .. but this ensures we at least loosely find the right + // directory. + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let dest = out_dir.join("error_codes.rs"); + let mut idx = 0; + for entry in WalkDir::new("../../../src") { + let entry = entry.unwrap(); + if entry.file_name() == "error_codes.rs" { + println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); + let file = fs::read_to_string(entry.path()).unwrap() + .replace("use syntax::{register_diagnostics, register_long_diagnostics};", "") + .replace("use syntax::register_diagnostics;", "") + .replace("use syntax::register_long_diagnostics;", ""); + let contents = format!("(|| {{\n{}\n}})();", file); + + fs::write(&out_dir.join(&format!("error_{}.rs", idx)), &contents).unwrap(); + + idx += 1; + } + } + + let mut all = String::new(); + all.push_str("fn register_all() -> Vec<(&'static str, Option<&'static str>)> {\n"); + all.push_str("let mut long_codes: Vec<(&'static str, Option<&'static str>)> = Vec::new();\n"); + all.push_str(r#" +macro_rules! register_diagnostics { + ($($code:tt),*) => {{ + long_codes.extend([$( + stringify!($code), + )*].iter().cloned().map(|s| (s, None)).collect::>()); + }}; + ($($code:tt),*,) => {{ + long_codes.extend([$( + stringify!($code), + )*].iter().cloned().map(|s| (s, None))); + }} +} + +macro_rules! register_long_diagnostics { + ($($code:tt: $description:tt),*) => { + {long_codes.extend([$( + (stringify!($code), Some(stringify!($description))), + )*].iter());} + }; + ($($code:tt: $description:tt),*,) => { + {long_codes.extend([$( + (stringify!($code), Some(stringify!($description))), + )*].iter());} + } +}"#); + for idx in 0..idx { + all.push_str(&format!(r#"include!(concat!(env!("OUT_DIR"), "/error_{}.rs"));"#, idx)); + } + all.push_str("\nlong_codes\n"); + all.push_str("}\n"); + + fs::write(&dest, all).unwrap(); +} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index a9d1d9997f6ef..c4826a0c31d6c 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -2,22 +2,26 @@ extern crate env_logger; extern crate syntax; -extern crate serialize as rustc_serialize; use std::collections::BTreeMap; use std::env; use std::error::Error; -use std::fs::{self, read_dir, File}; +use std::fs::File; use std::io::Write; use std::path::Path; use std::path::PathBuf; use std::cell::RefCell; use syntax::edition::DEFAULT_EDITION; -use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground}; -use rustc_serialize::json; + +pub struct ErrorMetadata { + pub description: Option, +} + +/// Mapping from error codes to metadata that can be (de)serialized. +pub type ErrorMetadataMap = BTreeMap; enum OutputFormat { HTML(HTMLFormatter), @@ -80,11 +84,7 @@ impl Formatter for HTMLFormatter { Some(_) => "error-described", None => "error-undescribed", }; - let use_desc = match info.use_site { - Some(_) => "error-used", - None => "error-unused", - }; - write!(output, "
", desc_desc, use_desc)?; + write!(output, "
", desc_desc)?; // Error title (with self-link). write!(output, @@ -199,25 +199,6 @@ impl Formatter for MarkdownFormatter { } } -/// Loads all the metadata files from `metadata_dir` into an in-memory map. -fn load_all_errors(metadata_dir: &Path) -> Result> { - let mut all_errors = BTreeMap::new(); - - for entry in read_dir(metadata_dir)? { - let path = entry?.path(); - - let metadata_str = fs::read_to_string(&path)?; - - let some_errors: ErrorMetadataMap = json::decode(&metadata_str)?; - - for (err_code, info) in some_errors { - all_errors.insert(err_code, info); - } - } - - Ok(all_errors) -} - /// Output an HTML page for the errors in `err_map` to `output_path`. fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Path, formatter: T) -> Result<(), Box> { @@ -234,9 +215,13 @@ fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Pat } fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box> { - let build_arch = env::var("CFG_BUILD")?; - let metadata_dir = get_metadata_dir(&build_arch); - let err_map = load_all_errors(&metadata_dir)?; + let long_codes = register_all(); + let mut err_map = BTreeMap::new(); + for (code, desc) in long_codes { + err_map.insert(code.to_string(), ErrorMetadata { + description: desc.map(String::from), + }); + } match format { OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), OutputFormat::HTML(h) => render_error_page(&err_map, dst, h)?, @@ -272,3 +257,5 @@ fn main() { panic!("{}", e.description()); } } + +include!(concat!(env!("OUT_DIR"), "/error_codes.rs")); diff --git a/src/tools/miri b/src/tools/miri index 4f6f264c305ea..69268fb75fdb4 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 4f6f264c305ea30f1de90ad0c2f341e84d972b2e +Subproject commit 69268fb75fdb452296caa9bc4aaeff1674279de2 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index b8dcba3afc3a1..1411f4c0b05a2 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -22,7 +22,7 @@ # List of people to ping when the status of a tool or a book changed. MAINTAINERS = { 'miri': '@oli-obk @RalfJung @eddyb', - 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch', + 'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk @phansch @flip1995', 'rls': '@Xanewok', 'rustfmt': '@topecongiro', 'book': '@carols10cents @steveklabnik', @@ -34,7 +34,7 @@ '@ryankurte @thejpster @therealprof' ), 'edition-guide': '@ehuss @Centril @steveklabnik', - 'rustc-guide': '@mark-i-m @spastorino' + 'rustc-guide': '@mark-i-m @spastorino @amanjeev' } REPOS = { diff --git a/src/tools/rust-installer b/src/tools/rust-installer index 85958b001dbff..9f66c14c3f91a 160000 --- a/src/tools/rust-installer +++ b/src/tools/rust-installer @@ -1 +1 @@ -Subproject commit 85958b001dbff8523396809bfa844fc34a7869a8 +Subproject commit 9f66c14c3f91a48a118c7817f434167b311c3515 diff --git a/src/tools/rustc-std-workspace-std/Cargo.toml b/src/tools/rustc-std-workspace-std/Cargo.toml new file mode 100644 index 0000000000000..ce1644809dbe6 --- /dev/null +++ b/src/tools/rustc-std-workspace-std/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rustc-std-workspace-std" +version = "1.0.0" +authors = ["Alex Crichton "] +license = 'MIT OR Apache-2.0' +description = """ +Hack for the compiler's own build system +""" +edition = "2018" + +[lib] +path = "lib.rs" + +[dependencies] +std = { path = "../../libstd" } diff --git a/src/tools/rustc-std-workspace-std/README.md b/src/tools/rustc-std-workspace-std/README.md new file mode 100644 index 0000000000000..2228907f304c4 --- /dev/null +++ b/src/tools/rustc-std-workspace-std/README.md @@ -0,0 +1,3 @@ +# The `rustc-std-workspace-std` crate + +See documentation for the `rustc-std-workspace-core` crate. diff --git a/src/tools/rustc-std-workspace-std/lib.rs b/src/tools/rustc-std-workspace-std/lib.rs new file mode 100644 index 0000000000000..f40d09cafbb47 --- /dev/null +++ b/src/tools/rustc-std-workspace-std/lib.rs @@ -0,0 +1 @@ +pub use std::*; diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 0462008de87d2..f800ce47d1da2 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 0462008de87d2757e8ef1dc26f2c54dd789a59a8 +Subproject commit f800ce47d1da2a1c02ffd260deca8b7445f7facf diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index de54eb8f57312..a564b991c404b 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -90,15 +90,18 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("crossbeam-epoch"), Crate("crossbeam-utils"), Crate("datafrog"), + Crate("dlmalloc"), Crate("either"), Crate("ena"), Crate("env_logger"), Crate("filetime"), Crate("flate2"), + Crate("fortanix-sgx-abi"), Crate("fuchsia-zircon"), Crate("fuchsia-zircon-sys"), Crate("getopts"), Crate("getrandom"), + Crate("hashbrown"), Crate("humantime"), Crate("indexmap"), Crate("itertools"), @@ -159,6 +162,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("termcolor"), Crate("terminon"), Crate("termion"), + Crate("term_size"), Crate("thread_local"), Crate("ucd-util"), Crate("unicode-width"), diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 88a469ef9550c..50e9116c778ea 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -176,7 +176,10 @@ pub fn check(path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures { CollectedFeatures { lib: lib_features, lang: features } } -fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator + 'a { +fn format_features<'a>( + features: &'a Features, + family: &'a str, +) -> impl Iterator + 'a { features.iter().map(move |(name, feature)| { format!("{:<32} {:<8} {:<12} {:<8}", name, @@ -221,7 +224,15 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { } pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { - let contents = t!(fs::read_to_string(base_src_path.join("libsyntax/feature_gate.rs"))); + let mut all = collect_lang_features_in(base_src_path, "active.rs", bad); + all.extend(collect_lang_features_in(base_src_path, "accepted.rs", bad)); + all.extend(collect_lang_features_in(base_src_path, "removed.rs", bad)); + all +} + +fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features { + let path = base.join("libsyntax/feature_gate").join(file); + let contents = t!(fs::read_to_string(&path)); // We allow rustc-internal features to omit a tracking issue. // To make tidy accept omitting a tracking issue, group the list of features @@ -252,8 +263,9 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { if in_feature_group { tidy_error!( bad, - // ignore-tidy-linelength - "libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one", + "{}:{}: \ + new feature group is started without ending the previous one", + path.display(), line_number, ); } @@ -282,7 +294,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { Err(err) => { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})", + "{}:{}: failed to parse since: {} ({:?})", + path.display(), line_number, since_str, err, @@ -294,7 +307,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { if prev_since > since { tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: feature {} is not sorted by since", + "{}:{}: feature {} is not sorted by since", + path.display(), line_number, name, ); @@ -308,7 +322,8 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { *bad = true; tidy_error!( bad, - "libsyntax/feature_gate.rs:{}: no tracking issue for feature {}", + "{}:{}: no tracking issue for feature {}", + path.display(), line_number, name, );