diff options
676 files changed, 9886 insertions, 4000 deletions
diff --git a/Cargo.lock b/Cargo.lock index 009767934d4..5bb6cda64cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2780,9 +2780,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.34" +version = "2.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9caecf1286a3ed28d3ae35207a178ba12e58de95540781e5c6cba05e0f0833" +checksum = "421174f19211ba9e5fda34aa0cbc292188aae8e0cfbff4aebbae23f1a416bfb3" dependencies = [ "bitflags", "clap", @@ -3207,43 +3207,38 @@ dependencies = [ ] [[package]] -name = "rustc-ap-arena" -version = "659.0.0" +name = "rustc-ap-rustc_arena" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdaf0295fc40b10ec1091aad1a1760b4bb3b4e7c4f77d543d1a2e9d50a01e6b1" +checksum = "0c6683b49209f8b132bec33dc6b6c8f9958c8c94eb3586d4cb495e092b61c1da" dependencies = [ "rustc-ap-rustc_data_structures", "smallvec 1.4.0", ] [[package]] -name = "rustc-ap-graphviz" -version = "659.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8028e8cdb4eb71810d0c22a5a5e1e3106c81123be63ce7f044b6d4ac100d8941" - -[[package]] name = "rustc-ap-rustc_ast" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e9e502bb3a5568433db1cf2fb1f1e1074934636069cf744ad7c77b58e1428e" +checksum = "5b21784d92fb2d584800f528866f00fe814f73abda794f406bfd1fbb2f1ca7f7" dependencies = [ + "bitflags", "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_lexer", "rustc-ap-rustc_macros", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", - "rustc-ap-serialize", "scoped-tls", "smallvec 1.4.0", ] [[package]] name = "rustc-ap-rustc_ast_passes" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf35ffecab28f97f7ac01cf6a13afaca6408529d15eb95f317a43b2ffb88933" +checksum = "820c46fde7ef1df0432073090d775f097b7279ca75ea34ba954081ce4b884d4c" dependencies = [ "itertools 0.8.0", "log", @@ -3260,20 +3255,21 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3684ed43dc552f1e030e3f7a5a300a7a834bdda4e9e00ab80284be4220d8c603" +checksum = "013db7dd198fe95962d2cefa5bd0b350cf2028af77c169b17b4baa9c3bbf77d1" dependencies = [ "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_span", + "rustc-ap-rustc_target", ] [[package]] name = "rustc-ap-rustc_attr" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b413927daa666983b3b49227f9ac218aa29254546abdb585f20cd71c391870" +checksum = "35b5a85c90eb341eec543600ffdd9e262da5ea72a73a23ae4ca2f4ab8cd1a188" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", @@ -3281,17 +3277,17 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_macros", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", "rustc-ap-rustc_span", - "rustc-ap-serialize", "version_check", ] [[package]] name = "rustc-ap-rustc_data_structures" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1c6069e5c522657f1c6f5ab33074e097092f48e804cc896d337e319aacbd60" +checksum = "b92e4c6cb6c43ee9031a71709dc12853b358253c2b41d12a26379994fab625e0" dependencies = [ "bitflags", "cfg-if", @@ -3303,10 +3299,11 @@ dependencies = [ "libc", "log", "measureme", + "once_cell", "parking_lot 0.10.2", - "rustc-ap-graphviz", + "rustc-ap-rustc_graphviz", "rustc-ap-rustc_index", - "rustc-ap-serialize", + "rustc-ap-rustc_serialize", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3318,16 +3315,16 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_errors" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c374e89b3c9714869ef86076942155383804ba6778c26be2169d324563c31f9" +checksum = "6b0aa79423260c1b9e2f856e144e040f606b0f5d43644408375becf9d7bcdf86" dependencies = [ - "annotate-snippets 0.6.1", + "annotate-snippets 0.8.0", "atty", "log", "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", - "rustc-ap-serialize", "termcolor", "termize", "unicode-width", @@ -3336,9 +3333,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_expand" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "259d2a7aa7a12f3c99a4ce4123643ec065f1a26f8e89be1f9bedd9757ea53fdc" +checksum = "c07d76ba2a1b7d4325a2ed21d6345ccebd89ddc6666a1535a6edd489fb4cbc11" dependencies = [ "log", "rustc-ap-rustc_ast", @@ -3350,17 +3347,17 @@ dependencies = [ "rustc-ap-rustc_feature", "rustc-ap-rustc_lexer", "rustc-ap-rustc_parse", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", "rustc-ap-rustc_span", - "rustc-ap-serialize", "smallvec 1.4.0", ] [[package]] name = "rustc-ap-rustc_feature" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0296fbc29b629d5ae2ebee1bbf0407bb22de04d26d87216c20899b79579ccb3" +checksum = "1bbd625705c1db42a0c7503736292813d7b76ada5da20578fb55c63228c80ab5" dependencies = [ "lazy_static", "rustc-ap-rustc_data_structures", @@ -3369,34 +3366,40 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_fs_util" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34734f6cc681399630acd836a14207c6b5b9671a290cc7cad0354b0a4d71b3c9" +checksum = "34cca6e2942fa0b059c582437ead666d5bcf20fa7c242599e2bbea9b609f29ae" + +[[package]] +name = "rustc-ap-rustc_graphviz" +version = "664.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d6a029b81f5e02da85763f82c135507f278a4a0c776432c728520563059529" [[package]] name = "rustc-ap-rustc_index" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e4508753d71d3523209c2ca5086db15a1413e71ebf17ad5412bb7ced5e44c2" +checksum = "bae50852d303e230b2781c994513788136dc6c2fe4ebe032959f0b990a425767" dependencies = [ - "rustc-ap-serialize", + "rustc-ap-rustc_serialize", "smallvec 1.4.0", ] [[package]] name = "rustc-ap-rustc_lexer" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b9fcd8407e322908a721262fbc0b35b5f3c35bb173a26dd1e0070bde336e33" +checksum = "b7186e74aa2d31bf0e2454325fefcdf0a3da77d9344134592144b9e40d45b15d" dependencies = [ "unicode-xid 0.2.0", ] [[package]] name = "rustc-ap-rustc_macros" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d104115a689367d2e0bcd99f37e0ebd6b9c8c78bab0d9cbea5bae86323601b5" +checksum = "4fc1add04e9d2301164118660ee0bc3266e9a7b1973fc2303fdbe002a12e5401" dependencies = [ "proc-macro2 1.0.3", "quote 1.0.2", @@ -3406,9 +3409,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afaaab91853fc5a3916785ccae727a4433359d9787c260d42b96a2265fe5b287" +checksum = "9cd7fc4968bd60084f2fa4f280fa450b0cf98660a7983d6b93a7ae41b6d1d322" dependencies = [ "bitflags", "log", @@ -3424,10 +3427,20 @@ dependencies = [ ] [[package]] +name = "rustc-ap-rustc_serialize" +version = "664.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bf4c110271d9a2b7dfd2c6eb82e56fd80606a8bad6c102e158c54e44044046" +dependencies = [ + "indexmap", + "smallvec 1.4.0", +] + +[[package]] name = "rustc-ap-rustc_session" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e756a57ce6ce1b868e35e64a7e10ab28d49ece80d7c661b07aff5afc6e5d2d" +checksum = "431cf962de71d4c03fb877d54f331ec36eca77350b0539017abc40a4410d6501" dependencies = [ "getopts", "log", @@ -3437,26 +3450,25 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_fs_util", - "rustc-ap-rustc_index", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", "rustc-ap-rustc_target", - "rustc-ap-serialize", ] [[package]] name = "rustc-ap-rustc_span" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21031c3396ee452f4c6e994b67513a633055c57c86d00336afd9d63149518f34" +checksum = "b912039640597624f4bcb75f1e1fcfa5710267d715a7f73a6336baef341b23d1" dependencies = [ "cfg-if", "log", "md-5", - "rustc-ap-arena", + "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", - "rustc-ap-serialize", + "rustc-ap-rustc_serialize", "scoped-tls", "sha-1", "unicode-width", @@ -3464,27 +3476,17 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_target" -version = "659.0.0" +version = "664.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff21badfbead5b0050391eaad8840f2e4fcb03b6b0fc6006f447443529e9ae6e" +checksum = "51347a9dadc5ad0b5916cc12d42624b31955285ad13745dbe72f0140038b84e9" dependencies = [ "bitflags", "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", + "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", - "rustc-ap-serialize", -] - -[[package]] -name = "rustc-ap-serialize" -version = "659.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768b5a305669d934522712bc13502962edfde5128ea63b9e7db4000410be1dc6" -dependencies = [ - "indexmap", - "smallvec 1.4.0", ] [[package]] @@ -4278,6 +4280,7 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ + "bitflags", "getopts", "log", "num_cpus", @@ -4481,16 +4484,16 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.15" +version = "1.4.18" dependencies = [ "annotate-snippets 0.6.1", + "anyhow", "bytecount", "cargo_metadata 0.8.0", "derive-new", "diff", "dirs", "env_logger 0.6.2", - "failure", "getopts", "ignore", "itertools 0.8.0", @@ -4512,6 +4515,7 @@ dependencies = [ "serde_json", "structopt", "term 0.6.0", + "thiserror", "toml", "unicode-segmentation", "unicode-width", diff --git a/Cargo.toml b/Cargo.toml index f2177a99a9b..f10d539d829 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,19 @@ debug-assertions = false debug = false debug-assertions = false +[profile.release.package.compiler_builtins] +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +codegen-units = 10000 + # We want the RLS to use the version of Cargo that we've got vendored in this # repository to ensure that the same exact version of Cargo is used by both the # RLS and the Cargo binary itself. The RLS depends on Cargo as a git repository diff --git a/RELEASES.md b/RELEASES.md index 3ae3417a9b4..006682f5059 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -912,7 +912,7 @@ Compatibility Notes [`Duration::mul_f32`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f32 [`Duration::mul_f64`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.mul_f64 [`any::type_name`]: https://doc.rust-lang.org/std/any/fn.type_name.html -[forge-platform-support]: https://forge.rust-lang.org/platform-support.html +[forge-platform-support]: https://forge.rust-lang.org/release/platform-support.html [pipeline-internals]: https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199 Version 1.37.0 (2019-08-15) diff --git a/config.toml.example b/config.toml.example index d995554913f..bc676033417 100644 --- a/config.toml.example +++ b/config.toml.example @@ -209,7 +209,8 @@ # Build the sanitizer runtimes #sanitizers = false -# Build the profiler runtime +# Build the profiler runtime (required when compiling with options that depend +# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`). #profiler = false # Indicates whether the native libraries linked into Cargo will be statically diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b7d0fac5be3..969d16d11e8 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -894,7 +894,7 @@ def bootstrap(help_triggered): build.clean = args.clean try: - toml_path = args.config or 'config.toml' + toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config or 'config.toml' if not os.path.exists(toml_path): toml_path = os.path.join(build.rust_root, toml_path) @@ -947,6 +947,7 @@ def bootstrap(help_triggered): env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable + env["BOOTSTRAP_CONFIG"] = toml_path env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' env["CARGO"] = build.cargo() diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 087b0da74e5..8f0a245a565 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -99,9 +99,21 @@ struct StepDescription { name: &'static str, } +/// Collection of paths used to match a task rule. #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] pub enum PathSet { + /// A collection of individual paths. + /// + /// These are generally matched as a path suffix. For example, a + /// command-line value of `libstd` will match if `src/libstd` is in the + /// set. Set(BTreeSet<PathBuf>), + /// A "suite" of paths. + /// + /// These can match as a path suffix (like `Set`), or as a prefix. For + /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs` + /// will match `src/test/ui`. A command-line value of `ui` would also + /// match `src/test/ui`. Suite(PathBuf), } @@ -251,21 +263,33 @@ impl<'a> ShouldRun<'a> { self } - // Unlike `krate` this will create just one pathset. As such, it probably shouldn't actually - // ever be used, but as we transition to having all rules properly handle passing krate(...) by - // actually doing something different for every crate passed. + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// Compared to `krate`, this treats the dependencies as aliases for the + /// same job. Generally it is preferred to use `krate`, and treat each + /// individual path separately. For example `./x.py test src/liballoc` + /// (which uses `krate`) will test just `liballoc`. However, `./x.py check + /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. + /// `all_krates` should probably be removed at some point. pub fn all_krates(mut self, name: &str) -> Self { let mut set = BTreeSet::new(); for krate in self.builder.in_tree_crates(name) { - set.insert(PathBuf::from(&krate.path)); + let path = krate.local_path(self.builder); + set.insert(path); } self.paths.insert(PathSet::Set(set)); self } + /// Indicates it should run if the command-line selects the given crate or + /// any of its (local) dependencies. + /// + /// `make_run` will be called separately for each matching command-line path. pub fn krate(mut self, name: &str) -> Self { for krate in self.builder.in_tree_crates(name) { - self.paths.insert(PathSet::one(&krate.path)); + let path = krate.local_path(self.builder); + self.paths.insert(PathSet::one(path)); } self } @@ -488,13 +512,19 @@ impl<'a> Builder<'a> { should_run = (desc.should_run)(should_run); } let mut help = String::from("Available paths:\n"); + let mut add_path = |path: &Path| { + help.push_str(&format!(" ./x.py {} {}\n", subcommand, path.display())); + }; for pathset in should_run.paths { - if let PathSet::Set(set) = pathset { - set.iter().for_each(|path| { - help.push_str( - format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(), - ) - }) + match pathset { + PathSet::Set(set) => { + for path in set { + add_path(&path); + } + } + PathSet::Suite(path) => { + add_path(&path.join("...")); + } } } Some(help) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c09b73b0420..afcf0dcac7e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -23,7 +23,7 @@ use crate::builder::Cargo; use crate::dist; use crate::native; use crate::util::{exe, is_dylib, symlink_dir}; -use crate::{Compiler, GitRepo, Mode}; +use crate::{Compiler, DependencyType, GitRepo, Mode}; use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; @@ -74,6 +74,7 @@ impl Step for Std { // Even if we're not building std this stage, the new sysroot must // still contain the third party objects needed by various targets. copy_third_party_objects(builder, &compiler, target); + copy_self_contained_objects(builder, &compiler, target); builder.ensure(StdLink { compiler: compiler_to_use, @@ -83,7 +84,8 @@ impl Step for Std { return; } - target_deps.extend(copy_third_party_objects(builder, &compiler, target).into_iter()); + target_deps.extend(copy_third_party_objects(builder, &compiler, target)); + target_deps.extend(copy_self_contained_objects(builder, &compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Std, target, "build"); std_cargo(builder, target, compiler.stage, &mut cargo); @@ -109,21 +111,76 @@ impl Step for Std { } } +fn copy_and_stamp( + builder: &Builder<'_>, + libdir: &Path, + sourcedir: &Path, + name: &str, + target_deps: &mut Vec<(PathBuf, DependencyType)>, + dependency_type: DependencyType, +) { + let target = libdir.join(name); + builder.copy(&sourcedir.join(name), &target); + + target_deps.push((target, dependency_type)); +} + /// Copies third party objects needed by various targets. fn copy_third_party_objects( builder: &Builder<'_>, compiler: &Compiler, target: Interned<String>, -) -> Vec<PathBuf> { +) -> Vec<(PathBuf, DependencyType)> { let libdir = builder.sysroot_libdir(*compiler, target); - let mut target_deps = vec![]; - let mut copy_and_stamp = |sourcedir: &Path, name: &str| { - let target = libdir.join(name); - builder.copy(&sourcedir.join(name), &target); - target_deps.push(target); + // Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx. + // + // This target needs to be linked to Fortanix's port of llvm's libunwind. + // libunwind requires support for rwlock and printing to stderr, + // which is provided by std for this target. + if target == "x86_64-fortanix-unknown-sgx" { + let src_path_env = "X86_FORTANIX_SGX_LIBS"; + let src = + env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env)); + copy_and_stamp( + builder, + &*libdir, + Path::new(&src), + "libunwind.a", + &mut target_deps, + DependencyType::Target, + ); + } + + if builder.config.sanitizers && compiler.stage != 0 { + // The sanitizers are only copied in stage1 or above, + // to avoid creating dependency on LLVM. + target_deps.extend( + copy_sanitizers(builder, &compiler, target) + .into_iter() + .map(|d| (d, DependencyType::Target)), + ); + } + + target_deps +} + +/// Copies third party objects needed by various targets for self-contained linkage. +fn copy_self_contained_objects( + builder: &Builder<'_>, + compiler: &Compiler, + target: Interned<String>, +) -> Vec<(PathBuf, DependencyType)> { + // cfg(bootstrap) + // Remove when upgrading bootstrap compiler. + let libdir_self_contained = if compiler.stage == 0 { + builder.sysroot_libdir(*compiler, target).to_path_buf() + } else { + builder.sysroot_libdir(*compiler, target).join("self-contained") }; + t!(fs::create_dir_all(&libdir_self_contained)); + let mut target_deps = vec![]; // Copies the CRT objects. // @@ -135,29 +192,32 @@ fn copy_third_party_objects( if target.contains("musl") { let srcdir = builder.musl_root(target).unwrap().join("lib"); for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { - copy_and_stamp(&srcdir, obj); + copy_and_stamp( + builder, + &libdir_self_contained, + &srcdir, + obj, + &mut target_deps, + DependencyType::TargetSelfContained, + ); } } else if target.ends_with("-wasi") { let srcdir = builder.wasi_root(target).unwrap().join("lib/wasm32-wasi"); - copy_and_stamp(&srcdir, "crt1.o"); - } - - // Copies libunwind.a compiled to be linked with x86_64-fortanix-unknown-sgx. - // - // This target needs to be linked to Fortanix's port of llvm's libunwind. - // libunwind requires support for rwlock and printing to stderr, - // which is provided by std for this target. - if target == "x86_64-fortanix-unknown-sgx" { - let src_path_env = "X86_FORTANIX_SGX_LIBS"; - let src = - env::var(src_path_env).unwrap_or_else(|_| panic!("{} not found in env", src_path_env)); - copy_and_stamp(Path::new(&src), "libunwind.a"); - } - - if builder.config.sanitizers && compiler.stage != 0 { - // The sanitizers are only copied in stage1 or above, - // to avoid creating dependency on LLVM. - target_deps.extend(copy_sanitizers(builder, &compiler, target)); + copy_and_stamp( + builder, + &libdir_self_contained, + &srcdir, + "crt1.o", + &mut target_deps, + DependencyType::TargetSelfContained, + ); + } else if target.contains("windows-gnu") { + for obj in ["crt2.o", "dllcrt2.o"].iter() { + let src = compiler_file(builder, builder.cc(target), target, obj); + let target = libdir_self_contained.join(obj); + builder.copy(&src, &target); + target_deps.push((target, DependencyType::TargetSelfContained)); + } } target_deps @@ -244,6 +304,16 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned<String>, stage: u32, ca if stage >= 1 { cargo.rustflag("-Cembed-bitcode=yes"); } + + // By default, rustc does not include unwind tables unless they are required + // for a particular target. They are not required by RISC-V targets, but + // compiling the standard library with them means that users can get + // backtraces without having to recompile the standard library themselves. + // + // This choice was discussed in https://github.com/rust-lang/rust/pull/69890 + if target.contains("riscv") { + cargo.rustflag("-Cforce-unwind-tables=yes"); + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -325,7 +395,7 @@ pub struct StartupObjects { } impl Step for StartupObjects { - type Output = Vec<PathBuf>; + type Output = Vec<(PathBuf, DependencyType)>; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/rtstartup") @@ -344,7 +414,7 @@ impl Step for StartupObjects { /// They don't require any library support as they're just plain old object /// files, so we just use the nightly snapshot compiler to always build them (as /// no other compilers are guaranteed to be available). - fn run(self, builder: &Builder<'_>) -> Vec<PathBuf> { + fn run(self, builder: &Builder<'_>) -> Vec<(PathBuf, DependencyType)> { let for_compiler = self.compiler; let target = self.target; if !target.contains("windows-gnu") { @@ -378,14 +448,7 @@ impl Step for StartupObjects { let target = sysroot_dir.join((*file).to_string() + ".o"); builder.copy(dst_file, &target); - target_deps.push(target); - } - - for obj in ["crt2.o", "dllcrt2.o"].iter() { - let src = compiler_file(builder, builder.cc(target), target, obj); - let target = sysroot_dir.join(obj); - builder.copy(&src, &target); - target_deps.push(target); + target_deps.push((target, DependencyType::Target)); } target_deps @@ -798,14 +861,17 @@ pub fn add_to_sysroot( sysroot_host_dst: &Path, stamp: &Path, ) { + let self_contained_dst = &sysroot_dst.join("self-contained"); t!(fs::create_dir_all(&sysroot_dst)); t!(fs::create_dir_all(&sysroot_host_dst)); - for (path, host) in builder.read_stamp_file(stamp) { - if host { - builder.copy(&path, &sysroot_host_dst.join(path.file_name().unwrap())); - } else { - builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); - } + t!(fs::create_dir_all(&self_contained_dst)); + for (path, dependency_type) in builder.read_stamp_file(stamp) { + let dst = match dependency_type { + DependencyType::Host => sysroot_host_dst, + DependencyType::Target => sysroot_dst, + DependencyType::TargetSelfContained => self_contained_dst, + }; + builder.copy(&path, &dst.join(path.file_name().unwrap())); } } @@ -814,7 +880,7 @@ pub fn run_cargo( cargo: Cargo, tail_args: Vec<String>, stamp: &Path, - additional_target_deps: Vec<PathBuf>, + additional_target_deps: Vec<(PathBuf, DependencyType)>, is_check: bool, ) -> Vec<PathBuf> { if builder.config.dry_run { @@ -865,7 +931,7 @@ pub fn run_cargo( if filename.starts_with(&host_root_dir) { // Unless it's a proc macro used in the compiler if crate_types.iter().any(|t| t == "proc-macro") { - deps.push((filename.to_path_buf(), true)); + deps.push((filename.to_path_buf(), DependencyType::Host)); } continue; } @@ -873,7 +939,7 @@ pub fn run_cargo( // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. if filename.starts_with(&target_deps_dir) { - deps.push((filename.to_path_buf(), false)); + deps.push((filename.to_path_buf(), DependencyType::Target)); continue; } @@ -925,17 +991,21 @@ pub fn run_cargo( let candidate = format!("{}.lib", path_to_add); let candidate = PathBuf::from(candidate); if candidate.exists() { - deps.push((candidate, false)); + deps.push((candidate, DependencyType::Target)); } } - deps.push((path_to_add.into(), false)); + deps.push((path_to_add.into(), DependencyType::Target)); } - deps.extend(additional_target_deps.into_iter().map(|d| (d, false))); + deps.extend(additional_target_deps); deps.sort(); let mut new_contents = Vec::new(); - for (dep, proc_macro) in deps.iter() { - new_contents.extend(if *proc_macro { b"h" } else { b"t" }); + for (dep, dependency_type) in deps.iter() { + new_contents.extend(match *dependency_type { + DependencyType::Host => b"h", + DependencyType::Target => b"t", + DependencyType::TargetSelfContained => b"s", + }); new_contents.extend(dep.to_str().unwrap().as_bytes()); new_contents.extend(b"\0"); } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index d1e53db573e..47673ce1e87 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -141,6 +141,8 @@ v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs", "rootfs in qemu testing, you probably don't want to use this") v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs", "rootfs in qemu testing, you probably don't want to use this") +v("qemu-riscv64-rootfs", "target.riscv64gc-unknown-linux-gnu.qemu-rootfs", + "rootfs in qemu testing, you probably don't want to use this") v("experimental-targets", "llvm.experimental-targets", "experimental LLVM targets to build") v("release-channel", "rust.channel", "the name of the release channel to build") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index a752d8045f7..8a2463d378f 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -22,7 +22,7 @@ use crate::channel; use crate::compile; use crate::tool::{self, Tool}; use crate::util::{exe, is_dylib, timeit}; -use crate::{Compiler, Mode, LLVM_TOOLS}; +use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; use time::{self, Timespec}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { @@ -306,7 +306,12 @@ fn make_win_dist( } //Copy platform tools to platform-specific bin directory - let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin"); + let target_bin_dir = plat_root + .join("lib") + .join("rustlib") + .join(target_triple) + .join("bin") + .join("self-contained"); fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); for src in target_tools { builder.copy_to_folder(&src, &target_bin_dir); @@ -321,7 +326,12 @@ fn make_win_dist( ); //Copy platform libs to platform-specific lib directory - let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib"); + let target_lib_dir = plat_root + .join("lib") + .join("rustlib") + .join(target_triple) + .join("lib") + .join("self-contained"); fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); for src in target_libs { builder.copy_to_folder(&src, &target_lib_dir); @@ -652,9 +662,13 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool { /// Copy stamped files into an image's `target/lib` directory. fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) { let dst = image.join("lib/rustlib").join(target).join("lib"); + let self_contained_dst = dst.join("self-contained"); t!(fs::create_dir_all(&dst)); - for (path, host) in builder.read_stamp_file(stamp) { - if !host || builder.config.build == target { + t!(fs::create_dir_all(&self_contained_dst)); + for (path, dependency_type) in builder.read_stamp_file(stamp) { + if dependency_type == DependencyType::TargetSelfContained { + builder.copy(&path, &self_contained_dst.join(path.file_name().unwrap())); + } else if dependency_type == DependencyType::Target || builder.config.build == target { builder.copy(&path, &dst.join(path.file_name().unwrap())); } } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5c01c5e852c..6d7fb7acfcb 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -548,8 +548,8 @@ impl Step for Rustc { // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - let interned_root_crate = INTERNER.intern_str(root_crate); - find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates); + compiler_crates + .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name)); } for krate in &compiler_crates { @@ -564,22 +564,6 @@ impl Step for Rustc { } } -fn find_compiler_crates( - builder: &Builder<'_>, - name: &Interned<String>, - crates: &mut HashSet<Interned<String>>, -) { - // Add current crate. - crates.insert(*name); - - // Look for dependencies. - for dep in builder.crates.get(name).unwrap().deps.iter() { - if builder.crates.get(dep).unwrap().is_local(builder) { - find_compiler_crates(builder, dep, crates); - } - } -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { stage: u32, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index cfaa43f3970..f477c752933 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -3,19 +3,17 @@ //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. -use std::fs; +use std::env; use std::path::PathBuf; use std::process; use getopts::Options; use crate::builder::Builder; +use crate::cache::{Interned, INTERNER}; use crate::config::Config; -use crate::metadata; use crate::{Build, DocTests}; -use crate::cache::{Interned, INTERNER}; - /// Deserialized version of all flags for this compile. pub struct Flags { pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo @@ -149,7 +147,12 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", "N", ); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); - opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); + let j_msg = format!( + "number of jobs to run in parallel; \ + defaults to {} (this host's logical CPU count)", + num_cpus::get() + ); + opts.optopt("j", "jobs", &j_msg, "JOBS"); opts.optflag("h", "help", "print this help message"); opts.optopt( "", @@ -433,19 +436,12 @@ Arguments: // Get any optional paths which occur after the subcommand let paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>(); - let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { - if fs::metadata("config.toml").is_ok() { - Some(PathBuf::from("config.toml")) - } else { - None - } - }); + let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); // All subcommands except `clean` can have an optional "Available paths" section if matches.opt_present("verbose") { let config = Config::parse(&["build".to_string()]); - let mut build = Build::new(config); - metadata::build(&mut build); + let build = Build::new(config); let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index fafd3cdf927..fbdef9d8272 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -70,7 +70,10 @@ fn install_sh( let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { - fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display())) + fs::create_dir_all(p) + .unwrap_or_else(|err| panic!("could not create {}: {}", p.display(), err)); + fs::canonicalize(p) + .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", p.display(), err)) }); let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d8a036caef..e7aeb08643c 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -270,16 +270,22 @@ struct Crate { } impl Crate { - fn is_local(&self, build: &Build) -> bool { - self.path.starts_with(&build.config.src) && !self.path.to_string_lossy().ends_with("_shim") - } - fn local_path(&self, build: &Build) -> PathBuf { - assert!(self.is_local(build)); self.path.strip_prefix(&build.config.src).unwrap().into() } } +/// When building Rust various objects are handled differently. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum DependencyType { + /// Libraries originating from proc-macros. + Host, + /// Typical Rust libraries. + Target, + /// Non Rust libraries and objects shipped to ease usage of certain targets. + TargetSelfContained, +} + /// The various "modes" of invoking Cargo. /// /// These entries currently correspond to the various output directories of the @@ -1079,17 +1085,29 @@ impl Build { } } + /// Returns a Vec of all the dependencies of the given root crate, + /// including transitive dependencies and the root itself. Only includes + /// "local" crates (those in the local source tree, not from a registry). fn in_tree_crates(&self, root: &str) -> Vec<&Crate> { let mut ret = Vec::new(); let mut list = vec![INTERNER.intern_str(root)]; let mut visited = HashSet::new(); while let Some(krate) = list.pop() { let krate = &self.crates[&krate]; - if krate.is_local(self) { - ret.push(krate); - } + ret.push(krate); for dep in &krate.deps { - if visited.insert(dep) && dep != "build_helper" { + // Don't include optional deps if their features are not + // enabled. Ideally this would be computed from `cargo + // metadata --features …`, but that is somewhat slow. Just + // skip `build_helper` since there aren't any operations we + // want to perform on it. In the future, we may want to + // consider just filtering all build and dev dependencies in + // metadata::build. + if visited.insert(dep) + && dep != "build_helper" + && (dep != "profiler_builtins" || self.config.profiler) + && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled()) + { list.push(*dep); } } @@ -1097,7 +1115,7 @@ impl Build { ret } - fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, bool)> { + fn read_stamp_file(&self, stamp: &Path) -> Vec<(PathBuf, DependencyType)> { if self.config.dry_run { return Vec::new(); } @@ -1110,9 +1128,14 @@ impl Build { if part.is_empty() { continue; } - let host = part[0] as char == 'h'; + let dependency_type = match part[0] as char { + 'h' => DependencyType::Host, + 's' => DependencyType::TargetSelfContained, + 't' => DependencyType::Target, + _ => unreachable!(), + }; let path = PathBuf::from(t!(str::from_utf8(&part[1..]))); - paths.push((path, host)); + paths.push((path, dependency_type)); } paths } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 292aa3b1e24..a38391c7b88 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; -use std::collections::HashSet; use std::path::PathBuf; use std::process::Command; @@ -12,7 +10,6 @@ use crate::{Build, Crate}; #[derive(Deserialize)] struct Output { packages: Vec<Package>, - resolve: Resolve, } #[derive(Deserialize)] @@ -21,63 +18,25 @@ struct Package { name: String, source: Option<String>, manifest_path: String, + dependencies: Vec<Dependency>, } #[derive(Deserialize)] -struct Resolve { - nodes: Vec<ResolveNode>, -} - -#[derive(Deserialize)] -struct ResolveNode { - id: String, - dependencies: Vec<String>, +struct Dependency { + name: String, + source: Option<String>, } pub fn build(build: &mut Build) { - let mut resolves = Vec::new(); - build_krate(&build.std_features(), build, &mut resolves, "src/libstd"); - build_krate("", build, &mut resolves, "src/libtest"); - build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc"); - - let mut id2name = HashMap::with_capacity(build.crates.len()); - for (name, krate) in build.crates.iter() { - id2name.insert(krate.id.clone(), name.clone()); - } - - for node in resolves { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.insert(*dep); - } - } -} - -fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode>, krate: &str) { // Run `cargo metadata` to figure out what crates we're testing. - // - // Down below we're going to call `cargo test`, but to test the right set - // of packages we're going to have to know what `-p` arguments to pass it - // to know what crates to test. Here we run `cargo metadata` to learn about - // the dependency graph and what `-p` arguments there are. let mut cargo = Command::new(&build.initial_cargo); cargo .arg("metadata") .arg("--format-version") .arg("1") - .arg("--features") - .arg(features) + .arg("--no-deps") .arg("--manifest-path") - .arg(build.src.join(krate).join("Cargo.toml")); + .arg(build.src.join("Cargo.toml")); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); for package in output.packages { @@ -85,8 +44,13 @@ fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec<ResolveNode let name = INTERNER.intern_string(package.name); let mut path = PathBuf::from(package.manifest_path); path.pop(); - build.crates.insert(name, Crate { name, id: package.id, deps: HashSet::new(), path }); + let deps = package + .dependencies + .into_iter() + .filter(|dep| dep.source.is_none()) + .map(|dep| INTERNER.intern_string(dep.name)) + .collect(); + build.crates.insert(name, Crate { name, id: package.id, deps, path }); } } - resolves.extend(output.resolve.nodes); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 252a6316e57..0a14957384d 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -689,48 +689,41 @@ fn supported_sanitizers( target: Interned<String>, channel: &str, ) -> Vec<SanitizerRuntime> { - let mut result = Vec::new(); + let darwin_libs = |os: &str, components: &[&str]| -> Vec<SanitizerRuntime> { + components + .into_iter() + .map(move |c| SanitizerRuntime { + cmake_target: format!("clang_rt.{}_{}_dynamic", c, os), + path: out_dir + .join(&format!("build/lib/darwin/libclang_rt.{}_{}_dynamic.dylib", c, os)), + name: format!("librustc-{}_rt.{}.dylib", channel, c), + }) + .collect() + }; + + let common_libs = |os: &str, arch: &str, components: &[&str]| -> Vec<SanitizerRuntime> { + components + .into_iter() + .map(move |c| SanitizerRuntime { + cmake_target: format!("clang_rt.{}-{}", c, arch), + path: out_dir.join(&format!("build/lib/{}/libclang_rt.{}-{}.a", os, c, arch)), + name: format!("librustc-{}_rt.{}.a", channel, c), + }) + .collect() + }; + match &*target { - "x86_64-apple-darwin" => { - for s in &["asan", "lsan", "tsan"] { - result.push(SanitizerRuntime { - cmake_target: format!("clang_rt.{}_osx_dynamic", s), - path: out_dir - .join(&format!("build/lib/darwin/libclang_rt.{}_osx_dynamic.dylib", s)), - name: format!("librustc-{}_rt.{}.dylib", channel, s), - }); - } + "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), + "aarch64-unknown-linux-gnu" => { + common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"]) } + "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), + "x86_64-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]), "x86_64-unknown-linux-gnu" => { - for s in &["asan", "lsan", "msan", "tsan"] { - result.push(SanitizerRuntime { - cmake_target: format!("clang_rt.{}-x86_64", s), - path: out_dir.join(&format!("build/lib/linux/libclang_rt.{}-x86_64.a", s)), - name: format!("librustc-{}_rt.{}.a", channel, s), - }); - } - } - "x86_64-fuchsia" => { - for s in &["asan"] { - result.push(SanitizerRuntime { - cmake_target: format!("clang_rt.{}-x86_64", s), - path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-x86_64.a", s)), - name: format!("librustc-{}_rt.{}.a", channel, s), - }); - } - } - "aarch64-fuchsia" => { - for s in &["asan"] { - result.push(SanitizerRuntime { - cmake_target: format!("clang_rt.{}-aarch64", s), - path: out_dir.join(&format!("build/lib/fuchsia/libclang_rt.{}-aarch64.a", s)), - name: format!("librustc-{}_rt.{}.a", channel, s), - }); - } + common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"]) } - _ => {} + _ => Vec::new(), } - result } struct HashStamp { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index b8c57515658..8a37a70d60d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -554,7 +554,10 @@ impl Step for Clippy { builder.add_rustc_lib_path(compiler, &mut cargo); - builder.run(&mut cargo.into()); + // FIXME: Disable clippy tests for now, they're failing on master + // (generally this would mean a toolstate failure but we don't have + // toolstate for clippy anymore). + // builder.run(&mut cargo.into()); } } @@ -1645,14 +1648,8 @@ impl Step for Crate { type Output = (); const DEFAULT: bool = true; - fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - 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()); - } - } - run + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.krate("test") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 9c95de0a81e..c92082a9423 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -481,7 +481,7 @@ impl Step for Rustdoc { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rustdoc") + run.path("src/tools/rustdoc").path("src/librustdoc") } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 6c219cee01e..8740393288c 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -272,6 +272,18 @@ impl Builder<'_> { /// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be /// done. The file is updated immediately after this function completes. pub fn save_toolstate(&self, tool: &str, state: ToolState) { + // If we're in a dry run setting we don't want to save toolstates as + // that means if we e.g. panic down the line it'll look like we tested + // everything (but we actually haven't). + if self.config.dry_run { + return; + } + // Toolstate isn't tracked for clippy, but since most tools do, we avoid + // checking in all the places we could save toolstate and just do so + // here. + if tool == "clippy-driver" { + return; + } if let Some(ref path) = self.config.save_toolstates { if let Some(parent) = path.parent() { // Ensure the parent directory always exists diff --git a/src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch b/src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch new file mode 100644 index 00000000000..08d0c5b2cac --- /dev/null +++ b/src/ci/docker/disabled/riscv64gc-linux/0001-Remove-stime-function-calls.patch @@ -0,0 +1,96 @@ +From c820da85c65c7f3aa9e9cb3ed71ada69bf9b783e Mon Sep 17 00:00:00 2001 +From: Alistair Francis <alistair.francis@wdc.com> +Date: Tue, 19 Nov 2019 13:06:40 +0100 +Subject: [PATCH] Remove stime() function calls + +stime() has been deprecated in glibc 2.31 and replaced with +clock_settime(). Let's replace the stime() function calls with +clock_settime() in preperation. + +function old new delta +rdate_main 197 224 +27 +clock_settime - 27 +27 +date_main 926 941 +15 +stime 37 - -37 +------------------------------------------------------------------------------ +(add/remove: 2/2 grow/shrink: 2/0 up/down: 69/-37) Total: 32 bytes + +Signed-off-by: Alistair Francis <alistair.francis@wdc.com> +Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com> + +[Tom Eccles: adjust patch context to apply on top of 1.31.1-stable] +Signed-off-by: Tom Eccles <tom.eccles@codethink.co.uk> +--- + coreutils/date.c | 6 +++++- + libbb/missing_syscalls.c | 8 -------- + util-linux/rdate.c | 8 ++++++-- + 3 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/coreutils/date.c b/coreutils/date.c +index 3414d38ae..4ade6abb4 100644 +--- a/coreutils/date.c ++++ b/coreutils/date.c +@@ -279,6 +279,9 @@ int date_main(int argc UNUSED_PARAM, char **argv) + time(&ts.tv_sec); + #endif + } ++#if !ENABLE_FEATURE_DATE_NANO ++ ts.tv_nsec = 0; ++#endif + localtime_r(&ts.tv_sec, &tm_time); + + /* If date string is given, update tm_time, and maybe set date */ +@@ -301,9 +304,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) + if (date_str[0] != '@') + tm_time.tm_isdst = -1; + ts.tv_sec = validate_tm_time(date_str, &tm_time); ++ ts.tv_nsec = 0; + + /* if setting time, set it */ +- if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) { ++ if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { + bb_perror_msg("can't set date"); + } + } +diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c +index 87cf59b3d..dc40d9155 100644 +--- a/libbb/missing_syscalls.c ++++ b/libbb/missing_syscalls.c +@@ -15,14 +15,6 @@ pid_t getsid(pid_t pid) + return syscall(__NR_getsid, pid); + } + +-int stime(const time_t *t) +-{ +- struct timeval tv; +- tv.tv_sec = *t; +- tv.tv_usec = 0; +- return settimeofday(&tv, NULL); +-} +- + int sethostname(const char *name, size_t len) + { + return syscall(__NR_sethostname, name, len); +diff --git a/util-linux/rdate.c b/util-linux/rdate.c +index 70f829e7f..878375d78 100644 +--- a/util-linux/rdate.c ++++ b/util-linux/rdate.c +@@ -95,9 +95,13 @@ int rdate_main(int argc UNUSED_PARAM, char **argv) + if (!(flags & 2)) { /* no -p (-s may be present) */ + if (time(NULL) == remote_time) + bb_error_msg("current time matches remote time"); +- else +- if (stime(&remote_time) < 0) ++ else { ++ struct timespec ts; ++ ts.tv_sec = remote_time; ++ ts.tv_nsec = 0; ++ if (clock_settime(CLOCK_REALTIME, &ts) < 0) + bb_perror_msg_and_die("can't set time of day"); ++ } + } + + if (flags != 1) /* not lone -s */ +-- +2.25.1 + diff --git a/src/ci/docker/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/disabled/riscv64gc-linux/Dockerfile new file mode 100644 index 00000000000..f21dc2ba309 --- /dev/null +++ b/src/ci/docker/disabled/riscv64gc-linux/Dockerfile @@ -0,0 +1,102 @@ +# based on armhf-gnu/Dockerfile +FROM ubuntu:20.04 + +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections +RUN apt-get update -y && apt-get install -y --no-install-recommends \ + bc \ + bison \ + ca-certificates \ + cmake \ + cpio \ + curl \ + debian-ports-archive-keyring \ + debootstrap \ + flex \ + gcc \ + gcc-riscv64-linux-gnu \ + git \ + g++-riscv64-linux-gnu \ + g++ \ + libc6-dev \ + libc6-dev-riscv64-cross \ + make \ + patch \ + python3 \ + qemu-system-misc \ + xz-utils + +ENV ARCH=riscv +ENV CROSS_COMPILE=riscv64-linux-gnu- + +WORKDIR /build + +# From https://github.com/michaeljclark/busybear-linux/blob/master/conf/linux.config +COPY riscv64gc-linux/linux.config /build + +# Compile the kernel that we're going to be emulating with. This is +# basically just done to be compatible with the QEMU target that we're going +# to be using when running tests. +RUN curl https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.6.16.tar.xz | tar xJf - && \ + cp linux.config linux-5.6.16/.config && \ + cd /build/linux-5.6.16 && \ + make olddefconfig && \ + make -j$(nproc) vmlinux +RUN cp linux-5.6.16/vmlinux /tmp +RUN rm -rf linux-5.6.16 + +# Compile an instance of busybox as this provides a lightweight system and init +# binary which we will boot into. Only trick here is configuring busybox to +# build static binaries. +RUN curl https://busybox.net/downloads/busybox-1.31.1.tar.bz2 | tar xjf - +COPY riscv64gc-linux/0001-Remove-stime-function-calls.patch /build/busybox-1.31.1/ +RUN cd /build/busybox-1.31.1 && \ + patch -p1 -i 0001-Remove-stime-function-calls.patch && \ + make defconfig && \ + sed -i 's/.*CONFIG_STATIC.*/CONFIG_STATIC=y/' .config && \ + make -j$(nproc) && \ + make install && \ + mv _install /tmp/rootfs && \ + cd /build && \ + rm -rf busybox-1.31.1 + +# Download the ubuntu rootfs, which we'll use as a chroot for all our tests +# This is only needed to provide /lib/* and /usr/lib/* +WORKDIR /tmp +RUN debootstrap --variant=minbase --arch=riscv64 --foreign focal /tmp/rootfs/ubuntu +RUN cd rootfs && mkdir proc sys dev etc etc/init.d +# rootfs/ubuntu/proc is in a weird state (access fails with ELOOP) until +# rootfs/ubuntu/debootstrap/debootstrap --second-stage is run (under emulation), +# but this takes ages. Instead hack it into a good enough state. +# /proc is used by std::env::current_exe() (which is roughly +# `readlink /proc/self/exe`) +RUN cd rootfs/ubuntu && rm -rf proc && mkdir proc + +# Copy over our init script, which starts up our test server and also a few other +# misc tasks +COPY scripts/qemu-bare-bones-rcS rootfs/etc/init.d/rcS +RUN chmod +x rootfs/etc/init.d/rcS + +# Helper to quickly fill the entropy pool in the kernel +COPY scripts/qemu-bare-bones-addentropy.c /tmp/addentropy.c +RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static + +# download and build the riscv bootloader +RUN git clone https://github.com/riscv/riscv-pk +WORKDIR /tmp/riscv-pk +# nothing special about this revision: it is just master at the time of writing +# v1.0.0 doesn't build +RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304 +RUN mkdir build && cd build && \ + ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \ + make -j$(nproc) && \ + cp bbl /tmp +WORKDIR /tmp +RUN rm -rf /tmp/riscv-pk + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV RUST_CONFIGURE_ARGS --qemu-riscv64-rootfs=/tmp/rootfs +ENV SCRIPT python3 ../x.py test --target riscv64gc-unknown-linux-gnu + +ENV NO_CHANGE_USER=1 diff --git a/src/ci/docker/disabled/riscv64gc-linux/linux.config b/src/ci/docker/disabled/riscv64gc-linux/linux.config new file mode 100644 index 00000000000..5142664742f --- /dev/null +++ b/src/ci/docker/disabled/riscv64gc-linux/linux.config @@ -0,0 +1,51 @@ +CONFIG_DEFAULT_HOSTNAME="busybear" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_USER_NS=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +CONFIG_BPF_SYSCALL=y +CONFIG_SMP=y +CONFIG_MODULES=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_NETLINK_DIAG=y +# CONFIG_WIRELESS is not set +CONFIG_PCI=y +CONFIG_DEVTMPFS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_VIRTIO_BLK=y +CONFIG_NETDEVICES=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +# CONFIG_WLAN is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_HVC_RISCV_SBI=y +# CONFIG_HW_RANDOM is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_VIRTIO_MMIO=y +CONFIG_SIFIVE_PLIC=y +CONFIG_RAS=y +CONFIG_EXT2_FS=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_AUTOFS4_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_HW is not set +CONFIG_PRINTK_TIME=y diff --git a/src/ci/docker/dist-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index 74766dc970d..fd764965ef2 100644 --- a/src/ci/docker/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -35,5 +35,6 @@ ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ --enable-profiler \ + --enable-sanitizers \ --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index c9d1cb21da8..b4b23a245e0 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -14,11 +14,13 @@ python3 "$X_PY" test --no-fail-fast \ src/doc/rust-by-example \ src/doc/embedded-book \ src/doc/edition-guide \ - src/tools/clippy \ src/tools/rls \ src/tools/rustfmt \ src/tools/miri \ set -e +# debugging: print out the saved toolstates +cat /tmp/toolstate/toolstates.json python3 "$X_PY" test check-tools +python3 "$X_PY" test src/tools/clippy diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index 7ebd8054ba0..5e2e04c063b 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -12,8 +12,7 @@ This feature allows for use of one of following sanitizers: * [ThreadSanitizer][clang-tsan] a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=leak`, -`-Zsanitizer=memory` or `-Zsanitizer=thread`. Only a single sanitizer can be -enabled at a time. +`-Zsanitizer=memory` or `-Zsanitizer=thread`. # AddressSanitizer diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index fbb40f1d2f3..a941bc9348f 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -68,10 +68,13 @@ Let us see another example that also uses an input: let i: u64 = 3; let o: u64; unsafe { - asm!(" - mov {0}, {1} - add {0}, {number} - ", out(reg) o, in(reg) i, number = const 5); + asm!( + "mov {0}, {1}", + "add {0}, {number}", + out(reg) o, + in(reg) i, + number = const 5, + ); } assert_eq!(o, 8); ``` @@ -82,13 +85,18 @@ and then adding `5` to it. The example shows a few things: -First we can see that inputs are declared by writing `in` instead of `out`. +First, we can see that `asm!` allows multiple template string arguments; each +one is treated as a separate line of assembly code, as if they were all joined +together with newlines between them. This makes it easy to format assembly +code. + +Second, we can see that inputs are declared by writing `in` instead of `out`. -Second one of our operands has a type we haven't seen yet, `const`. +Third, one of our operands has a type we haven't seen yet, `const`. This tells the compiler to expand this argument to value directly inside the assembly template. This is only possible for constants and literals. -Third we can see that we can specify an argument number, or name as in any format string. +Fourth, we can see that we can specify an argument number, or name as in any format string. For inline assembly templates this is particularly useful as arguments are often used more than once. For more complex inline assembly using this facility is generally recommended, as it improves readability, and allows reordering instructions without changing the argument order. @@ -137,10 +145,13 @@ let mut a: u64 = 4; let b: u64 = 4; let c: u64 = 4; unsafe { - asm!(" - add {0}, {1} - add {0}, {2} - ", inout(reg) a, in(reg) b, in(reg) c); + asm!( + "add {0}, {1}", + "add {0}, {2}", + inout(reg) a, + in(reg) b, + in(reg) c, + ); } assert_eq!(a, 12); ``` @@ -233,7 +244,7 @@ unsafe { // ECX 0 selects the L0 cache information. inout("ecx") 0 => ecx, lateout("ebx") ebx, - lateout("edx") _ + lateout("edx") _, ); } @@ -255,12 +266,14 @@ This can also be used with a general register class (e.g. `reg`) to obtain a scr // Multiply x by 6 using shifts and adds let mut x: u64 = 4; unsafe { - asm!(" - mov {tmp}, {x} - shl {tmp}, 1 - shl {x}, 2 - add {x}, {tmp} - ", x = inout(reg) x, tmp = out(reg) _); + asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); } assert_eq!(x, 4 * 6); ``` @@ -338,7 +351,7 @@ unsafe { asm!( "add {0}, {1}", inlateout(reg) a, in(reg) b, - options(pure, nomem, nostack) + options(pure, nomem, nostack), ); } assert_eq!(a, 8); @@ -371,24 +384,26 @@ reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax" options := "options(" option *["," option] [","] ")" -asm := "asm!(" format_string *("," [ident "="] operand) ["," options] [","] ")" +asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")" ``` -The macro will initially be supported only on ARM, AArch64, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. +The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target. [format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax -## Template string +## Template string arguments The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported. +An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments. + As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any. Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated. The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler. -The 4 targets specified in this RFC (x86, ARM, AArch64, RISC-V) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. +The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior. [rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795 @@ -475,6 +490,7 @@ Here is the list of currently supported register classes: | NVPTX | `reg64` | None\* | `l` | | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | +| Hexagon | `reg` | `r[0-28]` | `r` | > **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > @@ -509,6 +525,7 @@ Each register class has constraints on which value types they can be used with. | RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | RISC-V | `freg` | `f` | `f32` | | RISC-V | `freg` | `d` | `f64` | +| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -565,13 +582,16 @@ Some registers have multiple names. These are all treated by the compiler as ide | RISC-V | `f[10-17]` | `fa[0-7]` | | RISC-V | `f[18-27]` | `fs[2-11]` | | RISC-V | `f[28-31]` | `ft[8-11]` | +| Hexagon | `r29` | `sp` | +| Hexagon | `r30` | `fr` | +| Hexagon | `r31` | `lr` | Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | | x86 | `ip` | This is the program counter, not a real register. | | x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). | @@ -580,6 +600,7 @@ Some registers cannot be used for input or output operands: | ARM | `pc` | This is the program counter, not a real register. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | +| Hexagon | `lr` | This is the link register which cannot be used as an input or output. | ## Template modifiers @@ -625,6 +646,7 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | NVPTX | `reg64` | None | `rd0` | None | | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | +| Hexagon | `reg` | None | `r0` | None | > Notes: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index d1119f7b7c0..914195f015b 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -25,6 +25,7 @@ path = "../liballoc/tests/lib.rs" [[bench]] name = "collectionsbenches" path = "../liballoc/benches/lib.rs" +test = true [[bench]] name = "vec_deque_append_bench" diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index d31c73cc1bd..98c7ac3f2ef 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -77,7 +77,7 @@ pub struct Global; #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn alloc(layout: Layout) -> *mut u8 { - __rust_alloc(layout.size(), layout.align()) + unsafe { __rust_alloc(layout.size(), layout.align()) } } /// Deallocate memory with the global allocator. @@ -99,7 +99,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) + unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } } /// Reallocate memory with the global allocator. @@ -121,7 +121,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - __rust_realloc(ptr, layout.size(), layout.align(), new_size) + unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } } /// Allocate zero-initialized memory with the global allocator. @@ -158,7 +158,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { - __rust_alloc_zeroed(layout.size(), layout.align()) + unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } } #[unstable(feature = "allocator_api", issue = "32838")] @@ -183,7 +183,7 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { if layout.size() != 0 { - dealloc(ptr.as_ptr(), layout) + unsafe { dealloc(ptr.as_ptr(), layout) } } } @@ -209,16 +209,21 @@ unsafe impl AllocRef for Global { match placement { ReallocPlacement::InPlace => Err(AllocErr), ReallocPlacement::MayMove if layout.size() == 0 => { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_layout = + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; self.alloc(new_layout, init) } ReallocPlacement::MayMove => { // `realloc` probably checks for `new_size > size` or something similar. - intrinsics::assume(new_size > size); - let ptr = realloc(ptr.as_ptr(), layout, new_size); + let ptr = unsafe { + intrinsics::assume(new_size > size); + realloc(ptr.as_ptr(), layout, new_size) + }; let memory = MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }; - init.init_offset(memory, size); + unsafe { + init.init_offset(memory, size); + } Ok(memory) } } @@ -245,13 +250,17 @@ unsafe impl AllocRef for Global { match placement { ReallocPlacement::InPlace => Err(AllocErr), ReallocPlacement::MayMove if new_size == 0 => { - self.dealloc(ptr, layout); + unsafe { + self.dealloc(ptr, layout); + } Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) } ReallocPlacement::MayMove => { // `realloc` probably checks for `new_size < size` or something similar. - intrinsics::assume(new_size < size); - let ptr = realloc(ptr.as_ptr(), layout, new_size); + let ptr = unsafe { + intrinsics::assume(new_size < size); + realloc(ptr.as_ptr(), layout, new_size) + }; Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }) } } @@ -264,7 +273,7 @@ unsafe impl AllocRef for Global { #[lang = "exchange_malloc"] #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.alloc(layout, AllocInit::Uninitialized) { Ok(memory) => memory.ptr.as_ptr(), Err(_) => handle_alloc_error(layout), @@ -279,10 +288,12 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { // For example if `Box` is changed to `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`, // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well. pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { - let size = size_of_val(ptr.as_ref()); - let align = min_align_of_val(ptr.as_ref()); - let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr.cast().into(), layout) + unsafe { + let size = size_of_val(ptr.as_ref()); + let align = min_align_of_val(ptr.as_ref()); + let layout = Layout::from_size_align_unchecked(size, align); + Global.dealloc(ptr.cast().into(), layout) + } } /// Abort on memory allocation error or failure. diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 22c344323a2..d10cbf1afab 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -248,7 +248,7 @@ impl<T> Box<T> { #[unstable(feature = "box_into_boxed_slice", issue = "71582")] pub fn into_boxed_slice(boxed: Box<T>) -> Box<[T]> { // *mut T and *mut [T; 1] have the same size and alignment - unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1] as *mut [T]) } + unsafe { Box::from_raw(Box::into_raw(boxed) as *mut [T; 1]) } } } @@ -311,7 +311,7 @@ impl<T> Box<mem::MaybeUninit<T>> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<T> { - Box::from_raw(Box::into_raw(self) as *mut T) + unsafe { Box::from_raw(Box::into_raw(self) as *mut T) } } } @@ -349,7 +349,7 @@ impl<T> Box<[mem::MaybeUninit<T>]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Box<[T]> { - Box::from_raw(Box::into_raw(self) as *mut [T]) + unsafe { Box::from_raw(Box::into_raw(self) as *mut [T]) } } } @@ -393,7 +393,7 @@ impl<T: ?Sized> Box<T> { #[stable(feature = "box_raw", since = "1.4.0")] #[inline] pub unsafe fn from_raw(raw: *mut T) -> Self { - Box(Unique::new_unchecked(raw)) + Box(unsafe { Unique::new_unchecked(raw) }) } /// Consumes the `Box`, returning a wrapped raw pointer. diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index c2fe4691b34..15313e333ce 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1003,7 +1003,7 @@ impl<'a, T> Hole<'a, T> { unsafe fn new(data: &'a mut [T], pos: usize) -> Self { debug_assert!(pos < data.len()); // SAFE: pos should be inside the slice - let elt = ptr::read(data.get_unchecked(pos)); + let elt = unsafe { ptr::read(data.get_unchecked(pos)) }; Hole { data, elt: ManuallyDrop::new(elt), pos } } @@ -1025,7 +1025,7 @@ impl<'a, T> Hole<'a, T> { unsafe fn get(&self, index: usize) -> &T { debug_assert!(index != self.pos); debug_assert!(index < self.data.len()); - self.data.get_unchecked(index) + unsafe { self.data.get_unchecked(index) } } /// Move hole to new location @@ -1035,9 +1035,11 @@ impl<'a, T> Hole<'a, T> { unsafe fn move_to(&mut self, index: usize) { debug_assert!(index != self.pos); debug_assert!(index < self.data.len()); - let index_ptr: *const _ = self.data.get_unchecked(index); - let hole_ptr = self.data.get_unchecked_mut(self.pos); - ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + unsafe { + let index_ptr: *const _ = self.data.get_unchecked(index); + let hole_ptr = self.data.get_unchecked_mut(self.pos); + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + } self.pos = index; } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index fa1c09d9ece..2fcc8cc9873 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1725,7 +1725,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { &mut self, ) -> Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>> { let edge = self.cur_leaf_edge.as_ref()?; - ptr::read(edge).next_kv().ok() + unsafe { ptr::read(edge).next_kv().ok() } } /// Implementation of a typical `DrainFilter::next` method, given the predicate. @@ -1808,7 +1808,7 @@ impl<'a, K, V> Range<'a, K, V> { } unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - unwrap_unchecked(self.front.as_mut()).next_unchecked() + unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } } @@ -1821,7 +1821,7 @@ impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { impl<'a, K, V> Range<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - unwrap_unchecked(self.back.as_mut()).next_back_unchecked() + unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } @@ -1859,7 +1859,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unwrap_unchecked(self.front.as_mut()).next_unchecked() + unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } } @@ -1880,7 +1880,7 @@ impl<K, V> FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - unwrap_unchecked(self.back.as_mut()).next_back_unchecked() + unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } diff --git a/src/liballoc/collections/btree/mod.rs b/src/liballoc/collections/btree/mod.rs index fb5825ee21a..543ff41a4d4 100644 --- a/src/liballoc/collections/btree/mod.rs +++ b/src/liballoc/collections/btree/mod.rs @@ -19,7 +19,9 @@ pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T { if cfg!(debug_assertions) { panic!("'unchecked' unwrap on None in BTreeMap"); } else { - core::intrinsics::unreachable(); + unsafe { + core::intrinsics::unreachable(); + } } }) } diff --git a/src/liballoc/collections/btree/navigate.rs b/src/liballoc/collections/btree/navigate.rs index 5e8dcf247ae..5478d822438 100644 --- a/src/liballoc/collections/btree/navigate.rs +++ b/src/liballoc/collections/btree/navigate.rs @@ -64,8 +64,10 @@ macro_rules! def_next_kv_uncheched_dealloc { edge = match edge.$adjacent_kv() { Ok(internal_kv) => return internal_kv, Err(last_edge) => { - let parent_edge = last_edge.into_node().deallocate_and_ascend(); - unwrap_unchecked(parent_edge).forget_node_type() + unsafe { + let parent_edge = last_edge.into_node().deallocate_and_ascend(); + unwrap_unchecked(parent_edge).forget_node_type() + } } } } @@ -82,9 +84,11 @@ def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_k /// Safety: The change closure must not panic. #[inline] unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { - let value = ptr::read(v); + let value = unsafe { ptr::read(v) }; let (new_value, ret) = change(value); - ptr::write(v, new_value); + unsafe { + ptr::write(v, new_value); + } ret } @@ -93,22 +97,26 @@ impl<'a, K, V> Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Ed /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_leaf_edge(), kv.into_kv()) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unwrap_unchecked(kv.ok()); + (kv.next_leaf_edge(), kv.into_kv()) + }) + } } /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { - replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (kv.next_back_leaf_edge(), kv.into_kv()) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unwrap_unchecked(kv.ok()); + (kv.next_back_leaf_edge(), kv.into_kv()) + }) + } } } @@ -119,14 +127,16 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the last one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + unsafe { + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unwrap_unchecked(kv.ok()); + (ptr::read(&kv).next_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() + } } /// Moves the leaf edge handle to the previous leaf and returns references to the @@ -135,14 +145,16 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge /// - The caller must ensure that the leaf edge is not the first one in the tree. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { - let kv = replace(self, |leaf_edge| { - let kv = leaf_edge.next_back_kv(); - let kv = unwrap_unchecked(kv.ok()); - (ptr::read(&kv).next_back_leaf_edge(), kv) - }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + unsafe { + let kv = replace(self, |leaf_edge| { + let kv = leaf_edge.next_back_kv(); + let kv = unwrap_unchecked(kv.ok()); + (ptr::read(&kv).next_back_leaf_edge(), kv) + }); + // Doing the descend (and perhaps another move) invalidates the references + // returned by `into_kv_mut`, so we have to do this last. + kv.into_kv_mut() + } } } @@ -159,12 +171,14 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> { /// if the two preconditions above hold. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_unchecked(&mut self) -> (K, V) { - replace(self, |leaf_edge| { - let kv = next_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_leaf_edge(), (k, v)) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = next_kv_unchecked_dealloc(leaf_edge); + let k = ptr::read(kv.reborrow().into_kv().0); + let v = ptr::read(kv.reborrow().into_kv().1); + (kv.next_leaf_edge(), (k, v)) + }) + } } /// Moves the leaf edge handle to the previous leaf edge and returns the key @@ -179,12 +193,14 @@ impl<K, V> Handle<NodeRef<marker::Owned, K, V, marker::Leaf>, marker::Edge> { /// if the two preconditions above hold. /// - Using the updated handle may well invalidate the returned references. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { - replace(self, |leaf_edge| { - let kv = next_back_kv_unchecked_dealloc(leaf_edge); - let k = ptr::read(kv.reborrow().into_kv().0); - let v = ptr::read(kv.reborrow().into_kv().1); - (kv.next_back_leaf_edge(), (k, v)) - }) + unsafe { + replace(self, |leaf_edge| { + let kv = next_back_kv_unchecked_dealloc(leaf_edge); + let k = ptr::read(kv.reborrow().into_kv().0); + let v = ptr::read(kv.reborrow().into_kv().1); + (kv.next_back_leaf_edge(), (k, v)) + }) + } } } diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 5569c293e2f..a4b6cf12a23 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -107,7 +107,7 @@ impl<K, V> InternalNode<K, V> { /// `len` of 0), there must be one initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Self { - InternalNode { data: LeafNode::new(), edges: [MaybeUninit::UNINIT; 2 * B] } + InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] } } } @@ -131,7 +131,7 @@ impl<K, V> BoxedNode<K, V> { } unsafe fn from_ptr(ptr: NonNull<LeafNode<K, V>>) -> Self { - BoxedNode { ptr: Unique::new_unchecked(ptr.as_ptr()) } + BoxedNode { ptr: unsafe { Unique::new_unchecked(ptr.as_ptr()) } } } fn as_ptr(&self) -> NonNull<LeafNode<K, V>> { @@ -392,14 +392,16 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> { let height = self.height; let node = self.node; let ret = self.ascend().ok(); - Global.dealloc( - node.cast(), - if height > 0 { - Layout::new::<InternalNode<K, V>>() - } else { - Layout::new::<LeafNode<K, V>>() - }, - ); + unsafe { + Global.dealloc( + node.cast(), + if height > 0 { + Layout::new::<InternalNode<K, V>>() + } else { + Layout::new::<LeafNode<K, V>>() + }, + ); + } ret } } @@ -565,7 +567,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> { debug_assert!(first <= self.len()); debug_assert!(after_last <= self.len() + 1); for i in first..after_last { - Handle::new_edge(self.reborrow_mut(), i).correct_parent_link(); + unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); } } @@ -789,7 +791,7 @@ impl<'a, K, V, NodeType, HandleType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeT &mut self, ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type - Handle { node: self.node.reborrow_mut(), idx: self.idx, _marker: PhantomData } + Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData } } } @@ -885,7 +887,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: unsafe fn cast_unchecked<NewType>( &mut self, ) -> Handle<NodeRef<marker::Mut<'_>, K, V, NewType>, marker::Edge> { - Handle::new_edge(self.node.cast_unchecked(), self.idx) + unsafe { Handle::new_edge(self.node.cast_unchecked(), self.idx) } } /// Inserts a new key/value pair and an edge that will go to the right of that new pair @@ -1330,8 +1332,10 @@ unsafe fn move_kv<K, V>( dest_offset: usize, count: usize, ) { - ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count); - ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count); + unsafe { + ptr::copy_nonoverlapping(source.0.add(source_offset), dest.0.add(dest_offset), count); + ptr::copy_nonoverlapping(source.1.add(source_offset), dest.1.add(dest_offset), count); + } } // Source and destination must have the same height. @@ -1344,8 +1348,10 @@ unsafe fn move_edges<K, V>( ) { let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); - ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + unsafe { + ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); + dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + } } impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> { @@ -1459,12 +1465,16 @@ pub mod marker { } unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) { - ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx); - ptr::write(slice.get_unchecked_mut(idx), val); + unsafe { + ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx); + ptr::write(slice.get_unchecked_mut(idx), val); + } } unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T { - let ret = ptr::read(slice.get_unchecked(idx)); - ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1); - ret + unsafe { + let ret = ptr::read(slice.get_unchecked(idx)); + ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1); + ret + } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 85f2505f756..36b5785fdf6 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -225,17 +225,17 @@ impl<T> LinkedList<T> { /// maintain validity of aliasing pointers. #[inline] unsafe fn unlink_node(&mut self, mut node: NonNull<Node<T>>) { - let node = node.as_mut(); // this one is ours now, we can create an &mut. + let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. // Not creating new mutable (unique!) references overlapping `element`. match node.prev { - Some(prev) => (*prev.as_ptr()).next = node.next, + Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, // this node is the head node None => self.head = node.next, }; match node.next { - Some(next) => (*next.as_ptr()).prev = node.prev, + Some(next) => unsafe { (*next.as_ptr()).prev = node.prev }, // this node is the tail node None => self.tail = node.prev, }; @@ -258,17 +258,23 @@ impl<T> LinkedList<T> { // This method takes care not to create multiple mutable references to whole nodes at the same time, // to maintain validity of aliasing pointers into `element`. if let Some(mut existing_prev) = existing_prev { - existing_prev.as_mut().next = Some(splice_start); + unsafe { + existing_prev.as_mut().next = Some(splice_start); + } } else { self.head = Some(splice_start); } if let Some(mut existing_next) = existing_next { - existing_next.as_mut().prev = Some(splice_end); + unsafe { + existing_next.as_mut().prev = Some(splice_end); + } } else { self.tail = Some(splice_end); } - splice_start.as_mut().prev = existing_prev; - splice_end.as_mut().next = existing_next; + unsafe { + splice_start.as_mut().prev = existing_prev; + splice_end.as_mut().next = existing_next; + } self.len += splice_length; } @@ -297,9 +303,13 @@ impl<T> LinkedList<T> { if let Some(mut split_node) = split_node { let first_part_head; let first_part_tail; - first_part_tail = split_node.as_mut().prev.take(); + unsafe { + first_part_tail = split_node.as_mut().prev.take(); + } if let Some(mut tail) = first_part_tail { - tail.as_mut().next = None; + unsafe { + tail.as_mut().next = None; + } first_part_head = self.head; } else { first_part_head = None; @@ -333,9 +343,13 @@ impl<T> LinkedList<T> { if let Some(mut split_node) = split_node { let second_part_head; let second_part_tail; - second_part_head = split_node.as_mut().next.take(); + unsafe { + second_part_head = split_node.as_mut().next.take(); + } if let Some(mut head) = second_part_head { - head.as_mut().prev = None; + unsafe { + head.as_mut().prev = None; + } second_part_tail = self.tail; } else { second_part_tail = None; diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index ae54d3971ba..15f3a94ca2d 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -7,6 +7,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +// ignore-tidy-filelength + use core::array::LengthAtMost32; use core::cmp::{self, Ordering}; use core::fmt; @@ -201,25 +203,27 @@ impl<T> VecDeque<T> { /// Turn ptr into a slice #[inline] unsafe fn buffer_as_slice(&self) -> &[T] { - slice::from_raw_parts(self.ptr(), self.cap()) + unsafe { slice::from_raw_parts(self.ptr(), self.cap()) } } /// Turn ptr into a mut slice #[inline] unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { - slice::from_raw_parts_mut(self.ptr(), self.cap()) + unsafe { slice::from_raw_parts_mut(self.ptr(), self.cap()) } } /// Moves an element out of the buffer #[inline] unsafe fn buffer_read(&mut self, off: usize) -> T { - ptr::read(self.ptr().add(off)) + unsafe { ptr::read(self.ptr().add(off)) } } /// Writes an element into the buffer, moving it. #[inline] unsafe fn buffer_write(&mut self, off: usize, value: T) { - ptr::write(self.ptr().add(off), value); + unsafe { + ptr::write(self.ptr().add(off), value); + } } /// Returns `true` if the buffer is at full capacity. @@ -268,7 +272,9 @@ impl<T> VecDeque<T> { len, self.cap() ); - ptr::copy(self.ptr().add(src), self.ptr().add(dst), len); + unsafe { + ptr::copy(self.ptr().add(src), self.ptr().add(dst), len); + } } /// Copies a contiguous block of memory len long from src to dst @@ -290,7 +296,9 @@ impl<T> VecDeque<T> { len, self.cap() ); - ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len); + unsafe { + ptr::copy_nonoverlapping(self.ptr().add(src), self.ptr().add(dst), len); + } } /// Copies a potentially wrapping block of memory len long from src to dest. @@ -330,7 +338,9 @@ impl<T> VecDeque<T> { // 2 [_ _ A A A A B B _] // D . . . // - self.copy(dst, src, len); + unsafe { + self.copy(dst, src, len); + } } (false, false, true) => { // dst before src, src doesn't wrap, dst wraps @@ -341,8 +351,10 @@ impl<T> VecDeque<T> { // 3 [B B B B _ _ _ A A] // . . D . // - self.copy(dst, src, dst_pre_wrap_len); - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + unsafe { + self.copy(dst, src, dst_pre_wrap_len); + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + } } (true, false, true) => { // src before dst, src doesn't wrap, dst wraps @@ -353,8 +365,10 @@ impl<T> VecDeque<T> { // 3 [B B _ _ _ A A A A] // . . D . // - self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); - self.copy(dst, src, dst_pre_wrap_len); + unsafe { + self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len); + self.copy(dst, src, dst_pre_wrap_len); + } } (false, true, false) => { // dst before src, src wraps, dst doesn't wrap @@ -365,8 +379,10 @@ impl<T> VecDeque<T> { // 3 [C C _ _ _ B B C C] // D . . . // - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + unsafe { + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + } } (true, true, false) => { // src before dst, src wraps, dst doesn't wrap @@ -377,8 +393,10 @@ impl<T> VecDeque<T> { // 3 [C C A A _ _ _ C C] // D . . . // - self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); - self.copy(dst, src, src_pre_wrap_len); + unsafe { + self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len); + self.copy(dst, src, src_pre_wrap_len); + } } (false, true, true) => { // dst before src, src wraps, dst wraps @@ -392,9 +410,11 @@ impl<T> VecDeque<T> { // debug_assert!(dst_pre_wrap_len > src_pre_wrap_len); let delta = dst_pre_wrap_len - src_pre_wrap_len; - self.copy(dst, src, src_pre_wrap_len); - self.copy(dst + src_pre_wrap_len, 0, delta); - self.copy(0, delta, len - dst_pre_wrap_len); + unsafe { + self.copy(dst, src, src_pre_wrap_len); + self.copy(dst + src_pre_wrap_len, 0, delta); + self.copy(0, delta, len - dst_pre_wrap_len); + } } (true, true, true) => { // src before dst, src wraps, dst wraps @@ -408,9 +428,11 @@ impl<T> VecDeque<T> { // debug_assert!(src_pre_wrap_len > dst_pre_wrap_len); let delta = src_pre_wrap_len - dst_pre_wrap_len; - self.copy(delta, 0, len - src_pre_wrap_len); - self.copy(0, self.cap() - delta, delta); - self.copy(dst, src, dst_pre_wrap_len); + unsafe { + self.copy(delta, 0, len - src_pre_wrap_len); + self.copy(0, self.cap() - delta, delta); + self.copy(dst, src, dst_pre_wrap_len); + } } } } @@ -440,13 +462,17 @@ impl<T> VecDeque<T> { // Nop } else if self.head < old_capacity - self.tail { // B - self.copy_nonoverlapping(old_capacity, 0, self.head); + unsafe { + self.copy_nonoverlapping(old_capacity, 0, self.head); + } self.head += old_capacity; debug_assert!(self.head > self.tail); } else { // C let new_tail = new_capacity - (old_capacity - self.tail); - self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail); + unsafe { + self.copy_nonoverlapping(new_tail, self.tail, old_capacity - self.tail); + } self.tail = new_tail; debug_assert!(self.head < self.tail); } @@ -2297,7 +2323,9 @@ impl<T> VecDeque<T> { unsafe fn rotate_left_inner(&mut self, mid: usize) { debug_assert!(mid * 2 <= self.len()); - self.wrap_copy(self.head, self.tail, mid); + unsafe { + self.wrap_copy(self.head, self.tail, mid); + } self.head = self.wrap_add(self.head, mid); self.tail = self.wrap_add(self.tail, mid); } @@ -2306,7 +2334,9 @@ impl<T> VecDeque<T> { debug_assert!(k * 2 <= self.len()); self.head = self.wrap_sub(self.head, k); self.tail = self.wrap_sub(self.tail, k); - self.wrap_copy(self.tail, self.head, k); + unsafe { + self.wrap_copy(self.tail, self.head, k); + } } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 9bcfc9457f5..41c2b221704 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,6 +72,7 @@ #![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] +#![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] #![feature(allocator_api)] @@ -118,6 +119,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode_internals)] +#![feature(unsafe_block_in_unsafe_fn)] #![feature(unsize)] #![feature(unsized_locals)] #![feature(allocator_internals)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 805dbfe2775..15e81f92887 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -108,7 +108,7 @@ impl<T> RawVec<T, Global> { /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed. #[inline] pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self { - Self::from_raw_parts_in(ptr, capacity, Global) + unsafe { Self::from_raw_parts_in(ptr, capacity, Global) } } /// Converts a `Box<[T]>` into a `RawVec<T>`. @@ -139,8 +139,10 @@ impl<T> RawVec<T, Global> { ); let me = ManuallyDrop::new(self); - let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); - Box::from_raw(slice) + unsafe { + let slice = slice::from_raw_parts_mut(me.ptr() as *mut MaybeUninit<T>, len); + Box::from_raw(slice) + } } } @@ -192,7 +194,7 @@ impl<T, A: AllocRef> RawVec<T, A> { /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed. #[inline] pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self { - Self { ptr: Unique::new_unchecked(ptr), cap: capacity, alloc: a } + Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a } } /// Gets a raw pointer to the start of the allocation. Note that this is diff --git a/src/liballoc/raw_vec/tests.rs b/src/liballoc/raw_vec/tests.rs index 17622d72a05..6418c4a9823 100644 --- a/src/liballoc/raw_vec/tests.rs +++ b/src/liballoc/raw_vec/tests.rs @@ -35,7 +35,7 @@ fn allocator_param() { } } unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) { - Global.dealloc(ptr, layout) + unsafe { Global.dealloc(ptr, layout) } } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 0327a9f9a96..4d50ae9efca 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -304,7 +304,7 @@ impl<T: ?Sized> Rc<T> { } unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self { - Self::from_inner(NonNull::new_unchecked(ptr)) + Self::from_inner(unsafe { NonNull::new_unchecked(ptr) }) } } @@ -544,7 +544,7 @@ impl<T> Rc<[mem::MaybeUninit<T>]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Rc<[T]> { - Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + unsafe { Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) } } } @@ -643,13 +643,13 @@ impl<T: ?Sized> Rc<T> { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - let offset = data_offset(ptr); + let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcBox. let fake_ptr = ptr as *mut RcBox<T>; - let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) }; - Self::from_ptr(rc_ptr) + unsafe { Self::from_ptr(rc_ptr) } } /// Consumes the `Rc`, returning the wrapped pointer as `NonNull<T>`. @@ -805,7 +805,7 @@ impl<T: ?Sized> Rc<T> { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - &mut this.ptr.as_mut().value + unsafe { &mut this.ptr.as_mut().value } } #[inline] @@ -964,10 +964,12 @@ impl<T: ?Sized> Rc<T> { // Initialize the RcBox let inner = mem_to_rcbox(mem.ptr.as_ptr()); - debug_assert_eq!(Layout::for_value(&*inner), layout); + unsafe { + debug_assert_eq!(Layout::for_value(&*inner), layout); - ptr::write(&mut (*inner).strong, Cell::new(1)); - ptr::write(&mut (*inner).weak, Cell::new(1)); + ptr::write(&mut (*inner).strong, Cell::new(1)); + ptr::write(&mut (*inner).weak, Cell::new(1)); + } inner } @@ -975,9 +977,11 @@ impl<T: ?Sized> Rc<T> { /// Allocates an `RcBox<T>` with sufficient space for an unsized inner value unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> { // Allocate for the `RcBox<T>` using the given value. - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T> - }) + unsafe { + Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { + set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T> + }) + } } fn from_box(v: Box<T>) -> Rc<T> { @@ -1006,9 +1010,11 @@ impl<T: ?Sized> Rc<T> { impl<T> Rc<[T]> { /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { - Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> - }) + unsafe { + Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> + }) + } } } @@ -1017,7 +1023,9 @@ impl<T> Rc<[T]> { /// For a slice/trait object, this sets the `data` field and leaves the rest /// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + unsafe { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + } ptr } @@ -1026,11 +1034,11 @@ impl<T> Rc<[T]> { /// /// Unsafe because the caller must either take ownership or bind `T: Copy` unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { - let ptr = Self::allocate_for_slice(v.len()); - - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); - - Self::from_ptr(ptr) + unsafe { + let ptr = Self::allocate_for_slice(v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).value as *mut [T] as *mut T, v.len()); + Self::from_ptr(ptr) + } } /// Constructs an `Rc<[T]>` from an iterator known to be of a certain size. @@ -1058,25 +1066,27 @@ impl<T> Rc<[T]> { } } - let ptr = Self::allocate_for_slice(len); + unsafe { + let ptr = Self::allocate_for_slice(len); - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); - // Pointer to first element - let elems = &mut (*ptr).value as *mut [T] as *mut T; + // Pointer to first element + let elems = &mut (*ptr).value as *mut [T] as *mut T; - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } - // All clear. Forget the guard so it doesn't free the new RcBox. - forget(guard); + // All clear. Forget the guard so it doesn't free the new RcBox. + forget(guard); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } } @@ -1786,10 +1796,12 @@ impl<T> Weak<T> { Self::new() } else { // See Rc::from_raw for details - let offset = data_offset(ptr); - let fake_ptr = ptr as *mut RcBox<T>; - let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + unsafe { + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut RcBox<T>; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + } } } } @@ -2106,7 +2118,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { // Because it is ?Sized, it will always be the last field in memory. // Note: This is a detail of the current implementation of the compiler, // and is not a guaranteed language detail. Do not rely on it outside of std. - data_offset_align(align_of_val(&*ptr)) + unsafe { data_offset_align(align_of_val(&*ptr)) } } /// Computes the offset of the data field within `RcBox`. diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 53477288b59..d7dc2174d66 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -831,8 +831,7 @@ where { let len = v.len(); let v = v.as_mut_ptr(); - let v_mid = v.add(mid); - let v_end = v.add(len); + let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) }; // The merge process first copies the shorter run into `buf`. Then it traces the newly copied // run and the longer run forwards (or backwards), comparing their next unconsumed elements and @@ -855,8 +854,10 @@ where if mid <= len - mid { // The left run is shorter. - ptr::copy_nonoverlapping(v, buf, mid); - hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + unsafe { + ptr::copy_nonoverlapping(v, buf, mid); + hole = MergeHole { start: buf, end: buf.add(mid), dest: v }; + } // Initially, these pointers point to the beginnings of their arrays. let left = &mut hole.start; @@ -866,17 +867,21 @@ where while *left < hole.end && right < v_end { // Consume the lesser side. // If equal, prefer the left run to maintain stability. - let to_copy = if is_less(&*right, &**left) { - get_and_increment(&mut right) - } else { - get_and_increment(left) - }; - ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + unsafe { + let to_copy = if is_less(&*right, &**left) { + get_and_increment(&mut right) + } else { + get_and_increment(left) + }; + ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + } } } else { // The right run is shorter. - ptr::copy_nonoverlapping(v_mid, buf, len - mid); - hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + unsafe { + ptr::copy_nonoverlapping(v_mid, buf, len - mid); + hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid }; + } // Initially, these pointers point past the ends of their arrays. let left = &mut hole.dest; @@ -886,12 +891,14 @@ where while v < *left && buf < *right { // Consume the greater side. // If equal, prefer the right run to maintain stability. - let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) { - decrement_and_get(left) - } else { - decrement_and_get(right) - }; - ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + unsafe { + let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) { + decrement_and_get(left) + } else { + decrement_and_get(right) + }; + ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + } } } // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of @@ -899,12 +906,12 @@ where unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T { let old = *ptr; - *ptr = ptr.offset(1); + *ptr = unsafe { ptr.offset(1) }; old } unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T { - *ptr = ptr.offset(-1); + *ptr = unsafe { ptr.offset(-1) }; *ptr } diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 70860c09a2c..57927c68847 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -583,5 +583,5 @@ impl str { #[stable(feature = "str_box_extras", since = "1.20.0")] #[inline] pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> { - Box::from_raw(Box::into_raw(v) as *mut str) + unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 0378ff5362a..64d9692244d 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -724,7 +724,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String { - String { vec: Vec::from_raw_parts(buf, length, capacity) } + unsafe { String { vec: Vec::from_raw_parts(buf, length, capacity) } } } /// Converts a vector of bytes to a `String` without checking that the @@ -1329,9 +1329,11 @@ impl String { let amt = bytes.len(); self.vec.reserve(amt); - ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); - ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); - self.vec.set_len(len + amt); + unsafe { + ptr::copy(self.vec.as_ptr().add(idx), self.vec.as_mut_ptr().add(idx + amt), len - idx); + ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt); + self.vec.set_len(len + amt); + } } /// Inserts a string slice into this `String` at a byte position. @@ -2228,6 +2230,14 @@ impl<T: fmt::Display + ?Sized> ToString for T { } } +#[stable(feature = "char_to_string_specialization", since = "1.46.0")] +impl ToString for char { + #[inline] + fn to_string(&self) -> String { + String::from(self.encode_utf8(&mut [0; 4])) + } +} + #[stable(feature = "str_to_string_specialization", since = "1.9.0")] impl ToString for str { #[inline] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index cd4172d6a2d..826f0c8fa83 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -232,7 +232,7 @@ impl<T: ?Sized> Arc<T> { } unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self { - Self::from_inner(NonNull::new_unchecked(ptr)) + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } } } @@ -543,7 +543,7 @@ impl<T> Arc<[mem::MaybeUninit<T>]> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Arc<[T]> { - Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) + unsafe { Arc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _) } } } @@ -642,13 +642,15 @@ impl<T: ?Sized> Arc<T> { /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - let offset = data_offset(ptr); + unsafe { + let offset = data_offset(ptr); - // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner<T>; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + // Reverse the offset to find the original ArcInner. + let fake_ptr = ptr as *mut ArcInner<T>; + let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Self::from_ptr(arc_ptr) + Self::from_ptr(arc_ptr) + } } /// Consumes the `Arc`, returning the wrapped pointer as `NonNull<T>`. @@ -807,7 +809,7 @@ impl<T: ?Sized> Arc<T> { #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] pub unsafe fn incr_strong_count(ptr: *const T) { // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop - let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr)); + let arc = unsafe { mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr)) }; // Now increase refcount, but don't drop new refcount either let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); } @@ -847,7 +849,7 @@ impl<T: ?Sized> Arc<T> { #[inline] #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] pub unsafe fn decr_strong_count(ptr: *const T) { - mem::drop(Arc::from_raw(ptr)); + unsafe { mem::drop(Arc::from_raw(ptr)) }; } #[inline] @@ -865,7 +867,7 @@ impl<T: ?Sized> Arc<T> { unsafe fn drop_slow(&mut self) { // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(Self::get_mut_unchecked(self)); + unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) }; // Drop the weak ref collectively held by all strong references drop(Weak { ptr: self.ptr }); @@ -917,10 +919,12 @@ impl<T: ?Sized> Arc<T> { // Initialize the ArcInner let inner = mem_to_arcinner(mem.ptr.as_ptr()); - debug_assert_eq!(Layout::for_value(&*inner), layout); + debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + unsafe { + ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); + ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + } inner } @@ -928,9 +932,11 @@ impl<T: ?Sized> Arc<T> { /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value. unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> { // Allocate for the `ArcInner<T>` using the given value. - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T> - }) + unsafe { + Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { + set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T> + }) + } } fn from_box(v: Box<T>) -> Arc<T> { @@ -959,9 +965,11 @@ impl<T: ?Sized> Arc<T> { impl<T> Arc<[T]> { /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { - Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> - }) + unsafe { + Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> + }) + } } } @@ -970,7 +978,9 @@ impl<T> Arc<[T]> { /// For a slice/trait object, this sets the `data` field and leaves the rest /// unchanged. For a sized raw pointer, this simply sets the pointer. unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + unsafe { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + } ptr } @@ -979,11 +989,13 @@ impl<T> Arc<[T]> { /// /// Unsafe because the caller must either take ownership or bind `T: Copy`. unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { - let ptr = Self::allocate_for_slice(v.len()); + unsafe { + let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } /// Constructs an `Arc<[T]>` from an iterator known to be of a certain size. @@ -1011,25 +1023,27 @@ impl<T> Arc<[T]> { } } - let ptr = Self::allocate_for_slice(len); + unsafe { + let ptr = Self::allocate_for_slice(len); - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); - // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; + // Pointer to first element + let elems = &mut (*ptr).data as *mut [T] as *mut T; - let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; + let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; - for (i, item) in iter.enumerate() { - ptr::write(elems.add(i), item); - guard.n_elems += 1; - } + for (i, item) in iter.enumerate() { + ptr::write(elems.add(i), item); + guard.n_elems += 1; + } - // All clear. Forget the guard so it doesn't free the new ArcInner. - mem::forget(guard); + // All clear. Forget the guard so it doesn't free the new ArcInner. + mem::forget(guard); - Self::from_ptr(ptr) + Self::from_ptr(ptr) + } } } @@ -1274,7 +1288,7 @@ impl<T: ?Sized> Arc<T> { pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { // We are careful to *not* create a reference covering the "count" fields, as // this would alias with concurrent access to the reference counts (e.g. by `Weak`). - &mut (*this.ptr.as_ptr()).data + unsafe { &mut (*this.ptr.as_ptr()).data } } /// Determine whether this is the unique reference (including weak refs) to @@ -1551,10 +1565,12 @@ impl<T> Weak<T> { Self::new() } else { // See Arc::from_raw for details - let offset = data_offset(ptr); - let fake_ptr = ptr as *mut ArcInner<T>; - let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + unsafe { + let offset = data_offset(ptr); + let fake_ptr = ptr as *mut ArcInner<T>; + let ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + Weak { ptr: NonNull::new(ptr).expect("Invalid pointer passed to from_raw") } + } } } } @@ -2260,7 +2276,7 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize { // Because it is `?Sized`, it will always be the last field in memory. // Note: This is a detail of the current implementation of the compiler, // and is not a guaranteed language detail. Do not rely on it outside of std. - data_offset_align(align_of_val(&*ptr)) + unsafe { data_offset_align(align_of_val(&*ptr)) } } /// Computes the offset of the data field within `ArcInner`. diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index 745444a152e..0d1cc99df47 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -60,7 +60,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker { fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { // Increment the reference count of the arc to clone it. unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker { - Arc::incr_strong_count(waker as *const W); + unsafe { Arc::incr_strong_count(waker as *const W) }; RawWaker::new( waker as *const (), &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>), @@ -69,19 +69,20 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { // Wake by value, moving the Arc into the Wake::wake function unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) { - let waker: Arc<W> = Arc::from_raw(waker as *const W); + let waker: Arc<W> = unsafe { Arc::from_raw(waker as *const W) }; <W as Wake>::wake(waker); } // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) { - let waker: ManuallyDrop<Arc<W>> = ManuallyDrop::new(Arc::from_raw(waker as *const W)); + let waker: ManuallyDrop<Arc<W>> = + unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) }; <W as Wake>::wake_by_ref(&waker); } // Decrement the reference count of the Arc on drop unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) { - Arc::decr_strong_count(waker as *const W); + unsafe { Arc::decr_strong_count(waker as *const W) }; } RawWaker::new( diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 06462fd96d9..95c3b3b1861 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -465,7 +465,7 @@ impl<T> Vec<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec<T> { - Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } + unsafe { Vec { buf: RawVec::from_raw_parts(ptr, capacity), len: length } } } /// Returns the number of elements the vector can hold without @@ -1264,10 +1264,10 @@ impl<T> Vec<T> { /// Appends elements to `Self` from other buffer. #[inline] unsafe fn append_elements(&mut self, other: *const [T]) { - let count = (*other).len(); + let count = unsafe { (*other).len() }; self.reserve(count); let len = self.len(); - ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count); + unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; self.len += count; } @@ -1639,7 +1639,7 @@ impl<T: Default> Vec<T> { } } -// This code generalises `extend_with_{element,default}`. +// This code generalizes `extend_with_{element,default}`. trait ExtendWith<T> { fn next(&mut self) -> T; fn last(self) -> T; @@ -1837,7 +1837,7 @@ unsafe trait IsZero { } macro_rules! impl_is_zero { - ($t: ty, $is_zero: expr) => { + ($t:ty, $is_zero:expr) => { unsafe impl IsZero for $t { #[inline] fn is_zero(&self) -> bool { @@ -2362,9 +2362,9 @@ macro_rules! __impl_slice_eq1 { __impl_slice_eq1! { [] Vec<A>, Vec<B>, } __impl_slice_eq1! { [] Vec<A>, &[B], } __impl_slice_eq1! { [] Vec<A>, &mut [B], } +__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone } __impl_slice_eq1! { [] Cow<'_, [A]>, &[B], A: Clone } __impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B], A: Clone } -__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone } __impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], [B; N]: LengthAtMost32 } __impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], [B; N]: LengthAtMost32 } @@ -2965,15 +2965,16 @@ impl<T> Drain<'_, T> { /// Fill that range as much as possible with new elements from the `replace_with` iterator. /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) unsafe fn fill<I: Iterator<Item = T>>(&mut self, replace_with: &mut I) -> bool { - let vec = self.vec.as_mut(); + let vec = unsafe { self.vec.as_mut() }; let range_start = vec.len; let range_end = self.tail_start; - let range_slice = - slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start); + let range_slice = unsafe { + slice::from_raw_parts_mut(vec.as_mut_ptr().add(range_start), range_end - range_start) + }; for place in range_slice { if let Some(new_item) = replace_with.next() { - ptr::write(place, new_item); + unsafe { ptr::write(place, new_item) }; vec.len += 1; } else { return false; @@ -2984,14 +2985,16 @@ impl<T> Drain<'_, T> { /// Makes room for inserting more elements before the tail. unsafe fn move_tail(&mut self, additional: usize) { - let vec = self.vec.as_mut(); + let vec = unsafe { self.vec.as_mut() }; let len = self.tail_start + self.tail_len; vec.buf.reserve(len, additional); let new_tail_start = self.tail_start + additional; - let src = vec.as_ptr().add(self.tail_start); - let dst = vec.as_mut_ptr().add(new_tail_start); - ptr::copy(src, dst, self.tail_len); + unsafe { + let src = vec.as_ptr().add(self.tail_start); + let dst = vec.as_mut_ptr().add(new_tail_start); + ptr::copy(src, dst, self.tail_len); + } self.tail_start = new_tail_start; } } diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index ac07ffb14fe..42c555cafac 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -19,6 +19,7 @@ path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" path = "../libcore/benches/lib.rs" +test = true [dev-dependencies] rand = "0.7" diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 570fc4ab933..de4ef7949f3 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -1,3 +1,5 @@ +// wasm32 does not support benches (no time). +#![cfg(not(target_arch = "wasm32"))] #![feature(flt2dec)] #![feature(test)] diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs index eef9ee7cb00..8ff1ced53b0 100644 --- a/src/libcore/convert/mod.rs +++ b/src/libcore/convert/mod.rs @@ -374,6 +374,7 @@ pub trait Into<T>: Sized { /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from /// [book]: ../../book/ch09-00-error-handling.html +#[rustc_diagnostic_item = "from_trait"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( all(_Self = "&str", T = "std::string::String"), diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 85076a573b5..9061145a695 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1941,6 +1941,13 @@ extern "rust-intrinsic" { /// /// Perma-unstable: do not use. pub fn miri_start_panic(payload: *mut u8) -> !; + + /// Internal placeholder for injecting code coverage counters when the "instrument-coverage" + /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code + /// generation. + #[cfg(not(bootstrap))] + #[lang = "count_code_region"] + pub fn count_code_region(index: u32); } // Some functions are defined here because they accidentally got made @@ -2057,9 +2064,14 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) { fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); } - debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); - debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); - debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory"); + if cfg!(debug_assertions) + && !(is_aligned_and_not_null(src) + && is_aligned_and_not_null(dst) + && is_nonoverlapping(src, dst, count)) + { + // Not panicking to keep codegen impact smaller. + abort(); + } copy_nonoverlapping(src, dst, count) } @@ -2122,8 +2134,10 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) { fn copy<T>(src: *const T, dst: *mut T, count: usize); } - debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer"); - debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer"); + if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { + // Not panicking to keep codegen impact smaller. + abort(); + } copy(src, dst, count) } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index fbfcdc3c1a9..530cf881f29 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2265,7 +2265,7 @@ pub trait Iterator { } /// Applies function to the elements of iterator and returns - /// the first non-none result or the first error. + /// the first true result or the first error. /// /// # Examples /// @@ -2286,19 +2286,26 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] - fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E> + fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error> where Self: Sized, F: FnMut(&Self::Item) -> R, - R: Try<Ok = bool, Error = E>, - { - self.try_fold((), move |(), x| match f(&x).into_result() { - Ok(false) => LoopState::Continue(()), - Ok(true) => LoopState::Break(Ok(x)), - Err(x) => LoopState::Break(Err(x)), - }) - .break_value() - .transpose() + R: Try<Ok = bool>, + { + #[inline] + fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::Error>> + where + F: FnMut(&T) -> R, + R: Try<Ok = bool>, + { + move |(), x| match f(&x).into_result() { + Ok(false) => LoopState::Continue(()), + Ok(true) => LoopState::Break(Ok(x)), + Err(x) => LoopState::Break(Err(x)), + } + } + + self.try_fold((), check(f)).break_value().transpose() } /// Searches for an element in an iterator, returning its index. diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index d1f5cb44913..066bb8b3dc7 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -129,7 +129,7 @@ pub use crate::intrinsics::transmute; /// erring on the side of (double-)dropping. /// /// Also, `ManuallyDrop` prevents us from having to "touch" `v` after transferring the -/// ownership to `s` - the final step of interacting with `v` to dispoe of it without +/// ownership to `s` — the final step of interacting with `v` to dispose of it without /// running its destructor is entirely avoided. /// /// [drop]: fn.drop.html @@ -581,11 +581,12 @@ pub const fn needs_drop<T>() -> bool { /// This means that, for example, the padding byte in `(u8, u16)` is not /// necessarily zeroed. /// -/// There is no guarantee that an all-zero byte-pattern represents a valid value of -/// some type `T`. For example, the all-zero byte-pattern is not a valid value -/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types -/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv] -/// that there always is a valid value in a variable it considers initialized. +/// There is no guarantee that an all-zero byte-pattern represents a valid value +/// of some type `T`. For example, the all-zero byte-pattern is not a valid value +/// for reference types (`&T`, `&mut T`) and functions pointers. Using `zeroed` +/// on such types causes immediate [undefined behavior][ub] because [the Rust +/// compiler assumes][inv] that there always is a valid value in a variable it +/// considers initialized. /// /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. @@ -612,6 +613,7 @@ pub const fn needs_drop<T>() -> bool { /// use std::mem; /// /// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! +/// let _y: fn() = unsafe { mem::zeroed() }; // And again! /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 1ffd493d813..c7009b76e81 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -39,8 +39,7 @@ pub struct PanicInfo<'a> { impl<'a> PanicInfo<'a> { #[unstable( feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` \ - and related macros", + reason = "internal details of the implementation of the `panic!` and related macros", issue = "none" )] #[doc(hidden)] @@ -55,8 +54,7 @@ impl<'a> PanicInfo<'a> { #[unstable( feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` \ - and related macros", + reason = "internal details of the implementation of the `panic!` and related macros", issue = "none" )] #[doc(hidden)] @@ -244,8 +242,7 @@ impl<'a> Location<'a> { impl<'a> Location<'a> { #![unstable( feature = "panic_internals", - reason = "internal details of the implementation of the `panic!` \ - and related macros", + reason = "internal details of the implementation of the `panic!` and related macros", issue = "none" )] #[doc(hidden)] diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 3ed5e65e11c..766c69a5f94 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -22,8 +22,7 @@ #![allow(dead_code, missing_docs)] #![unstable( feature = "core_panic", - reason = "internal details of the implementation of the `panic!` \ - and related macros", + reason = "internal details of the implementation of the `panic!` and related macros", issue = "none" )] diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index 1be05d5efff..ca2b0c85ec1 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -70,7 +70,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash; -use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping}; +use crate::intrinsics::{self, abort, is_aligned_and_not_null, is_nonoverlapping}; use crate::mem::{self, MaybeUninit}; #[stable(feature = "rust1", since = "1.0.0")] @@ -420,9 +420,14 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) { #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { - debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer"); - debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer"); - debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory"); + if cfg!(debug_assertions) + && !(is_aligned_and_not_null(x) + && is_aligned_and_not_null(y) + && is_nonoverlapping(x, y, count)) + { + // Not panicking to keep codegen impact smaller. + abort(); + } let x = x as *mut u8; let y = y as *mut u8; @@ -838,7 +843,10 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write<T>(dst: *mut T, src: T) { - debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); + if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) { + // Not panicking to keep codegen impact smaller. + abort(); + } intrinsics::move_val_init(&mut *dst, src) } @@ -1003,7 +1011,10 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn read_volatile<T>(src: *const T) -> T { - debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer"); + if cfg!(debug_assertions) && !is_aligned_and_not_null(src) { + // Not panicking to keep codegen impact smaller. + abort(); + } intrinsics::volatile_load(src) } @@ -1072,7 +1083,10 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { #[inline] #[stable(feature = "volatile", since = "1.9.0")] pub unsafe fn write_volatile<T>(dst: *mut T, src: T) { - debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); + if cfg!(debug_assertions) && !is_aligned_and_not_null(dst) { + // Not panicking to keep codegen impact smaller. + abort(); + } intrinsics::volatile_store(dst, src); } @@ -1399,3 +1413,70 @@ fnptr_impls_args! { A, B, C, D, E, F, G, H, I } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K } fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L } + +/// Create a `const` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&expr as *const _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let packed = Packed { f1: 1, f2: 2 }; +/// // `&packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_const!(packed.f2); +/// assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "73394")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_const($e:expr) { + &raw const $e +} + +/// Create a `mut` raw pointer to a place, without creating an intermediate reference. +/// +/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned +/// and points to initialized data. For cases where those requirements do not hold, +/// raw pointers should be used instead. However, `&mut expr as *mut _` creates a reference +/// before casting it to a raw pointer, and that reference is subject to the same rules +/// as all other references. This macro can create a raw pointer *without* creating +/// a reference first. +/// +/// # Example +/// +/// ``` +/// #![feature(raw_ref_macros)] +/// use std::ptr; +/// +/// #[repr(packed)] +/// struct Packed { +/// f1: u8, +/// f2: u16, +/// } +/// +/// let mut packed = Packed { f1: 1, f2: 2 }; +/// // `&mut packed.f2` would create an unaligned reference, and thus be Undefined Behavior! +/// let raw_f2 = ptr::raw_mut!(packed.f2); +/// unsafe { raw_f2.write_unaligned(42); } +/// assert_eq!({packed.f2}, 42); // `{...}` forces copying the field instead of creating a reference. +/// ``` +#[unstable(feature = "raw_ref_macros", issue = "73394")] +#[rustc_macro_transparency = "semitransparent"] +#[allow_internal_unstable(raw_ref_op)] +pub macro raw_mut($e:expr) { + &raw mut $e +} diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c7b5777a16e..2080ae19366 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1145,45 +1145,69 @@ impl<T, E: Into<!>> Result<T, E> { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", issue = "50264")] impl<T: Deref, E> Result<T, E> { - /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T::Target, &E>`. + /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`. /// - /// Leaves the original `Result` in-place, creating a new one containing a reference to the - /// `Ok` type's `Deref::Target` type. + /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref) + /// and returns the new [`Result`]. + /// + /// # Examples + /// + /// ``` + /// let x: Result<String, u32> = Ok("hello".to_string()); + /// let y: Result<&str, &u32> = Ok("hello"); + /// assert_eq!(x.as_deref(), y); + /// + /// let x: Result<String, u32> = Err(42); + /// let y: Result<&str, &u32> = Err(&42); + /// assert_eq!(x.as_deref(), y); + /// ``` pub fn as_deref(&self) -> Result<&T::Target, &E> { self.as_ref().map(|t| t.deref()) } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", issue = "50264")] impl<T, E: Deref> Result<T, E> { - /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &E::Target>`. + /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&T, &<E as Deref>::Target>`. /// - /// Leaves the original `Result` in-place, creating a new one containing a reference to the - /// `Err` type's `Deref::Target` type. + /// Coerces the [`Err`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref) + /// and returns the new [`Result`]. pub fn as_deref_err(&self) -> Result<&T, &E::Target> { self.as_ref().map_err(|e| e.deref()) } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", issue = "50264")] impl<T: DerefMut, E> Result<T, E> { - /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T::Target, &mut E>`. + /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`. /// - /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to - /// the `Ok` type's `Deref::Target` type. + /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut) + /// and returns the new [`Result`]. + /// + /// # Examples + /// + /// ``` + /// let mut x: Result<String, u32> = Ok("hello".to_string()); + /// let y: Result<&mut str, &mut u32> = Ok("HELLO"); + /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); + /// + /// let mut x: Result<String, u32> = Err(42); + /// let y: Result<&mut str, &mut u32> = Err(&42); + /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y); + /// ``` pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> { self.as_mut().map(|t| t.deref_mut()) } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", issue = "50264")] impl<T, E: DerefMut> Result<T, E> { - /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut E::Target>`. + /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut T, &mut <E as DerefMut>::Target>`. /// - /// Leaves the original `Result` in-place, creating a new one containing a mutable reference to - /// the `Err` type's `Deref::Target` type. + /// Coerces the [`Err`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut) + /// and returns the new [`Result`]. pub fn as_deref_mut_err(&mut self) -> Result<&mut T, &mut E::Target> { self.as_mut().map_err(|e| e.deref_mut()) } diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index be3e7aaa2e8..8b2ac294764 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -1,6 +1,6 @@ //! Slice sorting //! -//! This module contains an sort algorithm based on Orson Peters' pattern-defeating quicksort, +//! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort, //! published at: https://github.com/orlp/pdqsort //! //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our @@ -20,6 +20,9 @@ struct CopyOnDrop<T> { impl<T> Drop for CopyOnDrop<T> { fn drop(&mut self) { + // SAFETY: This is a helper class. + // Please refer to its usage for correctness. + // Namely, one must be sure that `src` and `dst` does not overlap as required by `ptr::copy_nonoverlapping`. unsafe { ptr::copy_nonoverlapping(self.src, self.dest, 1); } @@ -32,6 +35,21 @@ where F: FnMut(&T, &T) -> bool, { let len = v.len(); + // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`) + // and copying memory (`ptr::copy_nonoverlapping`). + // + // a. Indexing: + // 1. We checked the size of the array to >=2. + // 2. All the indexing that we will do is always between {0 <= index < len} at most. + // + // b. Memory copying + // 1. We are obtaining pointers to references which are guaranteed to be valid. + // 2. They cannot overlap because we obtain pointers to difference indices of the slice. + // Namely, `i` and `i-1`. + // 3. If the slice is properly aligned, the elements are properly aligned. + // It is the caller's responsibility to make sure the slice is properly aligned. + // + // See comments below for further detail. unsafe { // If the first two elements are out-of-order... if len >= 2 && is_less(v.get_unchecked(1), v.get_unchecked(0)) { @@ -62,6 +80,21 @@ where F: FnMut(&T, &T) -> bool, { let len = v.len(); + // SAFETY: The unsafe operations below involves indexing without a bound check (`get_unchecked` and `get_unchecked_mut`) + // and copying memory (`ptr::copy_nonoverlapping`). + // + // a. Indexing: + // 1. We checked the size of the array to >= 2. + // 2. All the indexing that we will do is always between `0 <= index < len-1` at most. + // + // b. Memory copying + // 1. We are obtaining pointers to references which are guaranteed to be valid. + // 2. They cannot overlap because we obtain pointers to difference indices of the slice. + // Namely, `i` and `i+1`. + // 3. If the slice is properly aligned, the elements are properly aligned. + // It is the caller's responsibility to make sure the slice is properly aligned. + // + // See comments below for further detail. unsafe { // If the last two elements are out-of-order... if len >= 2 && is_less(v.get_unchecked(len - 1), v.get_unchecked(len - 2)) { @@ -103,6 +136,8 @@ where let mut i = 1; for _ in 0..MAX_STEPS { + // SAFETY: We already explicitly did the bound checking with `i < len`. + // All our subsequent indexing is only in the range `0 <= index < len` unsafe { // Find the next pair of adjacent out-of-order elements. while i < len && !is_less(v.get_unchecked(i), v.get_unchecked(i - 1)) { @@ -220,6 +255,7 @@ where let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). + // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe` let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); @@ -268,6 +304,16 @@ where let mut elem = l; for i in 0..block_l { + // SAFETY: The unsafety operations below involve the usage of the `offset`. + // According to the conditions required by the function, we satisfy them because: + // 1. `offsets_l` is stack-allocated, and thus considered separate allocated object. + // 2. The function `is_less` returns a `bool`. + // Casting a `bool` will never overflow `isize`. + // 3. We have guaranteed that `block_l` will be `<= BLOCK`. + // Plus, `end_l` was initially set to the begin pointer of `offsets_` which was declared on the stack. + // Thus, we know that even in the worst case (all invocations of `is_less` returns false) we will only be at most 1 byte pass the end. + // Another unsafety operation here is dereferencing `elem`. + // However, `elem` was initially the begin pointer to the slice which is always valid. unsafe { // Branchless comparison. *end_l = i as u8; @@ -284,6 +330,17 @@ where let mut elem = r; for i in 0..block_r { + // SAFETY: The unsafety operations below involve the usage of the `offset`. + // According to the conditions required by the function, we satisfy them because: + // 1. `offsets_r` is stack-allocated, and thus considered separate allocated object. + // 2. The function `is_less` returns a `bool`. + // Casting a `bool` will never overflow `isize`. + // 3. We have guaranteed that `block_r` will be `<= BLOCK`. + // Plus, `end_r` was initially set to the begin pointer of `offsets_` which was declared on the stack. + // Thus, we know that even in the worst case (all invocations of `is_less` returns true) we will only be at most 1 byte pass the end. + // Another unsafety operation here is dereferencing `elem`. + // However, `elem` was initially `1 * sizeof(T)` past the end and we decrement it by `1 * sizeof(T)` before accessing it. + // Plus, `block_r` was asserted to be less than `BLOCK` and `elem` will therefore at most be pointing to the beginning of the slice. unsafe { // Branchless comparison. elem = elem.offset(-1); @@ -404,8 +461,13 @@ where // Find the first pair of out-of-order elements. let mut l = 0; let mut r = v.len(); + + // SAFETY: The unsafety below involves indexing an array. + // For the first one: We already do the bounds checking here with `l < r`. + // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. + // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. unsafe { - // Find the first element greater then or equal to the pivot. + // Find the first element greater than or equal to the pivot. while l < r && is_less(v.get_unchecked(l), pivot) { l += 1; } @@ -444,6 +506,7 @@ where // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. + // SAFETY: The pointer here is valid because it is obtained from a reference to a slice. let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot }; let pivot = &*tmp; @@ -452,8 +515,12 @@ where let mut l = 0; let mut r = v.len(); loop { + // SAFETY: The unsafety below involves indexing an array. + // For the first one: We already do the bounds checking here with `l < r`. + // For the second one: We initially have `l == 0` and `r == v.len()` and we checked that `l < r` at every indexing operation. + // From here we know that `r` must be at least `r == l` which was shown to be valid from the first one. unsafe { - // Find the first element greater that the pivot. + // Find the first element greater than the pivot. while l < r && !is_less(pivot, v.get_unchecked(l)) { l += 1; } diff --git a/src/libcore/tests/array.rs b/src/libcore/tests/array.rs index c2a816f0a7d..4bc44e98fc8 100644 --- a/src/libcore/tests/array.rs +++ b/src/libcore/tests/array.rs @@ -241,3 +241,52 @@ fn iterator_drops() { } assert_eq!(i.get(), 5); } + +// This test does not work on targets without panic=unwind support. +// To work around this problem, test is marked is should_panic, so it will +// be automagically skipped on unsuitable targets, such as +// wasm32-unknown-unkown. +// +// It means that we use panic for indicating success. +#[test] +#[should_panic(expected = "test succeeded")] +fn array_default_impl_avoids_leaks_on_panic() { + use core::sync::atomic::{AtomicUsize, Ordering::Relaxed}; + static COUNTER: AtomicUsize = AtomicUsize::new(0); + #[derive(Debug)] + struct Bomb(usize); + + impl Default for Bomb { + fn default() -> Bomb { + if COUNTER.load(Relaxed) == 3 { + panic!("bomb limit exceeded"); + } + + COUNTER.fetch_add(1, Relaxed); + Bomb(COUNTER.load(Relaxed)) + } + } + + impl Drop for Bomb { + fn drop(&mut self) { + COUNTER.fetch_sub(1, Relaxed); + } + } + + let res = std::panic::catch_unwind(|| <[Bomb; 5]>::default()); + let panic_msg = match res { + Ok(_) => unreachable!(), + Err(p) => p.downcast::<&'static str>().unwrap(), + }; + assert_eq!(*panic_msg, "bomb limit exceeded"); + // check that all bombs are successfully dropped + assert_eq!(COUNTER.load(Relaxed), 0); + panic!("test succeeded") +} + +#[test] +fn empty_array_is_always_default() { + struct DoesNotImplDefault; + + let _arr = <[DoesNotImplDefault; 0]>::default(); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 37ebf411280..4e55452a4c3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -19,7 +19,7 @@ #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] -#![feature(specialization)] +#![feature(min_specialization)] #![feature(step_trait)] #![feature(step_trait_ext)] #![feature(str_internals)] diff --git a/src/librustc_arena/lib.rs b/src/librustc_arena/lib.rs index 4a2a0de0e21..6cf2db3e2da 100644 --- a/src/librustc_arena/lib.rs +++ b/src/librustc_arena/lib.rs @@ -22,6 +22,7 @@ extern crate alloc; use rustc_data_structures::cold_path; use smallvec::SmallVec; +use std::alloc::Layout; use std::cell::{Cell, RefCell}; use std::cmp; use std::intrinsics; @@ -333,13 +334,6 @@ impl Default for DroplessArena { } impl DroplessArena { - #[inline] - fn align(&self, align: usize) { - let final_address = ((self.ptr.get() as usize) + align - 1) & !(align - 1); - self.ptr.set(final_address as *mut u8); - assert!(self.ptr <= self.end); - } - #[inline(never)] #[cold] fn grow(&self, additional: usize) { @@ -370,22 +364,44 @@ impl DroplessArena { } } + /// Allocates a byte slice with specified layout from the current memory + /// chunk. Returns `None` if there is no free space left to satisfy the + /// request. #[inline] - pub fn alloc_raw(&self, bytes: usize, align: usize) -> &mut [u8] { - unsafe { - assert!(bytes != 0); - - self.align(align); + fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> { + let ptr = self.ptr.get() as usize; + let end = self.end.get() as usize; + let align = layout.align(); + let bytes = layout.size(); + // The allocation request fits into the current chunk iff: + // + // let aligned = align_to(ptr, align); + // ptr <= aligned && aligned + bytes <= end + // + // Except that we work with fixed width integers and need to be careful + // about potential overflow in the calcuation. If the overflow does + // happen, then we definitely don't have enough free and need to grow + // the arena. + let aligned = ptr.checked_add(align - 1)? & !(align - 1); + let new_ptr = aligned.checked_add(bytes)?; + if new_ptr <= end { + self.ptr.set(new_ptr as *mut u8); + Some(aligned as *mut u8) + } else { + None + } + } - let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize); - if (future_end as *mut u8) > self.end.get() { - self.grow(bytes); + #[inline] + pub fn alloc_raw(&self, layout: Layout) -> *mut u8 { + assert!(layout.size() != 0); + loop { + if let Some(a) = self.alloc_raw_without_grow(layout) { + break a; } - - let ptr = self.ptr.get(); - // Set the pointer past ourselves - self.ptr.set(intrinsics::arith_offset(self.ptr.get(), bytes as isize) as *mut u8); - slice::from_raw_parts_mut(ptr, bytes) + // No free space left. Allocate a new chunk to satisfy the request. + // On failure the grow will panic or abort. + self.grow(layout.size()); } } @@ -393,7 +409,7 @@ impl DroplessArena { pub fn alloc<T>(&self, object: T) -> &mut T { assert!(!mem::needs_drop::<T>()); - let mem = self.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut _ as *mut T; + let mem = self.alloc_raw(Layout::for_value::<T>(&object)) as *mut T; unsafe { // Write into uninitialized memory. @@ -418,13 +434,11 @@ impl DroplessArena { assert!(mem::size_of::<T>() != 0); assert!(!slice.is_empty()); - let mem = self.alloc_raw(slice.len() * mem::size_of::<T>(), mem::align_of::<T>()) as *mut _ - as *mut T; + let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; unsafe { - let arena_slice = slice::from_raw_parts_mut(mem, slice.len()); - arena_slice.copy_from_slice(slice); - arena_slice + mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len()); + slice::from_raw_parts_mut(mem, slice.len()) } } @@ -466,8 +480,8 @@ impl DroplessArena { if len == 0 { return &mut []; } - let size = len.checked_mul(mem::size_of::<T>()).unwrap(); - let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut _ as *mut T; + + let mem = self.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T; unsafe { self.write_from_iter(iter, len, mem) } } (_, _) => { @@ -480,9 +494,8 @@ impl DroplessArena { // the content of the SmallVec unsafe { let len = vec.len(); - let start_ptr = self - .alloc_raw(len * mem::size_of::<T>(), mem::align_of::<T>()) - as *mut _ as *mut T; + let start_ptr = + self.alloc_raw(Layout::for_value::<[T]>(vec.as_slice())) as *mut T; vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); vec.set_len(0); slice::from_raw_parts_mut(start_ptr, len) @@ -526,8 +539,7 @@ pub struct DropArena { impl DropArena { #[inline] pub unsafe fn alloc<T>(&self, object: T) -> &mut T { - let mem = - self.arena.alloc_raw(mem::size_of::<T>(), mem::align_of::<T>()) as *mut _ as *mut T; + let mem = self.arena.alloc_raw(Layout::new::<T>()) as *mut T; // Write into uninitialized memory. ptr::write(mem, object); let result = &mut *mem; @@ -547,10 +559,7 @@ impl DropArena { } let len = vec.len(); - let start_ptr = self - .arena - .alloc_raw(len.checked_mul(mem::size_of::<T>()).unwrap(), mem::align_of::<T>()) - as *mut _ as *mut T; + let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T; let mut destructors = self.destructors.borrow_mut(); // Reserve space for the destructors so we can't panic while adding them diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 62406552e31..e98d709539d 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -5,7 +5,7 @@ //! additional metadata), and [`ItemKind`] (which represents a concrete type and contains //! information specific to the type of the item). //! -//! Other module items that worth mentioning: +//! Other module items worth mentioning: //! - [`Ty`] and [`TyKind`]: A parsed Rust type. //! - [`Expr`] and [`ExprKind`]: A parsed Rust expression. //! - [`Pat`] and [`PatKind`]: A parsed Rust pattern. Patterns are often dual to expressions. @@ -1905,7 +1905,7 @@ impl fmt::Display for InlineAsmTemplatePiece { match c { '{' => f.write_str("{{")?, '}' => f.write_str("}}")?, - _ => write!(f, "{}", c.escape_debug())?, + _ => c.fmt(f)?, } } Ok(()) diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 480ee97f205..29885679604 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -11,7 +11,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{InnerSpan, Span}; struct AsmArgs { - template: P<ast::Expr>, + templates: Vec<P<ast::Expr>>, operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap<Symbol, usize>, reg_args: FxHashSet<usize>, @@ -52,9 +52,9 @@ fn parse_args<'a>( return Err(err); } - let template = p.parse_expr()?; + let first_template = p.parse_expr()?; let mut args = AsmArgs { - template, + templates: vec![first_template], operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), @@ -62,11 +62,11 @@ fn parse_args<'a>( options_span: None, }; - let mut first = true; + let mut allow_templates = true; while p.token != token::Eof { if !p.eat(&token::Comma) { - if first { - // After `asm!(""` we always expect *only* a comma... + if allow_templates { + // After a template string, we always expect *only* a comma... let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); err.span_label(p.token.span, "expected `,`"); p.maybe_annotate_with_ascription(&mut err, false); @@ -76,7 +76,6 @@ fn parse_args<'a>( return Err(p.expect(&token::Comma).err().unwrap()); } } - first = false; if p.token == token::Eof { break; } // accept trailing commas @@ -84,6 +83,7 @@ fn parse_args<'a>( // Parse options if p.eat(&token::Ident(sym::options, false)) { parse_options(&mut p, &mut args)?; + allow_templates = false; continue; } @@ -94,6 +94,7 @@ fn parse_args<'a>( let (ident, _) = p.token.ident().unwrap(); p.bump(); p.expect(&token::Eq)?; + allow_templates = false; Some(ident.name) } else { None @@ -135,8 +136,7 @@ fn parse_args<'a>( } else if p.eat(&token::Ident(kw::Const, false)) { let expr = p.parse_expr()?; ast::InlineAsmOperand::Const { expr } - } else { - p.expect(&token::Ident(sym::sym, false))?; + } else if p.eat(&token::Ident(sym::sym, false)) { let expr = p.parse_expr()?; match expr.kind { ast::ExprKind::Path(..) => {} @@ -147,8 +147,27 @@ fn parse_args<'a>( } } ast::InlineAsmOperand::Sym { expr } + } else if allow_templates { + let template = p.parse_expr()?; + // If it can't possibly expand to a string, provide diagnostics here to include other + // things it could have been. + match template.kind { + ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} + ast::ExprKind::MacCall(..) => {} + _ => { + let errstr = "expected operand, options, or additional template string"; + let mut err = ecx.struct_span_err(template.span, errstr); + err.span_label(template.span, errstr); + return Err(err); + } + } + args.templates.push(template); + continue; + } else { + return Err(p.expect_one_of(&[], &[]).unwrap_err()); }; + allow_templates = false; let span = span_start.to(p.prev_token.span); let slot = args.operands.len(); args.operands.push((op, span)); @@ -330,155 +349,180 @@ fn parse_reg<'a>( } fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast::Expr> { - let msg = "asm template must be a string literal"; - let template_sp = args.template.span; - let (template_str, template_style, template_span) = - match expr_to_spanned_string(ecx, args.template, msg) { - Ok(template) => template, - Err(err) => { - if let Some(mut err) = err { - err.emit(); - } - return DummyResult::raw_expr(sp, true); - } - }; - - let str_style = match template_style { - ast::StrStyle::Cooked => None, - ast::StrStyle::Raw(raw) => Some(raw as usize), - }; - - let template_str = &template_str.as_str(); - let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); - let mut parser = parse::Parser::new( - template_str, - str_style, - template_snippet, - false, - parse::ParseMode::InlineAsm, - ); - - let mut unverified_pieces = Vec::new(); - while let Some(piece) = parser.next() { - if !parser.errors.is_empty() { - break; - } else { - unverified_pieces.push(piece); - } - } - - if !parser.errors.is_empty() { - let err = parser.errors.remove(0); - let err_sp = template_span.from_inner(err.span); - let mut e = ecx - .struct_span_err(err_sp, &format!("invalid asm template string: {}", err.description)); - e.span_label(err_sp, err.label + " in asm template string"); - if let Some(note) = err.note { - e.note(¬e); - } - if let Some((label, span)) = err.secondary_label { - let err_sp = template_span.from_inner(span); - e.span_label(err_sp, label); - } - e.emit(); - return DummyResult::raw_expr(sp, true); - } - + let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. let mut used = vec![false; args.operands.len()]; for pos in &args.reg_args { used[*pos] = true; } - let named_pos: FxHashMap<usize, Symbol> = args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect(); - let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span)); - let mut template = vec![]; - for piece in unverified_pieces { - match piece { - parse::Piece::String(s) => { - template.push(ast::InlineAsmTemplatePiece::String(s.to_string())) + let mut line_spans = Vec::with_capacity(args.templates.len()); + let mut curarg = 0; + + for template_expr in args.templates.into_iter() { + if !template.is_empty() { + template.push(ast::InlineAsmTemplatePiece::String("\n".to_string())); + } + + let msg = "asm template must be a string literal"; + let template_sp = template_expr.span; + let (template_str, template_style, template_span) = + match expr_to_spanned_string(ecx, template_expr, msg) { + Ok(template_part) => template_part, + Err(err) => { + if let Some(mut err) = err { + err.emit(); + } + return DummyResult::raw_expr(sp, true); + } + }; + + let str_style = match template_style { + ast::StrStyle::Cooked => None, + ast::StrStyle::Raw(raw) => Some(raw as usize), + }; + + let template_str = &template_str.as_str(); + let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok(); + let mut parser = parse::Parser::new( + template_str, + str_style, + template_snippet, + false, + parse::ParseMode::InlineAsm, + ); + parser.curarg = curarg; + + let mut unverified_pieces = Vec::new(); + while let Some(piece) = parser.next() { + if !parser.errors.is_empty() { + break; + } else { + unverified_pieces.push(piece); } - parse::Piece::NextArgument(arg) => { - let span = arg_spans.next().unwrap_or(template_sp); - - let operand_idx = match arg.position { - parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { - if idx >= args.operands.len() - || named_pos.contains_key(&idx) - || args.reg_args.contains(&idx) - { - let msg = format!("invalid reference to argument at index {}", idx); - let mut err = ecx.struct_span_err(span, &msg); - err.span_label(span, "from here"); - - let positional_args = - args.operands.len() - args.named_args.len() - args.reg_args.len(); - let positional = if positional_args != args.operands.len() { - "positional " + } + + if !parser.errors.is_empty() { + let err = parser.errors.remove(0); + let err_sp = template_span.from_inner(err.span); + let msg = &format!("invalid asm template string: {}", err.description); + let mut e = ecx.struct_span_err(err_sp, msg); + e.span_label(err_sp, err.label + " in asm template string"); + if let Some(note) = err.note { + e.note(¬e); + } + if let Some((label, span)) = err.secondary_label { + let err_sp = template_span.from_inner(span); + e.span_label(err_sp, label); + } + e.emit(); + return DummyResult::raw_expr(sp, true); + } + + curarg = parser.curarg; + + let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span)); + for piece in unverified_pieces { + match piece { + parse::Piece::String(s) => { + template.push(ast::InlineAsmTemplatePiece::String(s.to_string())) + } + parse::Piece::NextArgument(arg) => { + let span = arg_spans.next().unwrap_or(template_sp); + + let operand_idx = match arg.position { + parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => { + if idx >= args.operands.len() + || named_pos.contains_key(&idx) + || args.reg_args.contains(&idx) + { + let msg = format!("invalid reference to argument at index {}", idx); + let mut err = ecx.struct_span_err(span, &msg); + err.span_label(span, "from here"); + + let positional_args = args.operands.len() + - args.named_args.len() + - args.reg_args.len(); + let positional = if positional_args != args.operands.len() { + "positional " + } else { + "" + }; + let msg = match positional_args { + 0 => format!("no {}arguments were given", positional), + 1 => format!("there is 1 {}argument", positional), + x => format!("there are {} {}arguments", x, positional), + }; + err.note(&msg); + + if named_pos.contains_key(&idx) { + err.span_label(args.operands[idx].1, "named argument"); + err.span_note( + args.operands[idx].1, + "named arguments cannot be referenced by position", + ); + } else if args.reg_args.contains(&idx) { + err.span_label( + args.operands[idx].1, + "explicit register argument", + ); + err.span_note( + args.operands[idx].1, + "explicit register arguments cannot be used in the asm template", + ); + } + err.emit(); + None } else { - "" - }; - let msg = match positional_args { - 0 => format!("no {}arguments were given", positional), - 1 => format!("there is 1 {}argument", positional), - x => format!("there are {} {}arguments", x, positional), - }; - err.note(&msg); - - if named_pos.contains_key(&idx) { - err.span_label(args.operands[idx].1, "named argument"); - err.span_note( - args.operands[idx].1, - "named arguments cannot be referenced by position", - ); - } else if args.reg_args.contains(&idx) { - err.span_label(args.operands[idx].1, "explicit register argument"); - err.span_note( - args.operands[idx].1, - "explicit register arguments cannot be used in the asm template", - ); + Some(idx) } - err.emit(); - None - } else { - Some(idx) - } - } - parse::ArgumentNamed(name) => match args.named_args.get(&name) { - Some(&idx) => Some(idx), - None => { - let msg = format!("there is no argument named `{}`", name); - ecx.struct_span_err(span, &msg[..]).emit(); - None } - }, - }; - - let mut chars = arg.format.ty.chars(); - let mut modifier = chars.next(); - if chars.next().is_some() { - let span = arg - .format - .ty_span - .map(|sp| template_sp.from_inner(sp)) - .unwrap_or(template_sp); - ecx.struct_span_err(span, "asm template modifier must be a single character") + parse::ArgumentNamed(name) => match args.named_args.get(&name) { + Some(&idx) => Some(idx), + None => { + let msg = format!("there is no argument named `{}`", name); + ecx.struct_span_err(span, &msg[..]).emit(); + None + } + }, + }; + + let mut chars = arg.format.ty.chars(); + let mut modifier = chars.next(); + if chars.next().is_some() { + let span = arg + .format + .ty_span + .map(|sp| template_sp.from_inner(sp)) + .unwrap_or(template_sp); + ecx.struct_span_err( + span, + "asm template modifier must be a single character", + ) .emit(); - modifier = None; - } + modifier = None; + } - if let Some(operand_idx) = operand_idx { - used[operand_idx] = true; - template.push(ast::InlineAsmTemplatePiece::Placeholder { - operand_idx, - modifier, - span, - }); + if let Some(operand_idx) = operand_idx { + used[operand_idx] = true; + template.push(ast::InlineAsmTemplatePiece::Placeholder { + operand_idx, + modifier, + span, + }); + } } } } + + if parser.line_spans.is_empty() { + let template_num_lines = 1 + template_str.matches('\n').count(); + line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines)); + } else { + line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span))); + }; } let mut unused_operands = vec![]; @@ -525,12 +569,6 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P<ast } } - let line_spans = if parser.line_spans.is_empty() { - vec![template_sp] - } else { - parser.line_spans.iter().map(|span| template_span.from_inner(*span)).collect() - }; - let inline_asm = ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans }; P(ast::Expr { diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 9d4a30f23a2..2f9e49591c3 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -255,6 +255,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} + InlineAsmArch::Hexagon => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -427,6 +428,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String { | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => "x", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -472,6 +474,7 @@ fn modifier_to_llvm( modifier } } + InlineAsmRegClass::Hexagon(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -523,6 +526,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { cx.type_vector(cx.type_i64(), 2) } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index a4e17a5f675..6234ade8a16 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{OptLevel, Sanitizer}; +use rustc_session::config::{OptLevel, SanitizerSet}; use rustc_session::Session; use crate::attributes; @@ -45,26 +45,16 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { /// Apply LLVM sanitize attributes. #[inline] -pub fn sanitize(cx: &CodegenCx<'ll, '_>, codegen_fn_flags: CodegenFnAttrFlags, llfn: &'ll Value) { - if let Some(ref sanitizer) = cx.tcx.sess.opts.debugging_opts.sanitizer { - match *sanitizer { - Sanitizer::Address => { - if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) { - llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); - } - } - Sanitizer::Memory => { - if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) { - llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); - } - } - Sanitizer::Thread => { - if !codegen_fn_flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) { - llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); - } - } - Sanitizer::Leak => {} - } +pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll Value) { + let enabled = cx.tcx.sess.opts.debugging_opts.sanitizer - no_sanitize; + if enabled.contains(SanitizerSet::ADDRESS) { + llvm::Attribute::SanitizeAddress.apply_llfn(Function, llfn); + } + if enabled.contains(SanitizerSet::MEMORY) { + llvm::Attribute::SanitizeMemory.apply_llfn(Function, llfn); + } + if enabled.contains(SanitizerSet::THREAD) { + llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn); } } @@ -123,9 +113,14 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Currently stack probes seem somewhat incompatible with the address // sanitizer and thread sanitizer. With asan we're already protected from // stack overflow anyway so we don't really need stack probes regardless. - match cx.sess().opts.debugging_opts.sanitizer { - Some(Sanitizer::Address | Sanitizer::Thread) => return, - _ => {} + if cx + .sess() + .opts + .debugging_opts + .sanitizer + .intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) + { + return; } // probestack doesn't play nice either with `-C profile-generate`. @@ -296,7 +291,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } - sanitize(cx, codegen_fn_attrs.flags, llfn); + sanitize(cx, codegen_fn_attrs.no_sanitize, llfn); // Always annotate functions with the target-cpu they are compiled for. // Without this, ThinLTO won't inline Rust functions into Clang generated diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 26f5334668b..868ce876a81 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -21,7 +21,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath}; +use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath}; use rustc_session::Session; use rustc_span::InnerSpan; use rustc_target::spec::{CodeModel, RelocModel}; @@ -394,12 +394,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO; // Sanitizer instrumentation is only inserted during the pre-link optimization stage. let sanitizer_options = if !is_lto { - config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions { - sanitize_memory: *s == Sanitizer::Memory, - sanitize_thread: *s == Sanitizer::Thread, - sanitize_address: *s == Sanitizer::Address, - sanitize_recover: config.sanitizer_recover.contains(s), + Some(llvm::SanitizerOptions { + sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS), + sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS), + sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY), + sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY), sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int, + sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD), }) } else { None @@ -600,25 +601,18 @@ pub(crate) unsafe fn optimize( } unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) { - let sanitizer = match &config.sanitizer { - None => return, - Some(s) => s, - }; - - let recover = config.sanitizer_recover.contains(sanitizer); - match sanitizer { - Sanitizer::Address => { - passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover)); - passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover)); - } - Sanitizer::Memory => { - let track_origins = config.sanitizer_memory_track_origins as c_int; - passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover)); - } - Sanitizer::Thread => { - passes.push(llvm::LLVMRustCreateThreadSanitizerPass()); - } - Sanitizer::Leak => {} + if config.sanitizer.contains(SanitizerSet::ADDRESS) { + let recover = config.sanitizer_recover.contains(SanitizerSet::ADDRESS); + passes.push(llvm::LLVMRustCreateAddressSanitizerFunctionPass(recover)); + passes.push(llvm::LLVMRustCreateModuleAddressSanitizerPass(recover)); + } + if config.sanitizer.contains(SanitizerSet::MEMORY) { + let track_origins = config.sanitizer_memory_track_origins as c_int; + let recover = config.sanitizer_recover.contains(SanitizerSet::MEMORY); + passes.push(llvm::LLVMRustCreateMemorySanitizerPass(track_origins, recover)); + } + if config.sanitizer.contains(SanitizerSet::THREAD) { + passes.push(llvm::LLVMRustCreateThreadSanitizerPass()); } } diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 3e17a51528e..e99fb8dcae1 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -29,12 +29,12 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_middle::dep_graph; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::TyCtxt; -use rustc_session::config::DebugInfo; +use rustc_session::config::{DebugInfo, SanitizerSet}; use rustc_span::symbol::Symbol; use std::ffi::CString; @@ -132,7 +132,7 @@ pub fn compile_codegen_unit( // If this codegen unit contains the main function, also create the // wrapper here if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) { - attributes::sanitize(&cx, CodegenFnAttrFlags::empty(), entry); + attributes::sanitize(&cx, SanitizerSet::empty(), entry); } // Run replace-all-uses-with for statics that need it diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index f5ae9824df8..ba285b5ef38 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -997,6 +997,33 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size); } + fn instrprof_increment( + &mut self, + fn_name: &'ll Value, + hash: &'ll Value, + num_counters: &'ll Value, + index: &'ll Value, + ) -> &'ll Value { + debug!( + "instrprof_increment() with args ({:?}, {:?}, {:?}, {:?})", + fn_name, hash, num_counters, index + ); + + let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) }; + let args = &[fn_name, hash, num_counters, index]; + let args = self.check_call("call", llfn, args); + + unsafe { + llvm::LLVMRustBuildCall( + self.llbuilder, + llfn, + args.as_ptr() as *const &llvm::Value, + args.len() as c_uint, + None, + ) + } + } + fn call( &mut self, llfn: &'ll Value, diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index a5cda5949ee..64140747871 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -206,7 +206,7 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let len = s.as_str().len(); let cs = consts::ptrcast( self.const_cstr(s, false), - self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)), + self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)), ); (cs, self.const_usize(len as u64)) } diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 4c810a37d41..7ff5ac5cbdc 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -749,6 +749,8 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void); ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void); + ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void); + ifn!("llvm.expect.i1", fn(i1, i1) -> i1); ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); ifn!("llvm.localescape", fn(...) -> void); diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 333eb805221..8a957a729fb 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -1,4 +1,4 @@ -use self::EnumDiscriminantInfo::*; +use self::EnumTagInfo::*; use self::MemberDescriptionFactory::*; use self::RecursiveTypeDescription::*; @@ -40,7 +40,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::{Interner, Symbol}; use rustc_span::{self, SourceFile, SourceFileHash, Span}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf}; +use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; @@ -1335,7 +1335,7 @@ fn generator_layout_and_saved_local_names( struct EnumMemberDescriptionFactory<'ll, 'tcx> { enum_type: Ty<'tcx>, layout: TyAndLayout<'tcx>, - discriminant_type_metadata: Option<&'ll DIType>, + tag_type_metadata: Option<&'ll DIType>, containing_scope: &'ll DIScope, span: Span, } @@ -1385,7 +1385,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, self.layout, variant_info, - NoDiscriminant, + NoTag, self_metadata, self.span, ); @@ -1409,19 +1409,19 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { }] } Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - discr_index, + tag_encoding: TagEncoding::Direct, + tag_field, ref variants, .. } => { - let discriminant_info = if fallback { - RegularDiscriminant { - discr_field: Field::from(discr_index), - discr_type_metadata: self.discriminant_type_metadata.unwrap(), + let tag_info = if fallback { + RegularTag { + tag_field: Field::from(tag_field), + tag_type_metadata: self.tag_type_metadata.unwrap(), } } else { // This doesn't matter in this case. - NoDiscriminant + NoTag }; variants .iter_enumerated() @@ -1432,7 +1432,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - discriminant_info, + tag_info, self_metadata, self.span, ); @@ -1467,11 +1467,11 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .collect() } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { ref niche_variants, niche_start, dataful_variant }, - ref discr, + tag_encoding: + TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, + ref tag, ref variants, - discr_index, + tag_field, } => { if fallback { let variant = self.layout.for_variant(cx, dataful_variant); @@ -1480,7 +1480,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info_for(dataful_variant), - OptimizedDiscriminant, + OptimizedTag, self.containing_scope, self.span, ); @@ -1524,8 +1524,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, &mut name, self.layout, - self.layout.fields.offset(discr_index), - self.layout.field(cx, discr_index).size, + self.layout.fields.offset(tag_field), + self.layout.field(cx, tag_field).size, ); variant_info_for(*niche_variants.start()).map_struct_name(|variant_name| { name.push_str(variant_name); @@ -1552,7 +1552,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - OptimizedDiscriminant, + OptimizedTag, self_metadata, self.span, ); @@ -1573,7 +1573,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { let value = (i.as_u32() as u128) .wrapping_sub(niche_variants.start().as_u32() as u128) .wrapping_add(niche_start); - let value = truncate(value, discr.value.size(cx)); + let value = truncate(value, tag.value.size(cx)); // NOTE(eddyb) do *NOT* remove this assert, until // we pass the full 128-bit value to LLVM, otherwise // truncation will be silent and remain undetected. @@ -1603,7 +1603,7 @@ struct VariantMemberDescriptionFactory<'ll, 'tcx> { /// Cloned from the `layout::Struct` describing the variant. offsets: Vec<Size>, args: Vec<(String, Ty<'tcx>)>, - discriminant_type_metadata: Option<&'ll DIType>, + tag_type_metadata: Option<&'ll DIType>, span: Span, } @@ -1617,7 +1617,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: name.to_string(), type_metadata: if use_enum_fallback(cx) { - match self.discriminant_type_metadata { + match self.tag_type_metadata { // Discriminant is always the first field of our variant // when using the enum fallback. Some(metadata) if i == 0 => metadata, @@ -1637,11 +1637,14 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } +// FIXME: terminology here should be aligned with `abi::TagEncoding`. +// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`. +// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead. #[derive(Copy, Clone)] -enum EnumDiscriminantInfo<'ll> { - RegularDiscriminant { discr_field: Field, discr_type_metadata: &'ll DIType }, - OptimizedDiscriminant, - NoDiscriminant, +enum EnumTagInfo<'ll> { + RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, + OptimizedTag, + NoTag, } #[derive(Copy, Clone)] @@ -1706,7 +1709,7 @@ fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyAndLayout<'tcx>, variant: VariantInfo<'_, 'tcx>, - discriminant_info: EnumDiscriminantInfo<'ll>, + discriminant_info: EnumTagInfo<'ll>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { @@ -1722,12 +1725,12 @@ fn describe_enum_variant( let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant { discr_field, .. } => { + RegularTag { tag_field, .. } => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); - let offset = enum_layout.fields.offset(discr_field.as_usize()); + let offset = enum_layout.fields.offset(tag_field.as_usize()); let args = - ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, discr_field.as_usize()).ty); + ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), @@ -1757,8 +1760,8 @@ fn describe_enum_variant( let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { offsets, args, - discriminant_type_metadata: match discriminant_info { - RegularDiscriminant { discr_type_metadata, .. } => Some(discr_type_metadata), + tag_type_metadata: match discriminant_info { + RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata), _ => None, }, span, @@ -1880,18 +1883,18 @@ fn prepare_enum_metadata( if let ( &Abi::Scalar(_), - &Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. }, + &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. }, ) = (&layout.abi, &layout.variants) { - return FinalMetadata(discriminant_type_metadata(discr.value)); + return FinalMetadata(discriminant_type_metadata(tag.value)); } if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { Variants::Single { .. } - | Variants::Multiple { discr_kind: DiscriminantKind::Niche { .. }, .. } => None, - Variants::Multiple { discr_kind: DiscriminantKind::Tag, ref discr, .. } => { - Some(discriminant_type_metadata(discr.value)) + | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None, + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) } }; @@ -1927,7 +1930,7 @@ fn prepare_enum_metadata( EnumMDF(EnumMemberDescriptionFactory { enum_type, layout, - discriminant_type_metadata, + tag_type_metadata: discriminant_type_metadata, containing_scope, span, }), @@ -1943,16 +1946,13 @@ fn prepare_enum_metadata( Variants::Single { .. } => None, Variants::Multiple { - discr_kind: DiscriminantKind::Niche { .. }, - ref discr, - discr_index, - .. + tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, .. } => { // Find the integer type of the correct size. - let size = discr.value.size(cx); - let align = discr.value.align(cx); + let size = tag.value.size(cx); + let align = tag.value.align(cx); - let discr_type = match discr.value { + let tag_type = match tag.value { Int(t, _) => t, F32 => Integer::I32, F64 => Integer::I64, @@ -1960,7 +1960,7 @@ fn prepare_enum_metadata( } .to_ty(cx.tcx, false); - let discr_metadata = basic_type_metadata(cx, discr_type); + let tag_metadata = basic_type_metadata(cx, tag_type); unsafe { Some(llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), @@ -1971,17 +1971,15 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.abi.bits() as u32, - layout.fields.offset(discr_index).bits(), + layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, - discr_metadata, + tag_metadata, )) } } - Variants::Multiple { - discr_kind: DiscriminantKind::Tag, ref discr, discr_index, .. - } => { - let discr_type = discr.value.to_ty(cx.tcx); + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => { + let discr_type = tag.value.to_ty(cx.tcx); let (size, align) = cx.size_and_align_of(discr_type); let discr_metadata = basic_type_metadata(cx, discr_type); @@ -1995,7 +1993,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - layout.fields.offset(discr_index).bits(), + layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, discr_metadata, )) @@ -2081,7 +2079,7 @@ fn prepare_enum_metadata( EnumMDF(EnumMemberDescriptionFactory { enum_type, layout, - discriminant_type_metadata: None, + tag_type_metadata: None, containing_scope, span, }), diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 1e6d2e3dbb7..95465939070 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -7,6 +7,8 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; +use log::debug; + use rustc_ast::ast; use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; @@ -21,6 +23,7 @@ use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_span::Symbol; use rustc_target::abi::{self, HasDataLayout, LayoutOf, Primitive}; use rustc_target::spec::PanicStrategy; @@ -86,6 +89,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { args: &[OperandRef<'tcx, &'ll Value>], llresult: &'ll Value, span: Span, + caller_instance: ty::Instance<'tcx>, ) { let tcx = self.tcx; let callee_ty = instance.monomorphic_ty(tcx); @@ -136,6 +140,28 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } + "count_code_region" => { + if let ty::InstanceDef::Item(fn_def_id) = caller_instance.def { + let caller_fn_path = tcx.def_path_str(fn_def_id); + debug!( + "count_code_region to llvm.instrprof.increment(fn_name={})", + caller_fn_path + ); + + // FIXME(richkadel): (1) Replace raw function name with mangled function name; + // (2) Replace hardcoded `1234` in `hash` with a computed hash (as discussed in) + // the MCP (compiler-team/issues/278); and replace the hardcoded `1` for + // `num_counters` with the actual number of counters per function (when the + // changes are made to inject more than one counter per function). + let (fn_name, _len_val) = self.const_str(Symbol::intern(&caller_fn_path)); + let index = args[0].immediate(); + let hash = self.const_u64(1234); + let num_counters = self.const_u32(1); + self.instrprof_increment(fn_name, hash, num_counters, index) + } else { + bug!("intrinsic count_code_region: no src.instance"); + } + } "va_start" => self.va_start(args[0].immediate()), "va_end" => self.va_end(args[0].immediate()), "va_copy" => { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 54cf99e1c6d..8063d97aa73 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -439,11 +439,12 @@ pub enum OptStage { /// LLVMRustSanitizerOptions #[repr(C)] pub struct SanitizerOptions { - pub sanitize_memory: bool, - pub sanitize_thread: bool, pub sanitize_address: bool, - pub sanitize_recover: bool, + pub sanitize_address_recover: bool, + pub sanitize_memory: bool, + pub sanitize_memory_recover: bool, pub sanitize_memory_track_origins: c_int, + pub sanitize_thread: bool, } /// LLVMRelocMode @@ -1360,6 +1361,7 @@ extern "C" { // Miscellaneous instructions pub fn LLVMBuildPhi(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value; + pub fn LLVMRustGetInstrprofIncrementIntrinsic(M: &Module) -> &'a Value; pub fn LLVMRustBuildCall( B: &Builder<'a>, Fn: &'a Value, diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index 53e3da3c0ba..6c995be913c 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -4,7 +4,7 @@ use rustc_hir::def_id::CrateNum; use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo}; -use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, Sanitizer}; +use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet}; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; @@ -766,23 +766,26 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( } } -fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { - let sanitizer = match &sess.opts.debugging_opts.sanitizer { - Some(s) => s, - None => return, - }; - +fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) { if crate_type != CrateType::Executable { return; } + let sanitizer = sess.opts.debugging_opts.sanitizer; + if sanitizer.contains(SanitizerSet::ADDRESS) { + link_sanitizer_runtime(sess, linker, "asan"); + } + if sanitizer.contains(SanitizerSet::LEAK) { + link_sanitizer_runtime(sess, linker, "lsan"); + } + if sanitizer.contains(SanitizerSet::MEMORY) { + link_sanitizer_runtime(sess, linker, "msan"); + } + if sanitizer.contains(SanitizerSet::THREAD) { + link_sanitizer_runtime(sess, linker, "tsan"); + } +} - let name = match sanitizer { - Sanitizer::Address => "asan", - Sanitizer::Leak => "lsan", - Sanitizer::Memory => "msan", - Sanitizer::Thread => "tsan", - }; - +fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { let default_sysroot = filesearch::get_or_default_sysroot(); let default_tlib = filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple()); @@ -801,7 +804,10 @@ fn link_sanitizer_runtime(sess: &Session, crate_type: CrateType, linker: &mut dy linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib(Symbol::intern(&libname)); } - "x86_64-unknown-linux-gnu" | "x86_64-fuchsia" | "aarch64-fuchsia" => { + "aarch64-fuchsia" + | "aarch64-unknown-linux-gnu" + | "x86_64-fuchsia" + | "x86_64-unknown-linux-gnu" => { let filename = format!("librustc{}_rt.{}.a", channel, name); let path = default_tlib.join(&filename); linker.link_whole_rlib(&path); @@ -1075,6 +1081,10 @@ fn get_object_file_path(sess: &Session, name: &str) -> PathBuf { if file_path.exists() { return file_path; } + let file_path = fs.get_selfcontained_lib_path().join(name); + if file_path.exists() { + return file_path; + } for search_path in fs.search_paths() { let file_path = search_path.dir.join(name); if file_path.exists() { @@ -1470,6 +1480,9 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session) { // The location of crates will be determined as needed. let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); + + let lib_path = sess.target_filesearch(PathKind::All).get_selfcontained_lib_path(); + cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); } /// Add options making relocation sections in the produced ELF files read-only @@ -1548,9 +1561,10 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable { - let prefix = match sess.opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) => "asan/", - _ => "", + let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) { + "asan/" + } else { + "" }; cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); } @@ -1574,7 +1588,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // OBJECT-FILES-YES, AUDIT-ORDER - link_sanitizer_runtime(sess, crate_type, cmd); + link_sanitizers(sess, crate_type, cmd); // OBJECT-FILES-NO, AUDIT-ORDER // Linker plugins should be specified early in the list of arguments diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index b17c3678207..6011d422ca6 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -280,7 +280,7 @@ impl<'a> Linker for GccLinker<'a> { fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { - if !self.is_ld { + if !self.is_ld && self.sess.target.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -291,7 +291,7 @@ impl<'a> Linker for GccLinker<'a> { LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. self.cmd.arg("-static"); - if !self.is_ld { + if !self.is_ld && self.sess.target.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -721,12 +721,14 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { - // not supported? self.link_staticlib(lib); + self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib)); } fn link_whole_rlib(&mut self, path: &Path) { - // not supported? self.link_rlib(path); + let mut arg = OsString::from("/WHOLEARCHIVE:"); + arg.push(path); + self.cmd.arg(arg); } fn optimize(&mut self) { // Needs more investigation of `/OPT` arguments diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 970d13b30c0..217ad57ddc9 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; use rustc_middle::ty::{SymbolName, TyCtxt}; -use rustc_session::config::{CrateType, Sanitizer}; +use rustc_session::config::{CrateType, SanitizerSet}; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types()) @@ -89,10 +89,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap< | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { let def_id = tcx.hir().local_def_id(hir_id); let generics = tcx.generics_of(def_id); - if !generics.requires_monomorphization(tcx) && - // Functions marked with #[inline] are only ever codegened - // with "internal" linkage and are never exported. - !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) + if !generics.requires_monomorphization(tcx) + // Functions marked with #[inline] are codegened with "internal" + // linkage and are not exported unless marked with an extern + // inidicator + && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) + || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator()) { Some(def_id) } else { @@ -202,7 +204,7 @@ fn exported_symbols_provider_local( })); } - if let Some(Sanitizer::Memory) = tcx.sess.opts.debugging_opts.sanitizer { + if tcx.sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::MEMORY) { // Similar to profiling, preserve weak msan symbol during LTO. const MSAN_WEAK_SYMBOLS: [&str; 2] = ["__msan_track_origins", "__msan_keep_going"]; diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index c118e5ebdb7..23e0b9344ec 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -29,7 +29,7 @@ use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::CguReuseTracker; use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType}; -use rustc_session::config::{Passes, Sanitizer, SwitchWithOptPath}; +use rustc_session::config::{Passes, SanitizerSet, SwitchWithOptPath}; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{sym, Symbol}; @@ -86,8 +86,8 @@ pub struct ModuleConfig { pub pgo_gen: SwitchWithOptPath, pub pgo_use: Option<PathBuf>, - pub sanitizer: Option<Sanitizer>, - pub sanitizer_recover: Vec<Sanitizer>, + pub sanitizer: SanitizerSet, + pub sanitizer_recover: SanitizerSet, pub sanitizer_memory_track_origins: usize, // Flags indicating which outputs to produce. @@ -175,6 +175,12 @@ impl ModuleConfig { if sess.opts.debugging_opts.profile && !is_compiler_builtins { passes.push("insert-gcov-profiling".to_owned()); } + + // The rustc option `-Zinstrument_coverage` injects intrinsic calls to + // `llvm.instrprof.increment()`, which requires the LLVM `instrprof` pass. + if sess.opts.debugging_opts.instrument_coverage { + passes.push("instrprof".to_owned()); + } passes }, vec![] @@ -189,10 +195,10 @@ impl ModuleConfig { ), pgo_use: if_regular!(sess.opts.cg.profile_use.clone(), None), - sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer.clone(), None), + sanitizer: if_regular!(sess.opts.debugging_opts.sanitizer, SanitizerSet::empty()), sanitizer_recover: if_regular!( - sess.opts.debugging_opts.sanitizer_recover.clone(), - vec![] + sess.opts.debugging_opts.sanitizer_recover, + SanitizerSet::empty() ), sanitizer_memory_track_origins: if_regular!( sess.opts.debugging_opts.sanitizer_memory_track_origins, diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index 57a3d8b5edc..a64489c04c8 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -195,7 +195,7 @@ pub fn push_debuginfo_type_name<'tcx>( tcx.def_key(def_id).disambiguated_data.disambiguator )); } - ty::Error + ty::Error(_) | ty::Infer(_) | ty::Placeholder(..) | ty::Projection(..) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 61692280d2a..db935c2b3e2 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -234,8 +234,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> self.visit_rvalue(rvalue, location); } - fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) { - let check = match *kind { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + let check = match terminator.kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => { match c.literal.ty.kind { ty::FnDef(did, _) => Some((did, args)), @@ -259,7 +259,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } } - self.super_terminator_kind(kind, location); + self.super_terminator(terminator, location); } fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index ef59ad486ee..d56c816811b 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -693,6 +693,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &args, dest, terminator.source_info.span, + self.instance, ); if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -998,8 +999,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.unreachable(); } - mir::TerminatorKind::Drop { location, target, unwind } => { - self.codegen_drop_terminator(helper, bx, location, target, unwind); + mir::TerminatorKind::Drop { place, target, unwind } => { + self.codegen_drop_terminator(helper, bx, place, target, unwind); } mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 2be06793829..0c8638b673d 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -10,7 +10,7 @@ use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape, Int}; +use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding}; use rustc_target::abi::{LayoutOf, VariantIdx, Variants}; #[derive(Copy, Clone, Debug)] @@ -199,7 +199,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { if self.layout.abi.is_uninhabited() { return bx.cx().const_undef(cast_to); } - let (discr_scalar, discr_kind, discr_index) = match self.layout.variants { + let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { Variants::Single { index } => { let discr_val = self .layout @@ -208,33 +208,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { .map_or(index.as_u32() as u128, |discr| discr.val); return bx.cx().const_uint_big(cast_to, discr_val); } - Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { - (discr, discr_kind, discr_index) + Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) } }; // Read the tag/niche-encoded discriminant from memory. - let encoded_discr = self.project_field(bx, discr_index); - let encoded_discr = bx.load_operand(encoded_discr); + let tag = self.project_field(bx, tag_field); + let tag = bx.load_operand(tag); // Decode the discriminant (specifically if it's niche-encoded). - match *discr_kind { - DiscriminantKind::Tag => { - let signed = match discr_scalar.value { + match *tag_encoding { + TagEncoding::Direct => { + let signed = match tag_scalar.value { // We use `i1` for bytes that are always `0` or `1`, // e.g., `#[repr(i8)] enum E { A, B }`, but we can't // let LLVM interpret the `i1` as signed, because // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. - Int(_, signed) => !discr_scalar.is_bool() && signed, + Int(_, signed) => !tag_scalar.is_bool() && signed, _ => false, }; - bx.intcast(encoded_discr.immediate(), cast_to, signed) + bx.intcast(tag.immediate(), cast_to, signed) } - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. - let niche_llty = bx.cx().immediate_backend_type(encoded_discr.layout); - let encoded_discr = encoded_discr.immediate(); + let niche_llty = bx.cx().immediate_backend_type(tag.layout); + let tag = tag.immediate(); // We first compute the "relative discriminant" (wrt `niche_variants`), // that is, if `n = niche_variants.end() - niche_variants.start()`, @@ -248,9 +248,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let relative_discr = if niche_start == 0 { // Avoid subtracting `0`, which wouldn't work for pointers. // FIXME(eddyb) check the actual primitive type here. - encoded_discr + tag } else { - bx.sub(encoded_discr, bx.cx().const_uint_big(niche_llty, niche_start)) + bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start)) }; let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); let is_niche = { @@ -312,8 +312,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Variants::Single { index } => { assert_eq!(index, variant_index); } - Variants::Multiple { discr_kind: DiscriminantKind::Tag, discr_index, .. } => { - let ptr = self.project_field(bx, discr_index); + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { + let ptr = self.project_field(bx, tag_field); let to = self.layout.ty.discriminant_for_variant(bx.tcx(), variant_index).unwrap().val; bx.store( @@ -323,9 +323,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { ); } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, - discr_index, + tag_encoding: + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag_field, .. } => { if variant_index != dataful_variant { @@ -339,7 +339,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); } - let niche = self.project_field(bx, discr_index); + let niche = self.project_field(bx, tag_field); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128).wrapping_add(niche_start); diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index caba7ebef59..7ffc9f15bff 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -260,6 +260,14 @@ pub trait BuilderMethods<'a, 'tcx>: /// Called for `StorageDead` fn lifetime_end(&mut self, ptr: Self::Value, size: Size); + fn instrprof_increment( + &mut self, + fn_name: Self::Value, + hash: Self::Value, + num_counters: Self::Value, + index: Self::Value, + ) -> Self::Value; + fn call( &mut self, llfn: Self::Value, diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index 9d48e233de6..f6201949851 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -15,6 +15,7 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { args: &[OperandRef<'tcx, Self::Value>], llresult: Self::Value, span: Span, + caller_instance: ty::Instance<'tcx>, ); fn abort(&mut self); diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 3fb5e04efc9..738b3bc7539 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -439,9 +439,12 @@ E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), E0758: include_str!("./error_codes/E0758.md"), +E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), E0761: include_str!("./error_codes/E0761.md"), E0762: include_str!("./error_codes/E0762.md"), +E0763: include_str!("./error_codes/E0763.md"), +E0764: include_str!("./error_codes/E0764.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0668.md b/src/librustc_error_codes/error_codes/E0668.md index 3b43a1bcae9..b6fedfe53fc 100644 --- a/src/librustc_error_codes/error_codes/E0668.md +++ b/src/librustc_error_codes/error_codes/E0668.md @@ -1,11 +1,7 @@ Malformed inline assembly rejected by LLVM. -LLVM checks the validity of the constraints and the assembly string passed to -it. This error implies that LLVM seems something wrong with the inline -assembly call. +Erroneous code example: -In particular, it can happen if you forgot the closing bracket of a register -constraint (see issue #51430): ```compile_fail,E0668 #![feature(llvm_asm)] @@ -17,3 +13,10 @@ fn main() { } } ``` + +LLVM checks the validity of the constraints and the assembly string passed to +it. This error implies that LLVM seems something wrong with the inline +assembly call. + +In particular, it can happen if you forgot the closing bracket of a register +constraint (see issue #51430), like in the previous code example. diff --git a/src/librustc_error_codes/error_codes/E0670.md b/src/librustc_error_codes/error_codes/E0670.md index 2026370bec3..74c1af06cf4 100644 --- a/src/librustc_error_codes/error_codes/E0670.md +++ b/src/librustc_error_codes/error_codes/E0670.md @@ -1,6 +1,6 @@ Rust 2015 does not permit the use of `async fn`. -Example of erroneous code: +Erroneous code example: ```compile_fail,E0670 async fn foo() {} diff --git a/src/librustc_error_codes/error_codes/E0759.md b/src/librustc_error_codes/error_codes/E0759.md new file mode 100644 index 00000000000..a74759bdf63 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0759.md @@ -0,0 +1,67 @@ +A `'static` requirement in a return type involving a trait is not fulfilled. + +Erroneous code examples: + +```compile_fail,E0759 +use std::fmt::Debug; + +fn foo(x: &i32) -> impl Debug { + x +} +``` + +```compile_fail,E0759 +# use std::fmt::Debug; +fn bar(x: &i32) -> Box<dyn Debug> { + Box::new(x) +} +``` + +These examples have the same semantics as the following: + +```compile_fail,E0759 +# use std::fmt::Debug; +fn foo(x: &i32) -> impl Debug + 'static { + x +} +``` + +```compile_fail,E0759 +# use std::fmt::Debug; +fn bar(x: &i32) -> Box<dyn Debug + 'static> { + Box::new(x) +} +``` + +Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit +`'static` requirement, meaning that the value implementing them that is being +returned has to be either a `'static` borrow or an owned value. + +In order to change the requirement from `'static` to be a lifetime derived from +its arguments, you can add an explicit bound, either to an anonymous lifetime +`'_` or some appropriate named lifetime. + +``` +# use std::fmt::Debug; +fn foo(x: &i32) -> impl Debug + '_ { + x +} +fn bar(x: &i32) -> Box<dyn Debug + '_> { + Box::new(x) +} +``` + +These are equivalent to the following explicit lifetime annotations: + +``` +# use std::fmt::Debug; +fn foo<'a>(x: &'a i32) -> impl Debug + 'a { + x +} +fn bar<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { + Box::new(x) +} +``` + +[`dyn Trait`]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types +[`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits diff --git a/src/librustc_error_codes/error_codes/E0763.md b/src/librustc_error_codes/error_codes/E0763.md new file mode 100644 index 00000000000..095b779f3e7 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0763.md @@ -0,0 +1,13 @@ +A byte constant wasn't correctly ended. + +Erroneous code example: + +```compile_fail,E0763 +let c = b'a; // error! +``` + +To fix this error, add the missing quote: + +``` +let c = b'a'; // ok! +``` diff --git a/src/librustc_error_codes/error_codes/E0764.md b/src/librustc_error_codes/error_codes/E0764.md new file mode 100644 index 00000000000..e9061f988ac --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0764.md @@ -0,0 +1,39 @@ +Mutable references (`&mut`) can only be used in constant functions, not statics +or constants. This limitation exists to prevent the creation of constants that +have a mutable reference in their final value. If you had a constant of `&mut +i32` type, you could modify the value through that reference, making the +constant essentially mutable. While there could be a more fine-grained scheme +in the future that allows mutable references if they are not "leaked" to the +final value, a more conservative approach was chosen for now. `const fn` do not +have this problem, as the borrow checker will prevent the `const fn` from +returning new mutable references. + +Erroneous code example: + +```compile_fail,E0764 +#![feature(const_fn)] +#![feature(const_mut_refs)] + +fn main() { + const OH_NO: &'static mut usize = &mut 1; // error! +} +``` + +Remember: you cannot use a function call inside a constant or static. However, +you can totally use it in constant functions: + +``` +#![feature(const_fn)] +#![feature(const_mut_refs)] + +const fn foo(x: usize) -> usize { + let mut y = 1; + let z = &mut y; + *z += x; + y +} + +fn main() { + const FOO: usize = foo(10); // ok! +} +``` diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 7261c638ce0..0c1418d3cad 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -5,6 +5,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] #![feature(nll)] +#![feature(track_caller)] pub use emitter::ColorConfig; @@ -621,6 +622,7 @@ impl Handler { self.inner.borrow_mut().span_bug(span, msg) } + #[track_caller] pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) { self.inner.borrow_mut().delay_span_bug(span, msg) } @@ -873,6 +875,7 @@ impl HandlerInner { self.emit_diagnostic(diag.set_span(sp)); } + #[track_caller] fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) { // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before // incrementing `err_count` by one, so we need to +1 the comparing. @@ -883,6 +886,7 @@ impl HandlerInner { } let mut diagnostic = Diagnostic::new(Level::Bug, msg); diagnostic.set_span(sp.into()); + diagnostic.note(&format!("delayed at {}", std::panic::Location::caller())); self.delay_as_bug(diagnostic) } diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index d186f35a12b..7aadf58243f 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -596,4 +596,5 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::raw_dylib, sym::const_trait_impl, sym::const_trait_bound_opt_out, + sym::specialization, ]; diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 634ab32a285..eb1db46fd2b 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -12,6 +12,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; +use rustc_span::def_id::LocalDefId; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; @@ -2651,25 +2652,11 @@ pub type CaptureModeMap = NodeMap<CaptureBy>; // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. #[derive(Clone, Debug)] -pub struct TraitCandidate<ID = HirId> { +pub struct TraitCandidate { pub def_id: DefId, - pub import_ids: SmallVec<[ID; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, } -impl<ID> TraitCandidate<ID> { - pub fn map_import_ids<F, T>(self, f: F) -> TraitCandidate<T> - where - F: Fn(ID) -> T, - { - let TraitCandidate { def_id, import_ids } = self; - let import_ids = import_ids.into_iter().map(f).collect(); - TraitCandidate { def_id, import_ids } - } -} - -// Trait method resolution -pub type TraitMap<ID = HirId> = NodeMap<Vec<TraitCandidate<ID>>>; - #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum Node<'hir> { Param(&'hir Param<'hir>), @@ -2726,17 +2713,23 @@ impl Node<'_> { } } + pub fn body_id(&self) -> Option<BodyId> { + match self { + Node::TraitItem(TraitItem { + kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)), + .. + }) + | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. }) + | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id), + _ => None, + } + } + pub fn generics(&self) -> Option<&Generics<'_>> { match self { Node::TraitItem(TraitItem { generics, .. }) - | Node::ImplItem(ImplItem { generics, .. }) - | Node::Item(Item { - kind: - ItemKind::Trait(_, _, generics, ..) - | ItemKind::Impl { generics, .. } - | ItemKind::Fn(_, generics, _), - .. - }) => Some(generics), + | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), + Node::Item(item) => item.kind.generics(), _ => None, } } diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 83bada40419..091ded6d74d 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -242,6 +242,8 @@ language_item_table! { StartFnLangItem, "start", start_fn, Target::Fn; + CountCodeRegionFnLangItem, "count_code_region", count_code_region_fn, Target::Fn; + EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn; EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static; diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/src/librustc_infer/infer/canonical/canonicalizer.rs index c2dae6ba4f8..2dc803b9595 100644 --- a/src/librustc_infer/infer/canonical/canonicalizer.rs +++ b/src/librustc_infer/infer/canonical/canonicalizer.rs @@ -314,18 +314,19 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } ty::ReVar(vid) => { - let r = self + let resolved_vid = self .infcx .unwrap() .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(self.tcx, vid); + .opportunistic_resolve_var(vid); debug!( "canonical: region var found with vid {:?}, \ opportunistically resolved to {:?}", vid, r ); + let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid)); self.canonicalize_region_mode.canonicalize_free_region(self, r) } @@ -403,7 +404,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::Float(..) | ty::Adt(..) | ty::Str - | ty::Error + | ty::Error(_) | ty::Array(..) | ty::Slice(..) | ty::RawPtr(..) diff --git a/src/librustc_infer/infer/canonical/mod.rs b/src/librustc_infer/infer/canonical/mod.rs index 7310d2c3bdc..2b8c46f1de4 100644 --- a/src/librustc_infer/infer/canonical/mod.rs +++ b/src/librustc_infer/infer/canonical/mod.rs @@ -154,7 +154,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { self.tcx .mk_const(ty::Const { val: ty::ConstKind::Placeholder(placeholder_mapped), - ty: self.tcx.types.err, // FIXME(const_generics) + ty: self.tcx.ty_error(), // FIXME(const_generics) }) .into() } diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 12f7a9c0ca5..9cfa11dd7c8 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -2035,8 +2035,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.sess, var_origin.span(), E0495, - "cannot infer an appropriate lifetime{} \ - due to conflicting requirements", + "cannot infer an appropriate lifetime{} due to conflicting requirements", var_description ) } diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 1361d5bede6..1687bcc1556 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -88,6 +88,17 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { if let (None, Some(ty)) = (self.found_local_pattern, self.node_ty_contains_target(local.hir_id)) { + // FIXME: There's a trade-off here - we can either check that our target span + // is contained in `local.span` or not. If we choose to check containment + // we can avoid some spurious suggestions (see #72690), but we lose + // the ability to report on things like: + // + // ``` + // let x = vec![]; + // ``` + // + // because the target span will be in the macro expansion of `vec![]`. + // At present we choose not to check containment. self.found_local_pattern = Some(&*local.pat); self.found_node_ty = Some(ty); } @@ -99,8 +110,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> { if let (None, Some(ty)) = (self.found_arg_pattern, self.node_ty_contains_target(param.hir_id)) { - self.found_arg_pattern = Some(&*param.pat); - self.found_node_ty = Some(ty); + if self.target_span.contains(param.pat.span) { + self.found_arg_pattern = Some(&*param.pat); + self.found_node_ty = Some(ty); + } } } intravisit::walk_body(self, body); diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs index f4c86ddae60..82feebc8029 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -1,14 +1,15 @@ //! Error Reporting for static impl Traits. -use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; -use rustc_errors::{Applicability, ErrorReported}; +use rustc_errors::{struct_span_err, Applicability, ErrorReported}; +use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind}; use rustc_middle::ty::RegionKind; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static impl Trait. pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> { + debug!("try_report_static_impl_trait(error={:?})", self.error); if let Some(ref error) = self.error { if let RegionResolutionError::SubSupConflict( _, @@ -17,18 +18,36 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub_r, sup_origin, sup_r, - ) = error.clone() + ) = error { + debug!( + "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})", + var_origin, sub_origin, sub_r, sup_origin, sup_r + ); let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - let (fn_return_span, is_dyn) = - self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; - if sub_r == &RegionKind::ReStatic { + debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup); + let fn_return = self.tcx().return_type_impl_or_dyn_trait(anon_reg_sup.def_id)?; + debug!("try_report_static_impl_trait: fn_return={:?}", fn_return); + if **sub_r == RegionKind::ReStatic { let sp = var_origin.span(); let return_sp = sub_origin.span(); - let mut err = - self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); let param_info = self.find_param_with_region(sup_r, sub_r)?; - err.span_label(param_info.param_ty_span, "data with this lifetime..."); + let (lifetime_name, lifetime) = if sup_r.has_name() { + (sup_r.to_string(), format!("lifetime `{}`", sup_r)) + } else { + ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) + }; + let mut err = struct_span_err!( + self.tcx().sess, + sp, + E0759, + "cannot infer an appropriate lifetime" + ); + err.span_label( + param_info.param_ty_span, + &format!("this data with {}...", lifetime), + ); + debug!("try_report_static_impl_trait: param_info={:?}", param_info); // We try to make the output have fewer overlapping spans if possible. if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) @@ -38,41 +57,146 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Customize the spans and labels depending on their relative order so // that split sentences flow correctly. - if sup_origin.span().shrink_to_hi() <= return_sp.shrink_to_lo() { - err.span_label(sup_origin.span(), "...is captured here..."); - err.span_label(return_sp, "...and required to be `'static` by this"); + if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { + // Avoid the following: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ---------^- + // + // and instead show: + // + // error: cannot infer an appropriate lifetime + // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + // | + // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) } + // | ---- ^ + err.span_label( + sup_origin.span(), + "...is captured here, requiring it to live as long as `'static`", + ); } else { - err.span_label(return_sp, "...is required to be `'static` by this..."); - err.span_label(sup_origin.span(), "...and is captured here"); + err.span_label(sup_origin.span(), "...is captured here..."); + if return_sp < sup_origin.span() { + err.span_note( + return_sp, + "...and is required to live as long as `'static` here", + ); + } else { + err.span_label( + return_sp, + "...and is required to live as long as `'static` here", + ); + } } } else { err.span_label( return_sp, - "...is captured and required to be `'static` here", + "...is captured and required to live as long as `'static` here", ); } - let (lifetime, _) = msg_span_from_free_region(self.tcx(), sup_r); - - let lifetime_name = - if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; // only apply this suggestion onto functions with // explicit non-desugar'able return. - if fn_return_span.desugaring_kind().is_none() { - let msg = format!( - "to permit non-static references in {} `{} Trait` value, you can add \ - an explicit bound for {}", - if is_dyn { "a" } else { "an" }, - if is_dyn { "dyn" } else { "impl" }, - lifetime, - ); + if fn_return.span.desugaring_kind().is_none() { // FIXME: account for the need of parens in `&(dyn Trait + '_)` - err.span_suggestion_verbose( - fn_return_span.shrink_to_hi(), - &msg, - format!(" + {}", lifetime_name), - Applicability::MaybeIncorrect, - ); + + let consider = "consider changing the"; + let declare = "to declare that the"; + let arg = match param_info.param.pat.simple_ident() { + Some(simple_ident) => format!("argument `{}`", simple_ident), + None => "the argument".to_string(), + }; + let explicit = + format!("you can add an explicit `{}` lifetime bound", lifetime_name); + let explicit_static = + format!("explicit `'static` bound to the lifetime of {}", arg); + let captures = format!("captures data from {}", arg); + let add_static_bound = + "alternatively, add an explicit `'static` bound to this reference"; + let plus_lt = format!(" + {}", lifetime_name); + match fn_return.kind { + TyKind::OpaqueDef(item_id, _) => { + let item = self.tcx().hir().item(item_id.id); + let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind { + opaque + } else { + err.emit(); + return Some(ErrorReported); + }; + + if let Some(span) = opaque + .bounds + .iter() + .filter_map(|arg| match arg { + GenericBound::Outlives(Lifetime { + name: LifetimeName::Static, + span, + .. + }) => Some(*span), + _ => None, + }) + .next() + { + err.span_suggestion_verbose( + span, + &format!("{} `impl Trait`'s {}", consider, explicit_static), + lifetime_name, + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + add_static_bound, + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} `impl Trait` {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt, + Applicability::MaybeIncorrect, + ); + }; + } + TyKind::TraitObject(_, lt) => match lt.name { + LifetimeName::ImplicitObjectLifetimeDefault => { + err.span_suggestion_verbose( + fn_return.span.shrink_to_hi(), + &format!( + "{declare} trait object {captures}, {explicit}", + declare = declare, + captures = captures, + explicit = explicit, + ), + plus_lt, + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_suggestion_verbose( + lt.span, + &format!("{} trait object's {}", consider, explicit_static), + lifetime_name, + Applicability::MaybeIncorrect, + ); + err.span_suggestion_verbose( + param_info.param_ty_span, + add_static_bound, + param_info.param_ty.to_string(), + Applicability::MaybeIncorrect, + ); + } + }, + _ => {} + } } err.emit(); return Some(ErrorReported); diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs index b4cfcb3a1c3..02bebe10ed0 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { | ty::Float(..) | ty::Adt(..) | ty::Str - | ty::Error + | ty::Error(_) | ty::Array(..) | ty::Slice(..) | ty::RawPtr(..) @@ -250,7 +250,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::ConstKind::Param(_) | ty::ConstKind::Value(_) | ty::ConstKind::Unevaluated(..) - | ty::ConstKind::Error => {} + | ty::ConstKind::Error(_) => {} } ct.super_fold_with(self) diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs index ef18918c177..0499dc9ed22 100644 --- a/src/librustc_infer/infer/higher_ranked/mod.rs +++ b/src/librustc_infer/infer/higher_ranked/mod.rs @@ -63,14 +63,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// placeholder region. This is the first step of checking subtyping /// when higher-ranked things are involved. /// - /// **Important:** you must call this function from within a snapshot. - /// Moreover, before committing the snapshot, you must eventually call - /// either `plug_leaks` or `pop_placeholders` to remove the placeholder - /// regions. If you rollback the snapshot (or are using a probe), then - /// the pop occurs as part of the rollback, so an explicit call is not - /// needed (but is also permitted). - /// - /// For more information about how placeholders and HRTBs work, see + /// **Important:** You have to be careful to not leak these placeholders, + /// for more information about how placeholders and HRTBs work, see /// the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 92387f753f5..91f4b3323f3 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1751,9 +1751,10 @@ impl<'tcx> TypeTrace<'tcx> { } pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { + let err = tcx.ty_error(); TypeTrace { cause: ObligationCause::dummy(), - values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }), + values: Types(ExpectedFound { expected: err, found: err }), } } } diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 473550d5433..91c39a0e78f 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -128,7 +128,7 @@ impl<'tcx> TaintSet<'tcx> { verifys[i].origin.span(), "we never add verifications while doing higher-ranked things", ), - &Purged | &AddCombination(..) | &AddVar(..) => {} + &AddCombination(..) | &AddVar(..) => {} } } } diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 626774617a6..2902c41a6bc 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -50,10 +50,10 @@ pub struct RegionConstraintStorage<'tcx> { /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this /// table. You can then call `opportunistic_resolve_var` early /// which will map R1 and R2 to some common region (i.e., either - /// R1 or R2). This is important when dropck and other such code - /// is iterating to a fixed point, because otherwise we sometimes - /// would wind up with a fresh stream of region variables that - /// have been equated but appear distinct. + /// R1 or R2). This is important when fulfillment, dropck and other such + /// code is iterating to a fixed point, because otherwise we sometimes + /// would wind up with a fresh stream of region variables that have been + /// equated but appear distinct. pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>, /// a flag set to true when we perform any unifications; this is used @@ -289,14 +289,6 @@ pub(crate) enum UndoLog<'tcx> { /// We added a GLB/LUB "combination variable". AddCombination(CombineMapType, TwoRegions<'tcx>), - - /// During skolemization, we sometimes purge entries from the undo - /// log in a kind of minisnapshot (unlike other snapshots, this - /// purging actually takes place *on success*). In that case, we - /// replace the corresponding entry with `Noop` so as to avoid the - /// need to do a bunch of swapping. (We can't use `swap_remove` as - /// the order of the vector is important.) - Purged, } #[derive(Copy, Clone, PartialEq)] @@ -357,9 +349,6 @@ impl<'tcx> RegionConstraintStorage<'tcx> { fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { match undo_entry { - Purged => { - // nothing to do here - } AddVar(vid) => { self.var_infos.pop().unwrap(); assert_eq!(self.var_infos.len(), vid.index() as usize); @@ -488,62 +477,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.var_infos[vid].origin } - /// Removes all the edges to/from the placeholder regions that are - /// in `skols`. This is used after a higher-ranked operation - /// completes to remove all trace of the placeholder regions - /// created in that time. - pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) { - debug!("pop_placeholders(placeholders={:?})", placeholders); - - assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); - - let constraints_to_kill: Vec<usize> = self - .undo_log - .iter() - .enumerate() - .rev() - .filter(|&(_, undo_entry)| match undo_entry { - super::UndoLog::RegionConstraintCollector(undo_entry) => { - kill_constraint(placeholders, undo_entry) - } - _ => false, - }) - .map(|(index, _)| index) - .collect(); - - for index in constraints_to_kill { - let undo_entry = match &mut self.undo_log[index] { - super::UndoLog::RegionConstraintCollector(undo_entry) => { - mem::replace(undo_entry, Purged) - } - _ => unreachable!(), - }; - self.rollback_undo_entry(undo_entry); - } - - return; - - fn kill_constraint<'tcx>( - placeholders: &FxHashSet<ty::Region<'tcx>>, - undo_entry: &UndoLog<'tcx>, - ) -> bool { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(..)) => false, - &AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a), - &AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b), - &AddConstraint(Constraint::RegSubReg(a, b)) => { - placeholders.contains(&a) || placeholders.contains(&b) - } - &AddGiven(..) => false, - &AddVerify(_) => false, - &AddCombination(_, ref two_regions) => { - placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b) - } - &AddVar(..) | &Purged => false, - } - } - } - fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { // cannot add constraints once regions are resolved debug!("RegionConstraintCollector: add_constraint({:?})", constraint); @@ -714,13 +647,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn opportunistic_resolve_var( - &mut self, - tcx: TyCtxt<'tcx>, - rid: RegionVid, - ) -> ty::Region<'tcx> { - let vid = self.unification_table().probe_value(rid).min_vid; - tcx.mk_region(ty::ReVar(vid)) + pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid { + self.unification_table().probe_value(rid).min_vid } fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { diff --git a/src/librustc_infer/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs index e28cf49c7f2..74f365ced23 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/src/librustc_infer/infer/resolve.rs @@ -46,51 +46,56 @@ impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { } } -/// The opportunistic type and region resolver is similar to the -/// opportunistic type resolver, but also opportunistically resolves -/// regions. It is useful for canonicalization. -pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx> { +/// The opportunistic region resolver opportunistically resolves regions +/// variables to the variable with the least variable id. It is used when +/// normlizing projections to avoid hitting the recursion limit by creating +/// many versions of a predicate for types that in the end have to unify. +/// +/// If you want to resolve type and const variables as well, call +/// [InferCtxt::resolve_vars_if_possible] first. +pub struct OpportunisticRegionResolver<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, } -impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> { +impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - OpportunisticTypeAndRegionResolver { infcx } + OpportunisticRegionResolver { infcx } } } -impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticRegionResolver<'a, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { self.infcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() { + if !t.has_infer_regions() { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { - let t0 = self.infcx.shallow_resolve(t); - t0.super_fold_with(self) + t.super_fold_with(self) } } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReVar(rid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.tcx(), rid), + ty::ReVar(rid) => { + let resolved = self + .infcx + .inner + .borrow_mut() + .unwrap_region_constraints() + .opportunistic_resolve_var(rid); + self.tcx().reuse_or_mk_region(r, ty::ReVar(resolved)) + } _ => r, } } fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !ct.needs_infer() { + if !ct.has_infer_regions() { ct // micro-optimize -- if there is nothing in this const that this fold affects... } else { - let c0 = self.infcx.shallow_resolve(ct); - c0.super_fold_with(self) + ct.super_fold_with(self) } } } @@ -189,15 +194,15 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { match t.kind { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); - self.tcx().types.err + self.tcx().ty_error() } ty::Infer(ty::IntVar(vid)) => { self.err = Some(FixupError::UnresolvedIntTy(vid)); - self.tcx().types.err + self.tcx().ty_error() } ty::Infer(ty::FloatVar(vid)) => { self.err = Some(FixupError::UnresolvedFloatTy(vid)); - self.tcx().types.err + self.tcx().ty_error() } ty::Infer(_) => { bug!("Unexpected type in full type resolver: {:?}", t); @@ -228,7 +233,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { match c.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { self.err = Some(FixupError::UnresolvedConst(vid)); - return self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: c.ty }); + return self.tcx().const_error(c.ty); } ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index b51af19883f..90962d210b5 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -119,9 +119,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { Ok(a) } - (&ty::Error, _) | (_, &ty::Error) => { + (&ty::Error(_), _) | (_, &ty::Error(_)) => { infcx.set_tainted_by_errors(); - Ok(self.tcx().types.err) + Ok(self.tcx().ty_error()) } _ => { diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs index e7f1869955d..2cfd6bb904c 100644 --- a/src/librustc_infer/infer/undo_log.rs +++ b/src/librustc_infer/infer/undo_log.rs @@ -198,10 +198,6 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> { assert!(self.logs.len() >= snapshot.undo_len); assert!(self.num_open_snapshots > 0); } - - pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> { - self.logs.iter() - } } impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> { diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index a15ac819be9..47555aca9f3 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -29,10 +29,10 @@ crate use self::util::elaborate_predicates; pub use rustc_middle::traits::*; -/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for +/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for /// which the "impl_source" must be found. The process of finding a "impl_source" is /// called "resolving" the `Obligation`. This process consists of -/// either identifying an `impl` (e.g., `impl Eq for int`) that +/// either identifying an `impl` (e.g., `impl Eq for i32`) that /// satisfies the obligation, or else finding a bound that is in /// scope. The eventual result is usually a `Selection` (defined below). #[derive(Clone, PartialEq, Eq, Hash)] diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index ee9846c64b6..4ae7e417a8f 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -63,11 +63,11 @@ impl PredicateSet<'tcx> { fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool { // We have to be careful here because we want // - // for<'a> Foo<&'a int> + // for<'a> Foo<&'a i32> // // and // - // for<'b> Foo<&'b int> + // for<'b> Foo<&'b i32> // // to be considered equivalent. So normalize all late-bound // regions before we throw things into the underlying set. diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index bbe2e8da12e..d861b444c88 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -6,7 +6,9 @@ use rustc_session::config::Strip; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes}; use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; -use rustc_session::config::{Externs, OutputType, OutputTypes, Sanitizer, SymbolManglingVersion}; +use rustc_session::config::{ + Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion, +}; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::NativeLibKind; @@ -548,6 +550,7 @@ fn test_debugging_options_tracking_hash() { tracked!(human_readable_cgu_names, true); tracked!(inline_in_all_cgus, Some(true)); tracked!(insert_sideeffect, true); + tracked!(instrument_coverage, true); tracked!(instrument_mcount, true); tracked!(link_only, true); tracked!(merge_functions, Some(MergeFunctions::Disabled)); @@ -568,9 +571,9 @@ fn test_debugging_options_tracking_hash() { tracked!(relro_level, Some(RelroLevel::Full)); tracked!(report_delayed_bugs, true); tracked!(run_dsymutil, false); - tracked!(sanitizer, Some(Sanitizer::Address)); + tracked!(sanitizer, SanitizerSet::ADDRESS); tracked!(sanitizer_memory_track_origins, 2); - tracked!(sanitizer_recover, vec![Sanitizer::Address]); + tracked!(sanitizer_recover, SanitizerSet::ADDRESS); tracked!(saturating_float_casts, Some(true)); tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); diff --git a/src/librustc_lint/early.rs b/src/librustc_lint/early.rs index 06987ffa3d5..d891466611a 100644 --- a/src/librustc_lint/early.rs +++ b/src/librustc_lint/early.rs @@ -55,7 +55,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { where F: FnOnce(&mut Self), { - let push = self.context.builder.push(attrs, &self.context.lint_store); + let is_crate_node = id == ast::CRATE_NODE_ID; + let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node); self.check_id(id); self.enter_attrs(attrs); f(self); diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 05e7c9a0c78..f875e2750a5 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -29,7 +29,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap { let mut builder = LintLevelMapBuilder { levels, tcx, store }; let krate = tcx.hir().krate(); - let push = builder.levels.push(&krate.item.attrs, &store); + let push = builder.levels.push(&krate.item.attrs, &store, true); builder.levels.register_id(hir::CRATE_HIR_ID); for macro_def in krate.exported_macros { builder.levels.register_id(macro_def.hir_id); @@ -109,7 +109,12 @@ impl<'s> LintLevelsBuilder<'s> { /// `#[allow]` /// /// Don't forget to call `pop`! - pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush { + pub fn push( + &mut self, + attrs: &[ast::Attribute], + store: &LintStore, + is_crate_node: bool, + ) -> BuilderPush { let mut specs = FxHashMap::default(); let sess = self.sess; let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input"); @@ -333,6 +338,40 @@ impl<'s> LintLevelsBuilder<'s> { } } + if !is_crate_node { + for (id, &(level, ref src)) in specs.iter() { + if !id.lint.crate_level_only { + continue; + } + + let (lint_attr_name, lint_attr_span) = match *src { + LintSource::Node(name, span, _) => (name, span), + _ => continue, + }; + + let lint = builtin::UNUSED_ATTRIBUTES; + let (lint_level, lint_src) = + self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess); + struct_lint_level( + self.sess, + lint, + lint_level, + lint_src, + Some(lint_attr_span.into()), + |lint| { + let mut db = lint.build(&format!( + "{}({}) is ignored unless specified at crate level", + level.as_str(), + lint_attr_name + )); + db.emit(); + }, + ); + // don't set a separate error for every lint in the group + break; + } + } + for (id, &(level, ref src)) in specs.iter() { if level == Level::Forbid { continue; @@ -449,7 +488,8 @@ impl LintLevelMapBuilder<'_, '_> { where F: FnOnce(&mut Self), { - let push = self.levels.push(attrs, self.store); + let is_crate_hir = id == hir::CRATE_HIR_ID; + let push = self.levels.push(attrs, self.store, is_crate_hir); if push.changed { self.levels.register_id(id); } diff --git a/src/librustc_lint/non_ascii_idents.rs b/src/librustc_lint/non_ascii_idents.rs index ad02b2637d2..064b0255397 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/src/librustc_lint/non_ascii_idents.rs @@ -8,20 +8,23 @@ use std::ops::Deref; declare_lint! { pub NON_ASCII_IDENTS, Allow, - "detects non-ASCII identifiers" + "detects non-ASCII identifiers", + crate_level_only } declare_lint! { pub UNCOMMON_CODEPOINTS, Warn, - "detects uncommon Unicode codepoints in identifiers" + "detects uncommon Unicode codepoints in identifiers", + crate_level_only } // FIXME: Change this to warn. declare_lint! { pub CONFUSABLE_IDENTS, Allow, - "detects visually confusable pairs between identifiers" + "detects visually confusable pairs between identifiers", + crate_level_only } declare_lint_pass!(NonAsciiIdents => [NON_ASCII_IDENTS, UNCOMMON_CODEPOINTS, CONFUSABLE_IDENTS]); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a8ecfdd0f3d..d92c1131ff9 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -11,11 +11,11 @@ use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_target::abi::{DiscriminantKind, Integer, LayoutOf, VariantIdx, Variants}; +use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants}; use rustc_target::spec::abi::Abi; use log::debug; @@ -507,7 +507,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> { enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), - FfiUnsafe { ty: Ty<'tcx>, reason: &'static str, help: Option<&'static str> }, + FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> }, } fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { @@ -597,6 +597,66 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } + /// Checks if the given field's type is "ffi-safe". + fn check_field_type_for_ffi( + &self, + cache: &mut FxHashSet<Ty<'tcx>>, + field: &ty::FieldDef, + substs: SubstsRef<'tcx>, + ) -> FfiResult<'tcx> { + let field_ty = field.ty(self.cx.tcx, substs); + if field_ty.has_opaque_types() { + self.check_type_for_ffi(cache, field_ty) + } else { + let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty); + self.check_type_for_ffi(cache, field_ty) + } + } + + /// Checks if the given `VariantDef`'s field types are "ffi-safe". + fn check_variant_for_ffi( + &self, + cache: &mut FxHashSet<Ty<'tcx>>, + ty: Ty<'tcx>, + def: &ty::AdtDef, + variant: &ty::VariantDef, + substs: SubstsRef<'tcx>, + ) -> FfiResult<'tcx> { + use FfiResult::*; + + if def.repr.transparent() { + // Can assume that only one field is not a ZST, so only check + // that field's type for FFI-safety. + if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) { + self.check_field_type_for_ffi(cache, field, substs) + } else { + bug!("malformed transparent type"); + } + } else { + // We can't completely trust repr(C) markings; make sure the fields are + // actually safe. + let mut all_phantom = !variant.fields.is_empty(); + for field in &variant.fields { + match self.check_field_type_for_ffi(cache, &field, substs) { + FfiSafe => { + all_phantom = false; + } + FfiPhantom(..) if def.is_enum() => { + return FfiUnsafe { + ty, + reason: "this enum contains a PhantomData field".into(), + help: None, + }; + } + FfiPhantom(..) => {} + r => return r, + } + } + + if all_phantom { FfiPhantom(ty) } else { FfiSafe } + } + } + /// Checks if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> { @@ -618,15 +678,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiPhantom(ty); } match def.adt_kind() { - AdtKind::Struct => { + AdtKind::Struct | AdtKind::Union => { + let kind = if def.is_struct() { "struct" } else { "union" }; + if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { ty, - reason: "this struct has unspecified layout", - help: Some( + reason: format!("this {} has unspecified layout", kind), + help: Some(format!( "consider adding a `#[repr(C)]` or \ - `#[repr(transparent)]` attribute to this struct", - ), + `#[repr(transparent)]` attribute to this {}", + kind + )), }; } @@ -635,7 +698,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !def.did.is_local() { return FfiUnsafe { ty, - reason: "this struct is non-exhaustive", + reason: format!("this {} is non-exhaustive", kind), help: None, }; } @@ -643,93 +706,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { ty, - reason: "this struct has no fields", - help: Some("consider adding a member to this struct"), - }; - } - - if def.repr.transparent() { - // Can assume that only one field is not a ZST, so only check - // that field's type for FFI-safety. - if let Some(field) = - def.transparent_newtype_field(cx, self.cx.param_env) - { - let field_ty = cx.normalize_erasing_regions( - self.cx.param_env, - field.ty(cx, substs), - ); - self.check_type_for_ffi(cache, field_ty) - } else { - FfiSafe - } - } else { - // We can't completely trust repr(C) markings; make sure the fields are - // actually safe. - let mut all_phantom = true; - for field in &def.non_enum_variant().fields { - let field_ty = cx.normalize_erasing_regions( - self.cx.param_env, - field.ty(cx, substs), - ); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => { - all_phantom = false; - } - FfiPhantom(..) => {} - FfiUnsafe { .. } => { - return r; - } - } - } - - if all_phantom { FfiPhantom(ty) } else { FfiSafe } - } - } - AdtKind::Union => { - if !def.repr.c() && !def.repr.transparent() { - return FfiUnsafe { - ty, - reason: "this union has unspecified layout", - help: Some( - "consider adding a `#[repr(C)]` or \ - `#[repr(transparent)]` attribute to this union", - ), - }; - } - - if def.non_enum_variant().fields.is_empty() { - return FfiUnsafe { - ty, - reason: "this union has no fields", - help: Some("consider adding a field to this union"), + reason: format!("this {} has no fields", kind), + help: Some(format!("consider adding a member to this {}", kind)), }; } - let mut all_phantom = true; - for field in &def.non_enum_variant().fields { - let field_ty = cx.normalize_erasing_regions( - ParamEnv::reveal_all(), - field.ty(cx, substs), - ); - // repr(transparent) types are allowed to have arbitrary ZSTs, not just - // PhantomData -- skip checking all ZST fields. - if def.repr.transparent() && field_ty.is_zst(cx, field.did) { - continue; - } - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => { - all_phantom = false; - } - FfiPhantom(..) => {} - FfiUnsafe { .. } => { - return r; - } - } - } - - if all_phantom { FfiPhantom(ty) } else { FfiSafe } + self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), substs) } AdtKind::Enum => { if def.variants.is_empty() { @@ -744,11 +726,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !is_repr_nullable_ptr(cx, ty, def, substs) { return FfiUnsafe { ty, - reason: "enum has no representation hint", + reason: "enum has no representation hint".into(), help: Some( "consider adding a `#[repr(C)]`, \ `#[repr(transparent)]`, or integer `#[repr(...)]` \ - attribute to this enum", + attribute to this enum" + .into(), ), }; } @@ -757,7 +740,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.is_variant_list_non_exhaustive() && !def.did.is_local() { return FfiUnsafe { ty, - reason: "this enum is non-exhaustive", + reason: "this enum is non-exhaustive".into(), help: None, }; } @@ -768,37 +751,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if is_non_exhaustive && !variant.def_id.is_local() { return FfiUnsafe { ty, - reason: "this enum has non-exhaustive variants", + reason: "this enum has non-exhaustive variants".into(), help: None, }; } - for field in &variant.fields { - let field_ty = cx.normalize_erasing_regions( - ParamEnv::reveal_all(), - field.ty(cx, substs), - ); - // repr(transparent) types are allowed to have arbitrary ZSTs, not - // just PhantomData -- skip checking all ZST fields. - if def.repr.transparent() && field_ty.is_zst(cx, field.did) { - continue; - } - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiUnsafe { .. } => { - return r; - } - FfiPhantom(..) => { - return FfiUnsafe { - ty, - reason: "this enum contains a PhantomData field", - help: None, - }; - } - } + match self.check_variant_for_ffi(cache, ty, def, variant, substs) { + FfiSafe => (), + r => return r, } } + FfiSafe } } @@ -806,13 +769,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Char => FfiUnsafe { ty, - reason: "the `char` type has no C equivalent", - help: Some("consider using `u32` or `libc::wchar_t` instead"), + reason: "the `char` type has no C equivalent".into(), + help: Some("consider using `u32` or `libc::wchar_t` instead".into()), }, ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe { ty, - reason: "128-bit integers don't currently have a known stable ABI", + reason: "128-bit integers don't currently have a known stable ABI".into(), help: None, }, @@ -821,24 +784,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Slice(_) => FfiUnsafe { ty, - reason: "slices have no C equivalent", - help: Some("consider using a raw pointer instead"), + reason: "slices have no C equivalent".into(), + help: Some("consider using a raw pointer instead".into()), }, ty::Dynamic(..) => { - FfiUnsafe { ty, reason: "trait objects have no C equivalent", help: None } + FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None } } ty::Str => FfiUnsafe { ty, - reason: "string slices have no C equivalent", - help: Some("consider using `*const u8` and a length instead"), + reason: "string slices have no C equivalent".into(), + help: Some("consider using `*const u8` and a length instead".into()), }, ty::Tuple(..) => FfiUnsafe { ty, - reason: "tuples have unspecified layout", - help: Some("consider using a struct instead"), + reason: "tuples have unspecified layout".into(), + help: Some("consider using a struct instead".into()), }, ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { @@ -852,10 +815,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { return FfiUnsafe { ty, - reason: "this function pointer has Rust-specific calling convention", + reason: "this function pointer has Rust-specific calling convention" + .into(), help: Some( "consider using an `extern fn(...) -> ...` \ - function pointer instead", + function pointer instead" + .into(), ), }; } @@ -886,16 +851,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Foreign(..) => FfiSafe, + // While opaque types are checked for earlier, if a projection in a struct field + // normalizes to an opaque type, then it will reach this branch. + ty::Opaque(..) => { + FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None } + } + ty::Param(..) | ty::Infer(..) | ty::Bound(..) - | ty::Error + | ty::Error(_) | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) | ty::Placeholder(..) | ty::Projection(..) - | ty::Opaque(..) | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), } } @@ -925,8 +895,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - use rustc_middle::ty::TypeFoldable; - struct ProhibitOpaqueTypes<'tcx> { ty: Option<Ty<'tcx>>, }; @@ -993,7 +961,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // argument, which after substitution, is `()`, then this branch can be hit. FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return, FfiResult::FfiUnsafe { ty, reason, help } => { - self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); + self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref()); } } } @@ -1056,15 +1024,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { }; let (variants, tag) = match layout.variants { Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - ref discr, + tag_encoding: TagEncoding::Direct, + ref tag, ref variants, .. - } => (variants, discr), + } => (variants, tag), _ => return, }; - let discr_size = tag.value.size(&cx.tcx).bytes(); + let tag_size = tag.value.size(&cx.tcx).bytes(); debug!( "enum `{}` is {} bytes large with layout:\n{:#?}", @@ -1078,8 +1046,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { .iter() .zip(variants) .map(|(variant, variant_layout)| { - // Subtract the size of the enum discriminant. - let bytes = variant_layout.size.bytes().saturating_sub(discr_size); + // Subtract the size of the enum tag. + let bytes = variant_layout.size.bytes().saturating_sub(tag_size); debug!("- variant `{}` is {} bytes large", variant.ident, bytes); bytes diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index b8ebcd6c8a8..0dc007bbfd7 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -452,6 +452,14 @@ impl<'a> CrateLoader<'a> { if dep.is_none() { self.used_extern_options.insert(name); } + if !name.as_str().is_ascii() { + self.sess + .struct_span_err( + span, + &format!("cannot load a crate with a non-ascii name `{}`", name,), + ) + .emit(); + } self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report()) } @@ -698,7 +706,9 @@ impl<'a> CrateLoader<'a> { } fn inject_profiler_runtime(&mut self) { - if (self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled()) + if (self.sess.opts.debugging_opts.instrument_coverage + || self.sess.opts.debugging_opts.profile + || self.sess.opts.cg.profile_generate.enabled()) && !self.sess.opts.debugging_opts.no_profiler_runtime { info!("loading profiler"); diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 0335aa8358c..800f794121a 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -565,6 +565,7 @@ impl MetadataBlob { impl EntryKind { fn def_kind(&self) -> DefKind { match *self { + EntryKind::AnonConst(..) => DefKind::AnonConst, EntryKind::Const(..) => DefKind::Const, EntryKind::AssocConst(..) => DefKind::AssocConst, EntryKind::ImmStatic @@ -1121,7 +1122,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs { match self.kind(id) { - EntryKind::Const(qualif, _) + EntryKind::AnonConst(qualif, _) + | EntryKind::Const(qualif, _) | EntryKind::AssocConst( AssocContainer::ImplDefault | AssocContainer::ImplFinal @@ -1340,7 +1342,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_rendered_const(&self, id: DefIndex) -> String { match self.kind(id) { - EntryKind::Const(_, data) | EntryKind::AssocConst(_, _, data) => data.decode(self).0, + EntryKind::AnonConst(_, data) + | EntryKind::Const(_, data) + | EntryKind::AssocConst(_, _, data) => data.decode(self).0, _ => bug!(), } } diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index d797e6d4a34..31821ea459f 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -1358,7 +1358,7 @@ impl EncodeContext<'tcx> { let const_data = self.encode_rendered_const_for_body(body_id); let qualifs = self.tcx.mir_const_qualif(def_id); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Const(qualifs, const_data)); + record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data)); record!(self.tables.visibility[def_id.to_def_id()] <- ty::Visibility::Public); record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id)); self.encode_item_type(def_id.to_def_id()); diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index ec80a2b6171..381e7ee115e 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -281,6 +281,7 @@ define_tables! { #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] enum EntryKind { + AnonConst(mir::ConstQualifs, Lazy<RenderedConst>), Const(mir::ConstQualifs, Lazy<RenderedConst>), ImmStatic, MutStatic, diff --git a/src/librustc_middle/arena.rs b/src/librustc_middle/arena.rs index f861d63aba0..aaef9871aa5 100644 --- a/src/librustc_middle/arena.rs +++ b/src/librustc_middle/arena.rs @@ -114,6 +114,7 @@ macro_rules! arena_types { // This is used to decode the &'tcx [Span] for InlineAsm's line_spans. [decode] span: rustc_span::Span, rustc_span::Span; + [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>, rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>; ], $tcx); ) } diff --git a/src/librustc_middle/ich/impls_hir.rs b/src/librustc_middle/ich/impls_hir.rs index f668cc99754..78b9167ddd9 100644 --- a/src/librustc_middle/ich/impls_hir.rs +++ b/src/librustc_middle/ich/impls_hir.rs @@ -210,16 +210,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate { } impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate { - type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>); + type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>); fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { let hir::TraitCandidate { def_id, import_ids } = self; - let import_keys = import_ids - .iter() - .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), hir_id.local_id)) - .collect(); - (hcx.def_path_hash(*def_id), import_keys) + ( + hcx.def_path_hash(*def_id), + import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(), + ) } } diff --git a/src/librustc_middle/macros.rs b/src/librustc_middle/macros.rs index 88ddd96eec8..a5482b7bdcf 100644 --- a/src/librustc_middle/macros.rs +++ b/src/librustc_middle/macros.rs @@ -1,16 +1,20 @@ #[macro_export] macro_rules! bug { - () => ( bug!("impossible case reached") ); - ($($message:tt)*) => ({ - $crate::util::bug::bug_fmt(file!(), line!(), format_args!($($message)*)) - }) + () => ( $crate::bug!("impossible case reached") ); + ($msg:expr) => ({ $crate::util::bug::bug_fmt(::std::format_args!($msg)) }); + ($msg:expr,) => ({ $crate::bug!($msg) }); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+)) + }); } #[macro_export] macro_rules! span_bug { - ($span:expr, $($message:tt)*) => ({ - $crate::util::bug::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) - }) + ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) }); + ($span:expr, $msg:expr,) => ({ $crate::span_bug!($span, $msg) }); + ($span:expr, $fmt:expr, $($arg:tt)+) => ({ + $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+)) + }); } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_middle/middle/codegen_fn_attrs.rs b/src/librustc_middle/middle/codegen_fn_attrs.rs index c480944069e..d2749f8529b 100644 --- a/src/librustc_middle/middle/codegen_fn_attrs.rs +++ b/src/librustc_middle/middle/codegen_fn_attrs.rs @@ -1,5 +1,6 @@ use crate::mir::mono::Linkage; use rustc_attr::{InlineAttr, OptimizeAttr}; +use rustc_session::config::SanitizerSet; use rustc_span::symbol::Symbol; #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] @@ -30,6 +31,9 @@ pub struct CodegenFnAttrs { /// The `#[link_section = "..."]` attribute, or what executable section this /// should be placed in. pub link_section: Option<Symbol>, + /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which + /// instrumentation should be disabled inside the annotated function. + pub no_sanitize: SanitizerSet, } bitflags! { @@ -69,20 +73,12 @@ bitflags! { const FFI_RETURNS_TWICE = 1 << 10; /// `#[track_caller]`: allow access to the caller location const TRACK_CALLER = 1 << 11; - /// `#[no_sanitize(address)]`: disables address sanitizer instrumentation - const NO_SANITIZE_ADDRESS = 1 << 12; - /// `#[no_sanitize(memory)]`: disables memory sanitizer instrumentation - const NO_SANITIZE_MEMORY = 1 << 13; - /// `#[no_sanitize(thread)]`: disables thread sanitizer instrumentation - const NO_SANITIZE_THREAD = 1 << 14; - /// All `#[no_sanitize(...)]` attributes. - const NO_SANITIZE_ANY = Self::NO_SANITIZE_ADDRESS.bits | Self::NO_SANITIZE_MEMORY.bits | Self::NO_SANITIZE_THREAD.bits; /// #[ffi_pure]: applies clang's `pure` attribute to a foreign function /// declaration. - const FFI_PURE = 1 << 15; + const FFI_PURE = 1 << 12; /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. - const FFI_CONST = 1 << 16; + const FFI_CONST = 1 << 13; } } @@ -98,6 +94,7 @@ impl CodegenFnAttrs { target_features: vec![], linkage: None, link_section: None, + no_sanitize: SanitizerSet::empty(), } } diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index 1b3ede40f02..abbbbf7fbd6 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -390,8 +390,8 @@ pub enum UndefinedBehaviorInfo<'tcx> { InvalidBool(u8), /// Using a non-character `u32` as character. InvalidChar(u32), - /// An enum discriminant was set to a value which was outside the range of valid values. - InvalidDiscriminant(Scalar), + /// The tag of an enum does not encode an actual discriminant. + InvalidTag(Scalar), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), /// Using a string that is not valid UTF-8, @@ -463,7 +463,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { InvalidChar(c) => { write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c) } - InvalidDiscriminant(val) => write!(f, "enum value has invalid discriminant: {}", val), + InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val), InvalidFunctionPointer(p) => { write!(f, "using {} as function pointer but it does not point to a function", p) } diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 27848684706..3381b95c2a3 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -29,6 +29,7 @@ use rustc_macros::HashStable; use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi; use rustc_target::asm::InlineAsmRegOrRegClass; use std::borrow::Cow; use std::fmt::{self, Debug, Display, Formatter, Write}; @@ -1112,7 +1113,7 @@ pub enum TerminatorKind<'tcx> { Unreachable, /// Drop the `Place`. - Drop { location: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, + Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> }, /// Drop the `Place` and assign the new value over it. This ensures /// that the assignment to `P` occurs *even if* the destructor for @@ -1141,7 +1142,7 @@ pub enum TerminatorKind<'tcx> { /// } /// ``` DropAndReplace { - location: Place<'tcx>, + place: Place<'tcx>, value: Operand<'tcx>, target: BasicBlock, unwind: Option<BasicBlock>, @@ -1607,9 +1608,9 @@ impl<'tcx> TerminatorKind<'tcx> { Abort => write!(fmt, "abort"), Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), Unreachable => write!(fmt, "unreachable"), - Drop { location, .. } => write!(fmt, "drop({:?})", location), - DropAndReplace { location, value, .. } => { - write!(fmt, "replace({:?} <- {:?})", location, value) + Drop { place, .. } => write!(fmt, "drop({:?})", place), + DropAndReplace { place, value, .. } => { + write!(fmt, "replace({:?} <- {:?})", place, value) } Call { func, args, destination, .. } => { if let Some((destination, _)) = destination { @@ -2218,6 +2219,33 @@ impl<'tcx> Operand<'tcx> { }) } + /// Convenience helper to make a literal-like constant from a given scalar value. + /// Since this is used to synthesize MIR, assumes `user_ty` is None. + pub fn const_from_scalar( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + val: Scalar, + span: Span, + ) -> Operand<'tcx> { + debug_assert!({ + let param_env_and_ty = ty::ParamEnv::empty().and(ty); + let type_size = tcx + .layout_of(param_env_and_ty) + .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e)) + .size; + let scalar_size = abi::Size::from_bytes(match val { + Scalar::Raw { size, .. } => size, + _ => panic!("Invalid scalar type {:?}", val), + }); + scalar_size == type_size + }); + Operand::Constant(box Constant { + span, + user_ty: None, + literal: ty::Const::from_scalar(tcx, val, ty), + }) + } + pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs index c889dbc0a44..f1c1b962ab9 100644 --- a/src/librustc_middle/mir/mono.rs +++ b/src/librustc_middle/mir/mono.rs @@ -91,9 +91,9 @@ impl<'tcx> MonoItem<'tcx> { match *self { MonoItem::Fn(ref instance) => { let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); - // If this function isn't inlined or otherwise has explicit - // linkage, then we'll be creating a globally shared version. - if self.explicit_linkage(tcx).is_some() + // If this function isn't inlined or otherwise has an extern + // indicator, then we'll be creating a globally shared version. + if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() || !instance.def.generates_cgu_internal_copy(tcx) || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id) { @@ -102,7 +102,7 @@ impl<'tcx> MonoItem<'tcx> { // At this point we don't have explicit linkage and we're an // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU + // be creating a local copy per CGU. if generate_cgu_internal_copies { return InstantiationMode::LocalCopy; } diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index d82faf3e5fb..1aae97cc2a8 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -244,6 +244,6 @@ pub enum ClosureOutlivesSubject<'tcx> { /// The constituent parts of an ADT or array. #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { - pub variant: VariantIdx, + pub variant: Option<VariantIdx>, pub fields: &'tcx [&'tcx ty::Const<'tcx>], } diff --git a/src/librustc_middle/mir/type_foldable.rs b/src/librustc_middle/mir/type_foldable.rs index 3f5d528d9e7..89f8f10449e 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/src/librustc_middle/mir/type_foldable.rs @@ -27,11 +27,11 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { values: values.clone(), targets: targets.clone(), }, - Drop { ref location, target, unwind } => { - Drop { location: location.fold_with(folder), target, unwind } + Drop { ref place, target, unwind } => { + Drop { place: place.fold_with(folder), target, unwind } } - DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { - location: location.fold_with(folder), + DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace { + place: place.fold_with(folder), value: value.fold_with(folder), target, unwind, @@ -97,9 +97,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { SwitchInt { ref discr, switch_ty, .. } => { discr.visit_with(visitor) || switch_ty.visit_with(visitor) } - Drop { ref location, .. } => location.visit_with(visitor), - DropAndReplace { ref location, ref value, .. } => { - location.visit_with(visitor) || value.visit_with(visitor) + Drop { ref place, .. } => place.visit_with(visitor), + DropAndReplace { ref place, ref value, .. } => { + place.visit_with(visitor) || value.visit_with(visitor) } Yield { ref value, .. } => value.visit_with(visitor), Call { ref func, ref args, ref destination, .. } => { diff --git a/src/librustc_middle/mir/visit.rs b/src/librustc_middle/mir/visit.rs index 5f9fcdca516..2efc5f1dabe 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/src/librustc_middle/mir/visit.rs @@ -108,12 +108,6 @@ macro_rules! make_mir_visitor { self.super_terminator(terminator, location); } - fn visit_terminator_kind(&mut self, - kind: & $($mutability)? TerminatorKind<'tcx>, - location: Location) { - self.super_terminator_kind(kind, location); - } - fn visit_assert_message(&mut self, msg: & $($mutability)? AssertMessage<'tcx>, location: Location) { @@ -417,12 +411,6 @@ macro_rules! make_mir_visitor { let Terminator { source_info, kind } = terminator; self.visit_source_info(source_info); - self.visit_terminator_kind(kind, location); - } - - fn super_terminator_kind(&mut self, - kind: & $($mutability)? TerminatorKind<'tcx>, - source_location: Location) { match kind { TerminatorKind::Goto { .. } | TerminatorKind::Resume | @@ -440,7 +428,7 @@ macro_rules! make_mir_visitor { self.visit_local( & $($mutability)? local, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move), - source_location, + location, ); assert_eq!( @@ -456,34 +444,34 @@ macro_rules! make_mir_visitor { values: _, targets: _ } => { - self.visit_operand(discr, source_location); - self.visit_ty(switch_ty, TyContext::Location(source_location)); + self.visit_operand(discr, location); + self.visit_ty(switch_ty, TyContext::Location(location)); } TerminatorKind::Drop { - location, + place, target: _, unwind: _, } => { self.visit_place( - location, + place, PlaceContext::MutatingUse(MutatingUseContext::Drop), - source_location + location ); } TerminatorKind::DropAndReplace { - location, + place, value, target: _, unwind: _, } => { self.visit_place( - location, + place, PlaceContext::MutatingUse(MutatingUseContext::Drop), - source_location + location ); - self.visit_operand(value, source_location); + self.visit_operand(value, location); } TerminatorKind::Call { @@ -494,15 +482,15 @@ macro_rules! make_mir_visitor { from_hir_call: _, fn_span: _ } => { - self.visit_operand(func, source_location); + self.visit_operand(func, location); for arg in args { - self.visit_operand(arg, source_location); + self.visit_operand(arg, location); } if let Some((destination, _)) = destination { self.visit_place( destination, PlaceContext::MutatingUse(MutatingUseContext::Call), - source_location + location ); } } @@ -514,8 +502,8 @@ macro_rules! make_mir_visitor { target: _, cleanup: _, } => { - self.visit_operand(cond, source_location); - self.visit_assert_message(msg, source_location); + self.visit_operand(cond, location); + self.visit_assert_message(msg, location); } TerminatorKind::Yield { @@ -524,11 +512,11 @@ macro_rules! make_mir_visitor { resume_arg, drop: _, } => { - self.visit_operand(value, source_location); + self.visit_operand(value, location); self.visit_place( resume_arg, PlaceContext::MutatingUse(MutatingUseContext::Yield), - source_location, + location, ); } @@ -543,29 +531,29 @@ macro_rules! make_mir_visitor { match op { InlineAsmOperand::In { value, .. } | InlineAsmOperand::Const { value } => { - self.visit_operand(value, source_location); + self.visit_operand(value, location); } InlineAsmOperand::Out { place, .. } => { if let Some(place) = place { self.visit_place( place, PlaceContext::MutatingUse(MutatingUseContext::Store), - source_location, + location, ); } } InlineAsmOperand::InOut { in_value, out_place, .. } => { - self.visit_operand(in_value, source_location); + self.visit_operand(in_value, location); if let Some(out_place) = out_place { self.visit_place( out_place, PlaceContext::MutatingUse(MutatingUseContext::Store), - source_location, + location, ); } } InlineAsmOperand::SymFn { value } => { - self.visit_constant(value, source_location); + self.visit_constant(value, location); } InlineAsmOperand::SymStatic { def_id: _ } => {} } diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 3b6d54a1bc1..b3751beede2 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -526,7 +526,7 @@ rustc_queries! { } Other { - query used_trait_imports(key: LocalDefId) -> &'tcx DefIdSet { + query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> { desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) } cache_on_disk_if { true } } diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index 17ea84836bf..f650240a41c 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -393,23 +393,25 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>; /// ``` /// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1 /// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2 -/// impl Clone for int { ... } // Impl_3 +/// impl Clone for i32 { ... } // Impl_3 /// -/// fn foo<T:Clone>(concrete: Option<Box<int>>, -/// param: T, -/// mixed: Option<T>) { +/// fn foo<T: Clone>(concrete: Option<Box<i32>>, param: T, mixed: Option<T>) { +/// // Case A: Vtable points at a specific impl. Only possible when +/// // type is concretely known. If the impl itself has bounded +/// // type parameters, Vtable will carry resolutions for those as well: +/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])]) /// -/// // Case A: ImplSource points at a specific impl. Only possible when -/// // type is concretely known. If the impl itself has bounded -/// // type parameters, ImplSource will carry resolutions for those as well: -/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])]) +/// // Case A: ImplSource points at a specific impl. Only possible when +/// // type is concretely known. If the impl itself has bounded +/// // type parameters, ImplSource will carry resolutions for those as well: +/// concrete.clone(); // ImplSource(Impl_1, [ImplSource(Impl_2, [ImplSource(Impl_3)])]) /// -/// // Case B: ImplSource must be provided by caller. This applies when -/// // type is a type parameter. -/// param.clone(); // ImplSourceParam +/// // Case B: ImplSource must be provided by caller. This applies when +/// // type is a type parameter. +/// param.clone(); // ImplSourceParam /// -/// // Case C: A mix of cases A and B. -/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) +/// // Case C: A mix of cases A and B. +/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) /// } /// ``` /// diff --git a/src/librustc_middle/traits/query.rs b/src/librustc_middle/traits/query.rs index e030125b5b1..69696ac9e93 100644 --- a/src/librustc_middle/traits/query.rs +++ b/src/librustc_middle/traits/query.rs @@ -221,7 +221,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Ref(..) | ty::Str | ty::Foreign(..) - | ty::Error => true, + | ty::Error(_) => true, // [T; N] and [T] have same properties as T. ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), diff --git a/src/librustc_middle/ty/_match.rs b/src/librustc_middle/ty/_match.rs index 02abe868f39..db9229ae3d2 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/src/librustc_middle/ty/_match.rs @@ -79,7 +79,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { Err(TypeError::Sorts(relate::expected_found(self, &a, &b))) } - (&ty::Error, _) | (_, &ty::Error) => Ok(self.tcx().types.err), + (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()), _ => relate::super_relate_tys(self, a, b), } diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index d5be3508d2d..6380f8be98d 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -35,7 +35,7 @@ use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_hir::lang_items::{self, PanicLocationLangItem}; use rustc_hir::{HirId, ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet, Node, TraitCandidate}; @@ -46,7 +46,7 @@ use rustc_session::lint::{Level, Lint}; use rustc_session::Session; use rustc_span::source_map::MultiSpan; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; @@ -143,9 +143,9 @@ pub struct CommonTypes<'tcx> { pub u128: Ty<'tcx>, pub f32: Ty<'tcx>, pub f64: Ty<'tcx>, + pub str_: Ty<'tcx>, pub never: Ty<'tcx>, pub self_param: Ty<'tcx>, - pub err: Ty<'tcx>, /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. @@ -189,8 +189,7 @@ fn validate_hir_id_for_typeck_tables( if hir_id.owner != hir_owner { ty::tls::with(|tcx| { bug!( - "node {} with HirId::owner {:?} cannot be placed in \ - TypeckTables with hir_owner {:?}", + "node {} with HirId::owner {:?} cannot be placed in TypeckTables with hir_owner {:?}", tcx.hir().node_to_string(hir_id), hir_id.owner, hir_owner @@ -392,7 +391,7 @@ pub struct TypeckTables<'tcx> { /// This is used for warning unused imports. During type /// checking, this `Lrc` should not be cloned: it must have a ref-count /// of 1 so that we can insert things into the set mutably. - pub used_trait_imports: Lrc<DefIdSet>, + pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>, /// If any errors occurred while type-checking this body, /// this field will be set to `Some(ErrorReported)`. @@ -804,7 +803,6 @@ impl<'tcx> CommonTypes<'tcx> { bool: mk(Bool), char: mk(Char), never: mk(Never), - err: mk(Error), isize: mk(Int(ast::IntTy::Isize)), i8: mk(Int(ast::IntTy::I8)), i16: mk(Int(ast::IntTy::I16)), @@ -819,6 +817,7 @@ impl<'tcx> CommonTypes<'tcx> { u128: mk(Uint(ast::UintTy::U128)), f32: mk(Float(ast::FloatTy::F32)), f64: mk(Float(ast::FloatTy::F64)), + str_: mk(Str), self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })), trait_object_dummy_self: mk(Infer(ty::FreshTy(0))), @@ -1143,6 +1142,31 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used. + #[track_caller] + pub fn ty_error(self) -> Ty<'tcx> { + self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported") + } + + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to + /// ensure it gets used. + #[track_caller] + pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> { + self.sess.delay_span_bug(span, msg); + self.mk_ty(Error(super::sty::DelaySpanBugEmitted(()))) + } + + /// Like `err` but for constants. + #[track_caller] + pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> { + self.sess + .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported."); + self.mk_const(ty::Const { + val: ty::ConstKind::Error(super::sty::DelaySpanBugEmitted(())), + ty, + }) + } + pub fn consider_optimizing<T: Fn() -> String>(&self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) @@ -1383,7 +1407,10 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn return_type_impl_or_dyn_trait(&self, scope_def_id: DefId) -> Option<(Span, bool)> { + pub fn return_type_impl_or_dyn_trait( + &self, + scope_def_id: DefId, + ) -> Option<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().as_local_hir_id(scope_def_id.expect_local()); let hir_output = match self.hir().get(hir_id) { Node::Item(hir::Item { @@ -1429,15 +1456,17 @@ impl<'tcx> TyCtxt<'tcx> { let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); - Some((fn_decl.output.span(), false)) + if let hir::FnRetTy::Return(ty) = fn_decl.output { + return Some(ty); + } } else { let mut v = TraitObjectVisitor(vec![]); rustc_hir::intravisit::walk_ty(&mut v, hir_output); if v.0.len() == 1 { - return Some((v.0[0], true)); + return Some(v.0[0]); } - None } + None } _ => None, } @@ -1846,7 +1875,7 @@ macro_rules! sty_debug_print { let variant = match t.kind { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, - ty::Error => /* unimportant */ continue, + ty::Error(_) => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); @@ -2081,6 +2110,13 @@ impl<'tcx> TyCtxt<'tcx> { }) } + /// Same a `self.mk_region(kind)`, but avoids accessing the interners if + /// `*r == kind`. + #[inline] + pub fn reuse_or_mk_region(self, r: Region<'tcx>, kind: RegionKind) -> Region<'tcx> { + if *r == kind { r } else { self.mk_region(kind) } + } + #[allow(rustc::usage_of_ty_tykind)] #[inline] pub fn mk_ty(&self, st: TyKind<'tcx>) -> Ty<'tcx> { @@ -2123,13 +2159,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_str(self) -> Ty<'tcx> { - self.mk_ty(Str) - } - - #[inline] pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.lifetimes.re_static, self.mk_str()) + self.mk_imm_ref(self.lifetimes.re_static, self.types.str_) } #[inline] diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 2e9aa724ac5..a2812e117ed 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -236,21 +236,24 @@ pub fn suggest_constraining_type_param( } } -pub struct TraitObjectVisitor(pub Vec<rustc_span::Span>); -impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor { +pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>); +impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { type Map = rustc_hir::intravisit::ErasedMap<'v>; fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> { hir::intravisit::NestedVisitorMap::None } - fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { if let hir::TyKind::TraitObject( _, - hir::Lifetime { name: hir::LifetimeName::ImplicitObjectLifetimeDefault, .. }, + hir::Lifetime { + name: hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static, + .. + }, ) = ty.kind { - self.0.push(ty.span); + self.0.push(ty); } } } diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index be3bf748225..6113359ca93 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -286,14 +286,14 @@ impl<'tcx> ty::TyS<'tcx> { ty::Projection(_) => "associated type".into(), ty::Param(p) => format!("type parameter `{}`", p).into(), ty::Opaque(..) => "opaque type".into(), - ty::Error => "type error".into(), + ty::Error(_) => "type error".into(), } } pub fn prefix_string(&self) -> Cow<'static, str> { match self.kind { ty::Infer(_) - | ty::Error + | ty::Error(_) | ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_middle/ty/fast_reject.rs b/src/librustc_middle/ty/fast_reject.rs index 16d8e379407..b0fb179b18b 100644 --- a/src/librustc_middle/ty/fast_reject.rs +++ b/src/librustc_middle/ty/fast_reject.rs @@ -104,7 +104,7 @@ pub fn simplify_type( } ty::Opaque(def_id, _) => Some(OpaqueSimplifiedType(def_id)), ty::Foreign(def_id) => Some(ForeignSimplifiedType(def_id)), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, } } diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index edcb69c5e8c..bee42be8a53 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -70,7 +70,7 @@ impl FlagComputation { | &ty::Str | &ty::Foreign(..) => {} - &ty::Error => self.add_flags(TypeFlags::HAS_ERROR), + &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), &ty::Param(_) => { self.add_flags(TypeFlags::HAS_TY_PARAM); @@ -227,7 +227,7 @@ impl FlagComputation { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } ty::ConstKind::Value(_) => {} - ty::ConstKind::Error => self.add_flags(TypeFlags::HAS_ERROR), + ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 248dd00ef47..24dbf7b8c46 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -87,6 +87,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_param_types_or_consts(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) } + fn has_infer_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_INFER) + } fn has_infer_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER) } diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 1ce079821a2..d628d6783d5 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -9,6 +9,11 @@ use rustc_macros::HashStable; use std::fmt; +/// A monomorphized `InstanceDef`. +/// +/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type +/// simply couples a potentially generic `InstanceDef` with some substs, and codegen and const eval +/// will do all required substitution as they run. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] #[derive(HashStable, Lift)] pub struct Instance<'tcx> { @@ -18,10 +23,26 @@ pub struct Instance<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, HashStable)] pub enum InstanceDef<'tcx> { + /// A user-defined callable item. + /// + /// This includes: + /// - `fn` items + /// - closures + /// - generators Item(DefId), + + /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI). + /// + /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR. + /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the + /// caller. Intrinsic(DefId), - /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`. + /// `<T as Trait>::method` where `method` receives unsizeable `self: Self` (part of the + /// `unsized_locals` feature). + /// + /// The generated shim will take `Self` via `*mut Self` - conceptually this is `&owned Self` - + /// and dereference the argument to call the original function. VtableShim(DefId), /// `fn()` pointer where the function itself cannot be turned into a pointer. @@ -37,7 +58,8 @@ pub enum InstanceDef<'tcx> { /// (the definition of the function itself). ReifyShim(DefId), - /// `<fn() as FnTrait>::call_*` + /// `<fn() as FnTrait>::call_*` (generated `FnTrait` implementation for `fn()` pointers). + /// /// `DefId` is `FnTrait::call_*`. /// /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution @@ -45,19 +67,22 @@ pub enum InstanceDef<'tcx> { // FIXME(#69925) support polymorphic MIR shim bodies properly instead. FnPtrShim(DefId, Ty<'tcx>), - /// `<dyn Trait as Trait>::fn`, "direct calls" of which are implicitly - /// codegen'd as virtual calls. + /// Dynamic dispatch to `<dyn Trait as Trait>::fn`. /// - /// NB: if this is reified to a `fn` pointer, a `ReifyShim` is used - /// (see `ReifyShim` above for more details on that). + /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be + /// codegen'd as virtual calls through the vtable. + /// + /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more + /// details on that). Virtual(DefId, usize), - /// `<[mut closure] as FnOnce>::call_once` - ClosureOnceShim { - call_once: DefId, - }, + /// `<[FnMut closure] as FnOnce>::call_once`. + /// + /// The `DefId` is the ID of the `call_once` method in `FnOnce`. + ClosureOnceShim { call_once: DefId }, /// `core::ptr::drop_in_place::<T>`. + /// /// The `DefId` is for `core::ptr::drop_in_place`. /// The `Option<Ty<'tcx>>` is either `Some(T)`, or `None` for empty drop /// glue. @@ -67,7 +92,12 @@ pub enum InstanceDef<'tcx> { // FIXME(#69925) support polymorphic MIR shim bodies properly instead. DropGlue(DefId, Option<Ty<'tcx>>), - ///`<T as Clone>::clone` shim. + /// Compiler-generated `<T as Clone>::clone` implementation. + /// + /// For all types that automatically implement `Copy`, a trivial `Clone` impl is provided too. + /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`. + /// + /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. /// /// NB: the type must currently be monomorphic to avoid double substitution /// problems with the MIR shim bodies. `Instance::resolve` enforces this. diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index f5bca90c2bd..68af22569e3 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -974,13 +974,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { return Ok(tcx.intern_layout(Layout { variants: Variants::Multiple { - discr: niche_scalar, - discr_kind: DiscriminantKind::Niche { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { dataful_variant: i, niche_variants, niche_start, }, - discr_index: 0, + tag_field: 0, variants: st, }, fields: FieldsShape::Arbitrary { @@ -1216,9 +1216,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(Layout { variants: Variants::Multiple { - discr: tag, - discr_kind: DiscriminantKind::Tag, - discr_index: 0, + tag, + tag_encoding: TagEncoding::Direct, + tag_field: 0, variants: layout_variants, }, fields: FieldsShape::Arbitrary { @@ -1245,7 +1245,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error => { + ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) @@ -1399,15 +1399,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Build a prefix layout, including "promoting" all ineligible // locals as part of the prefix. We compute the layout of all of // these fields at once to get optimal packing. - let discr_index = substs.as_generator().prefix_tys().count(); + let tag_index = substs.as_generator().prefix_tys().count(); // `info.variant_fields` already accounts for the reserved variants, so no need to add them. let max_discr = (info.variant_fields.len() - 1) as u128; let discr_int = Integer::fit_unsigned(max_discr); let discr_int_ty = discr_int.to_ty(tcx, false); - let discr = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr }; - let discr_layout = self.tcx.intern_layout(Layout::scalar(self, discr.clone())); - let discr_layout = TyAndLayout { ty: discr_int_ty, layout: discr_layout }; + let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr }; + let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone())); + let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout }; let promoted_layouts = ineligible_locals .iter() @@ -1418,7 +1418,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { .as_generator() .prefix_tys() .map(|ty| self.layout_of(ty)) - .chain(iter::once(Ok(discr_layout))) + .chain(iter::once(Ok(tag_layout))) .chain(promoted_layouts) .collect::<Result<Vec<_>, _>>()?; let prefix = self.univariant_uninterned( @@ -1441,7 +1441,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. - let b_start = (discr_index + 1) as u32; + let b_start = (tag_index + 1) as u32; let offsets_b = offsets.split_off(b_start as usize); let offsets_a = offsets; @@ -1558,9 +1558,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let layout = tcx.intern_layout(Layout { variants: Variants::Multiple { - discr, - discr_kind: DiscriminantKind::Tag, - discr_index, + tag: tag, + tag_encoding: TagEncoding::Direct, + tag_field: tag_index, variants, }, fields: outer_fields, @@ -1680,7 +1680,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } - Variants::Multiple { ref discr, ref discr_kind, .. } => { + Variants::Multiple { ref tag, ref tag_encoding, .. } => { debug!( "print-type-size `{:#?}` adt general variants def {}", layout.ty, @@ -1702,8 +1702,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { record( adt_kind.into(), adt_packed, - match discr_kind { - DiscriminantKind::Tag => Some(discr.value.size(self)), + match tag_encoding { + TagEncoding::Direct => Some(tag.value.size(self)), _ => None, }, variant_infos, @@ -2001,6 +2001,8 @@ where } let fields = match this.ty.kind { + ty::Adt(def, _) if def.variants.is_empty() => + bug!("for_variant called on zero-variant enum"), ty::Adt(def, _) => def.variants[variant_index].fields.len(), _ => bug!(), }; @@ -2028,11 +2030,11 @@ where fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { let tcx = cx.tcx(); - let discr_layout = |discr: &Scalar| -> C::TyAndLayout { - let layout = Layout::scalar(cx, discr.clone()); + let tag_layout = |tag: &Scalar| -> C::TyAndLayout { + let layout = Layout::scalar(cx, tag.clone()); MaybeResult::from(Ok(TyAndLayout { layout: tcx.intern_layout(layout), - ty: discr.value.to_ty(tcx), + ty: tag.value.to_ty(tcx), })) }; @@ -2109,9 +2111,9 @@ where .unwrap() .nth(i) .unwrap(), - Variants::Multiple { ref discr, discr_index, .. } => { - if i == discr_index { - return discr_layout(discr); + Variants::Multiple { ref tag, tag_field, .. } => { + if i == tag_field { + return tag_layout(tag); } substs.as_generator().prefix_tys().nth(i).unwrap() } @@ -2128,9 +2130,9 @@ where Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), // Discriminant field for enums (where applicable). - Variants::Multiple { ref discr, .. } => { + Variants::Multiple { ref tag, .. } => { assert_eq!(i, 0); - return discr_layout(discr); + return tag_layout(tag); } } } @@ -2141,7 +2143,7 @@ where | ty::Opaque(..) | ty::Param(_) | ty::Infer(_) - | ty::Error => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), + | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), }) } @@ -2207,10 +2209,10 @@ where // using more niches than just null (e.g., the first page of // the address space, or unaligned pointers). Variants::Multiple { - discr_kind: DiscriminantKind::Niche { dataful_variant, .. }, - discr_index, + tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_field, .. - } if this.fields.offset(discr_index) == offset => { + } if this.fields.offset(tag_field) == offset => { Some(this.for_variant(cx, dataful_variant)) } _ => Some(this), diff --git a/src/librustc_middle/ty/list.rs b/src/librustc_middle/ty/list.rs index 161783bb370..92d6dbb5f90 100644 --- a/src/librustc_middle/ty/list.rs +++ b/src/librustc_middle/ty/list.rs @@ -2,7 +2,8 @@ use crate::arena::Arena; use rustc_serialize::{Encodable, Encoder}; -use std::cmp::{self, Ordering}; +use std::alloc::Layout; +use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter; @@ -43,19 +44,11 @@ impl<T: Copy> List<T> { assert!(mem::size_of::<T>() != 0); assert!(!slice.is_empty()); - // Align up the size of the len (usize) field - let align = mem::align_of::<T>(); - let align_mask = align - 1; - let offset = mem::size_of::<usize>(); - let offset = (offset + align_mask) & !align_mask; - - let size = offset + slice.len() * mem::size_of::<T>(); - - let mem = arena - .dropless - .alloc_raw(size, cmp::max(mem::align_of::<T>(), mem::align_of::<usize>())); + let (layout, _offset) = + Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap(); + let mem = arena.dropless.alloc_raw(layout); unsafe { - let result = &mut *(mem.as_mut_ptr() as *mut List<T>); + let result = &mut *(mem as *mut List<T>); // Write the length result.len = slice.len(); diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 93ef7317199..ca0a1ac71c6 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -121,7 +121,7 @@ pub struct ResolverOutputs { pub definitions: rustc_hir::definitions::Definitions, pub cstore: Box<CrateStoreDyn>, pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>, - pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate<hir::HirId>>>, + pub trait_map: FxHashMap<hir::HirId, Vec<hir::TraitCandidate>>, pub maybe_unused_trait_imports: FxHashSet<LocalDefId>, pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, pub export_map: ExportMap<LocalDefId>, @@ -1807,6 +1807,19 @@ impl<'tcx> VariantDef { pub fn is_field_list_non_exhaustive(&self) -> bool { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } + + /// `repr(transparent)` structs can have a single non-ZST field, this function returns that + /// field. + pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> { + for field in &self.fields { + let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id)); + if !field_ty.is_zst(tcx, self.def_id) { + return Some(field); + } + } + + None + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] @@ -2339,6 +2352,7 @@ impl<'tcx> AdtDef { /// Alternatively, if there is no explicit discriminant, returns the /// inferred discriminant directly. pub fn discriminant_def_for_variant(&self, variant_index: VariantIdx) -> (Option<DefId>, u32) { + assert!(!self.variants.is_empty()); let mut explicit_index = variant_index.as_u32(); let expr_did; loop { @@ -2376,29 +2390,6 @@ impl<'tcx> AdtDef { pub fn sized_constraint(&self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] { tcx.adt_sized_constraint(self.did).0 } - - /// `repr(transparent)` structs can have a single non-ZST field, this function returns that - /// field. - pub fn transparent_newtype_field( - &self, - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ) -> Option<&FieldDef> { - assert!(self.is_struct() && self.repr.transparent()); - - for field in &self.non_enum_variant().fields { - let field_ty = tcx.normalize_erasing_regions( - param_env, - field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.did)), - ); - - if !field_ty.is_zst(tcx, self.did) { - return Some(field); - } - } - - None - } } impl<'tcx> FieldDef { diff --git a/src/librustc_middle/ty/outlives.rs b/src/librustc_middle/ty/outlives.rs index 1da042e1617..1a8693b8df7 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/src/librustc_middle/ty/outlives.rs @@ -171,7 +171,7 @@ fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Compo ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) ty::Placeholder(..) | ty::Bound(..) | - ty::Error => { + ty::Error(_) => { // (*) Function pointers and trait objects are both binders. // In the RFC, this means we would add the bound regions to // the "bound regions list". In our representation, no such diff --git a/src/librustc_middle/ty/print/mod.rs b/src/librustc_middle/ty/print/mod.rs index 69b36980bd7..6c8f23c139f 100644 --- a/src/librustc_middle/ty/print/mod.rs +++ b/src/librustc_middle/ty/print/mod.rs @@ -298,7 +298,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { | ty::Opaque(..) | ty::Infer(_) | ty::Bound(..) - | ty::Error + | ty::Error(_) | ty::GeneratorWitness(..) | ty::Never | ty::Float(_) => None, diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs index 7d9943ab079..67b6433b611 100644 --- a/src/librustc_middle/ty/print/obsolete.rs +++ b/src/librustc_middle/ty/print/obsolete.rs @@ -144,7 +144,7 @@ impl DefPathBasedNames<'tcx> { let substs = substs.truncate_to(self.tcx, generics); self.push_generic_params(substs, iter::empty(), output, debug); } - ty::Error + ty::Error(_) | ty::Bound(..) | ty::Infer(_) | ty::Placeholder(..) diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index d782dd07a65..1a08639a533 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -518,7 +518,7 @@ pub trait PrettyPrinter<'tcx>: p!(write("{}", infer_ty)) } } - ty::Error => p!(write("[type error]")), + ty::Error(_) => p!(write("[type error]")), ty::Param(ref param_ty) => p!(write("{}", param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, @@ -919,7 +919,7 @@ pub trait PrettyPrinter<'tcx>: self.pretty_print_bound_var(debruijn, bound_var)? } ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), - ty::ConstKind::Error => p!(write("[const error]")), + ty::ConstKind::Error(_) => p!(write("[const error]")), }; Ok(self) } @@ -1177,8 +1177,13 @@ pub trait PrettyPrinter<'tcx>: } p!(write(")")); } + ty::Adt(def, substs) if def.variants.is_empty() => { + p!(print_value_path(def.did, substs)); + } ty::Adt(def, substs) => { - let variant_def = &def.variants[contents.variant]; + let variant_id = + contents.variant.expect("destructed const of adt without variant id"); + let variant_def = &def.variants[variant_id]; p!(print_value_path(variant_def.def_id, substs)); match variant_def.ctor_kind { diff --git a/src/librustc_middle/ty/query/values.rs b/src/librustc_middle/ty/query/values.rs index b1f76ff6a03..0a0ff101b52 100644 --- a/src/librustc_middle/ty/query/values.rs +++ b/src/librustc_middle/ty/query/values.rs @@ -17,7 +17,7 @@ impl<'tcx> Value<'tcx> for &'_ TyS<'_> { fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. - unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.types.err) } + unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) } } } @@ -33,7 +33,7 @@ impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> { // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::<AdtSizedConstraint<'tcx>, AdtSizedConstraint<'_>>( - AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])), + AdtSizedConstraint(tcx.intern_type_list(&[tcx.ty_error()])), ) } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index cddd7081ca3..14cddd11c43 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -354,7 +354,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>( bug!("bound types encountered in super_relate_tys") } - (&ty::Error, _) | (_, &ty::Error) => Ok(tcx.types.err), + (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(tcx.ty_error()), (&ty::Never, _) | (&ty::Char, _) @@ -524,7 +524,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>( bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) } - (ty::ConstKind::Error, _) | (_, ty::ConstKind::Error) => Ok(ty::ConstKind::Error), + (ty::ConstKind::Error(d), _) | (_, ty::ConstKind::Error(d)) => Ok(ty::ConstKind::Error(d)), (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { return Ok(a); diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index f6f5dfd6516..f04d31601ea 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -911,7 +911,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Int(_) | ty::Uint(_) | ty::Float(_) - | ty::Error + | ty::Error(_) | ty::Infer(_) | ty::Param(..) | ty::Bound(..) @@ -952,7 +952,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Int(_) | ty::Uint(_) | ty::Float(_) - | ty::Error + | ty::Error(_) | ty::Infer(_) | ty::Bound(..) | ty::Placeholder(..) @@ -1051,7 +1051,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) - | ty::ConstKind::Error => *self, + | ty::ConstKind::Error(_) => *self, } } @@ -1063,7 +1063,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> { ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Error => false, + | ty::ConstKind::Error(_) => false, } } } diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index fad96aa86cc..b0addcb2bb6 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -203,9 +203,15 @@ pub enum TyKind<'tcx> { /// A placeholder for a type which could not be computed; this is /// propagated to avoid useless error messages. - Error, + Error(DelaySpanBugEmitted), } +/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` +/// except through `tcx.err*()`. +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(RustcEncodable, RustcDecodable, HashStable)] +pub struct DelaySpanBugEmitted(pub(super) ()); + // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] static_assert_size!(TyKind<'_>, 24); @@ -1984,7 +1990,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn has_concrete_skeleton(&self) -> bool { match self.kind { - Param(_) | Infer(_) | Error => false, + Param(_) | Infer(_) | Error(_) => false, _ => true, } } @@ -2016,7 +2022,7 @@ impl<'tcx> TyS<'tcx> { match self.kind { FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs), FnPtr(f) => f, - Error => { + Error(_) => { // ignore errors (#54954) ty::Binder::dummy(FnSig::fake()) } @@ -2093,6 +2099,9 @@ impl<'tcx> TyS<'tcx> { variant_index: VariantIdx, ) -> Option<Discr<'tcx>> { match self.kind { + TyKind::Adt(adt, _) if adt.variants.is_empty() => { + bug!("discriminant_for_variant called on zero variant enum"); + } TyKind::Adt(adt, _) if adt.is_enum() => { Some(adt.discriminant_for_variant(tcx, variant_index)) } @@ -2140,7 +2149,7 @@ impl<'tcx> TyS<'tcx> { // closure type is not yet known Bound(..) | Infer(_) => None, - Error => Some(ty::ClosureKind::Fn), + Error(_) => Some(ty::ClosureKind::Fn), _ => bug!("cannot convert type `{:?}` to a closure kind", self), } @@ -2167,7 +2176,7 @@ impl<'tcx> TyS<'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never - | ty::Error => true, + | ty::Error(_) => true, ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, @@ -2372,9 +2381,7 @@ impl<'tcx> Const<'tcx> { // can leak through `val` into the const we return. Ok(val) => Const::from_value(tcx, val, self.ty), Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self, - Err(ErrorHandled::Reported(ErrorReported)) => { - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: self.ty }) - } + Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty), } } else { self @@ -2434,7 +2441,7 @@ pub enum ConstKind<'tcx> { /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. - Error, + Error(DelaySpanBugEmitted), } #[cfg(target_arch = "x86_64")] diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index 1529f1173b3..3b4254a18ea 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -599,12 +599,12 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { /// /// ``` /// type Func<A> = fn(A); - /// type MetaFunc = for<'a> fn(Func<&'a int>) + /// type MetaFunc = for<'a> fn(Func<&'a i32>) /// ``` /// /// The type `MetaFunc`, when fully expanded, will be /// - /// for<'a> fn(fn(&'a int)) + /// for<'a> fn(fn(&'a i32)) /// ^~ ^~ ^~~ /// | | | /// | | DebruijnIndex of 2 @@ -613,7 +613,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the - /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a + /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a /// De Bruijn index of 1. It's only during the substitution that we can see we must increase the /// depth by 1 to account for the binder that we passed through. /// @@ -621,18 +621,18 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { /// /// ``` /// type FuncTuple<A> = (A,fn(A)); - /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>) + /// type MetaFuncTuple = for<'a> fn(FuncTuple<&'a i32>) /// ``` /// /// Here the final type will be: /// - /// for<'a> fn((&'a int, fn(&'a int))) + /// for<'a> fn((&'a i32, fn(&'a i32))) /// ^~~ ^~~ /// | | /// DebruijnIndex of 1 | /// DebruijnIndex of 2 /// - /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the + /// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the /// first case we do not increase the De Bruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. fn shift_vars_through_binders<T: TypeFoldable<'tcx>>(&self, val: T) -> T { diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs index ff284b709c2..47110be53b2 100644 --- a/src/librustc_middle/ty/util.rs +++ b/src/librustc_middle/ty/util.rs @@ -176,7 +176,7 @@ impl<'tcx> TyCtxt<'tcx> { if let ty::Adt(def, substs) = ty.kind { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error = field_ty.kind { + if let Error(_) = field_ty.kind { return true; } } @@ -731,7 +731,7 @@ impl<'tcx> ty::TyS<'tcx> { | ty::Ref(..) | ty::RawPtr(_) | ty::FnDef(..) - | ty::Error + | ty::Error(_) | ty::FnPtr(_) => true, ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze), ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), @@ -826,7 +826,7 @@ impl<'tcx> ty::TyS<'tcx> { // called for known, fully-monomorphized types. Projection(_) | Opaque(..) | Param(_) | Bound(..) | Placeholder(_) | Infer(_) => false, - Foreign(_) | GeneratorWitness(..) | Error => false, + Foreign(_) | GeneratorWitness(..) | Error(_) => false, } } @@ -1109,7 +1109,7 @@ pub fn needs_drop_components( // Foreign types can never have destructors. ty::Foreign(..) => Ok(SmallVec::new()), - ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop), + ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop), ty::Slice(ty) => needs_drop_components(ty, target_layout), ty::Array(elem_ty, size) => { diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs index bf988a43026..633d4fda8a4 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/src/librustc_middle/ty/walk.rs @@ -22,13 +22,13 @@ impl<'tcx> TypeWalker<'tcx> { /// Skips the subtree corresponding to the last type /// returned by `next()`. /// - /// Example: Imagine you are walking `Foo<Bar<int>, usize>`. + /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`. /// /// ``` /// let mut iter: TypeWalker = ...; /// iter.next(); // yields Foo - /// iter.next(); // yields Bar<int> - /// iter.skip_current_subtree(); // skips int + /// iter.next(); // yields Bar<i32> + /// iter.skip_current_subtree(); // skips i32 /// iter.next(); // yields usize /// ``` pub fn skip_current_subtree(&mut self) { @@ -108,7 +108,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Infer(_) | ty::Param(_) | ty::Never - | ty::Error + | ty::Error(_) | ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => {} @@ -171,7 +171,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Value(_) - | ty::ConstKind::Error => {} + | ty::ConstKind::Error(_) => {} ty::ConstKind::Unevaluated(_, substs, _) => { stack.extend(substs.iter().rev()); diff --git a/src/librustc_middle/util/bug.rs b/src/librustc_middle/util/bug.rs index 54cd8a29f94..9c3a97d8332 100644 --- a/src/librustc_middle/util/bug.rs +++ b/src/librustc_middle/util/bug.rs @@ -3,34 +3,31 @@ use crate::ty::{tls, TyCtxt}; use rustc_span::{MultiSpan, Span}; use std::fmt; +use std::panic::Location; #[cold] #[inline(never)] -pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments<'_>) -> ! { +#[track_caller] +pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! { // this wrapper mostly exists so I don't have to write a fully // qualified path of None::<Span> inside the bug!() macro definition - opt_span_bug_fmt(file, line, None::<Span>, args); + opt_span_bug_fmt(None::<Span>, args, Location::caller()); } #[cold] #[inline(never)] -pub fn span_bug_fmt<S: Into<MultiSpan>>( - file: &'static str, - line: u32, - span: S, - args: fmt::Arguments<'_>, -) -> ! { - opt_span_bug_fmt(file, line, Some(span), args); +#[track_caller] +pub fn span_bug_fmt<S: Into<MultiSpan>>(span: S, args: fmt::Arguments<'_>) -> ! { + opt_span_bug_fmt(Some(span), args, Location::caller()); } fn opt_span_bug_fmt<S: Into<MultiSpan>>( - file: &'static str, - line: u32, span: Option<S>, args: fmt::Arguments<'_>, + location: &Location<'_>, ) -> ! { tls::with_opt(move |tcx| { - let msg = format!("{}:{}: {}", file, line, args); + let msg = format!("{}: {}", location, args); match (tcx, span) { (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg), (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg), diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/src/librustc_mir/borrow_check/invalidation.rs index 17fa641ae6c..fd8f17718e7 100644 --- a/src/librustc_mir/borrow_check/invalidation.rs +++ b/src/librustc_mir/borrow_check/invalidation.rs @@ -2,7 +2,7 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue}; use rustc_middle::mir::{BorrowKind, Mutability, Operand}; -use rustc_middle::mir::{InlineAsmOperand, TerminatorKind}; +use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; use rustc_middle::ty::TyCtxt; @@ -112,14 +112,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.super_statement(statement, location); } - fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { self.check_activations(location); - match kind { + match &terminator.kind { TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { self.consume_operand(location, discr); } - TerminatorKind::Drop { location: drop_place, target: _, unwind: _ } => { + TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { self.access_place( location, *drop_place, @@ -128,7 +128,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { ); } TerminatorKind::DropAndReplace { - location: drop_place, + place: drop_place, value: ref new_value, target: _, unwind: _, @@ -222,7 +222,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { } } - self.super_terminator_kind(kind, location); + self.super_terminator(terminator, location); } } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index d099f48adc5..83691d439eb 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -663,7 +663,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { self.consume_operand(loc, (discr, span), flow_state); } - TerminatorKind::Drop { location: ref drop_place, target: _, unwind: _ } => { + TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => { let tcx = self.infcx.tcx; // Compute the type with accurate region information. @@ -692,7 +692,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc ); } TerminatorKind::DropAndReplace { - location: drop_place, + place: drop_place, value: ref new_value, target: _, unwind: _, diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 5707127340d..beee3181256 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -264,7 +264,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> { .tcx .sess .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty)); - (self.infcx.tcx.types.err, None) + (self.infcx.tcx.ty_error(), None) }); let constraints2 = self.add_implied_bounds(ty); normalized_inputs_and_output.push(ty); diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index 7cf4fdfcf3c..0e35cafb9f3 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -498,7 +498,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { if place_ty.variant_index.is_none() { if place_ty.ty.references_error() { assert!(self.errors_reported); - return PlaceTy::from_ty(self.tcx().types.err); + return PlaceTy::from_ty(self.tcx().ty_error()); } } place_ty = self.sanitize_projection(place_ty, elem, place, location) @@ -725,7 +725,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { fn error(&mut self) -> Ty<'tcx> { self.errors_reported = true; - self.tcx().types.err + self.tcx().ty_error() } fn field_ty( @@ -1558,8 +1558,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // no checks needed for these } - TerminatorKind::DropAndReplace { ref location, ref value, target: _, unwind: _ } => { - let place_ty = location.ty(body, tcx).ty; + TerminatorKind::DropAndReplace { ref place, ref value, target: _, unwind: _ } => { + let place_ty = place.ty(body, tcx).ty; let rv_ty = value.ty(body, tcx); let locations = term_location.to_locations(); diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs index 2da72f3bcc5..e027056842d 100644 --- a/src/librustc_mir/borrow_check/used_muts.rs +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -1,5 +1,7 @@ use rustc_middle::mir::visit::{PlaceContext, Visitor}; -use rustc_middle::mir::{Local, Location, Place, Statement, StatementKind, TerminatorKind}; +use rustc_middle::mir::{ + Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind, +}; use rustc_data_structures::fx::FxHashSet; @@ -62,20 +64,22 @@ impl GatherUsedMutsVisitor<'_, '_, '_> { } impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tcx> { - fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, _location: Location) { - debug!("visit_terminator_kind: kind={:?}", kind); - match &kind { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + debug!("visit_terminator: terminator={:?}", terminator); + match &terminator.kind { TerminatorKind::Call { destination: Some((into, _)), .. } => { self.remove_never_initialized_mut_locals(*into); } - TerminatorKind::DropAndReplace { location, .. } => { - self.remove_never_initialized_mut_locals(*location); + TerminatorKind::DropAndReplace { place, .. } => { + self.remove_never_initialized_mut_locals(*place); } _ => {} } + + self.super_terminator(terminator, location); } - fn visit_statement(&mut self, statement: &Statement<'tcx>, _location: Location) { + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { if let StatementKind::Assign(box (into, _)) = &statement.kind { debug!( "visit_statement: statement={:?} local={:?} \ @@ -84,6 +88,8 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc ); self.remove_never_initialized_mut_locals(*into); } + + self.super_statement(statement, location); } fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) { diff --git a/src/librustc_mir/const_eval/mod.rs b/src/librustc_mir/const_eval/mod.rs index 3539ccf5de0..ed992a59839 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/src/librustc_mir/const_eval/mod.rs @@ -30,8 +30,10 @@ pub(crate) fn const_caller_location( ConstValue::Scalar(loc_place.ptr) } -// this function uses `unwrap` copiously, because an already validated constant -// must have valid fields and can thus never fail outside of compiler bugs +/// This function uses `unwrap` copiously, because an already validated constant +/// must have valid fields and can thus never fail outside of compiler bugs. However, it is +/// invoked from the pretty printer, where it can receive enums with no variants and e.g. +/// `read_discriminant` needs to be able to handle that. pub(crate) fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -41,17 +43,21 @@ pub(crate) fn destructure_const<'tcx>( let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); let op = ecx.eval_const_to_op(val, None).unwrap(); - let variant = ecx.read_discriminant(op).unwrap().1; - // We go to `usize` as we cannot allocate anything bigger anyway. - let field_count = match val.ty.kind { - ty::Array(_, len) => usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), - ty::Adt(def, _) => def.variants[variant].fields.len(), - ty::Tuple(substs) => substs.len(), + let (field_count, variant, down) = match val.ty.kind { + ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), + ty::Adt(def, _) if def.variants.is_empty() => { + return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) }; + } + ty::Adt(def, _) => { + let variant = ecx.read_discriminant(op).unwrap().1; + let down = ecx.operand_downcast(op, variant).unwrap(); + (def.variants[variant].fields.len(), Some(variant), down) + } + ty::Tuple(substs) => (substs.len(), None, op), _ => bug!("cannot destructure constant {:?}", val), }; - let down = ecx.operand_downcast(op, variant).unwrap(); let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(down, i).unwrap(); let val = op_to_const(&ecx, field_op); diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/src/librustc_mir/dataflow/framework/direction.rs index 6c9cb529dc2..4512ae96c08 100644 --- a/src/librustc_mir/dataflow/framework/direction.rs +++ b/src/librustc_mir/dataflow/framework/direction.rs @@ -441,8 +441,8 @@ impl Direction for Forward { Goto { target } => propagate(target, exit_state), Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ } - | Drop { target, unwind, location: _ } - | DropAndReplace { target, unwind, value: _, location: _ } + | Drop { target, unwind, place: _ } + | DropAndReplace { target, unwind, value: _, place: _ } | FalseUnwind { real_target: target, unwind } => { if let Some(unwind) = unwind { if dead_unwinds.map_or(true, |dead| !dead.contains(bb)) { diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs index 1d49a32e196..70c916a0892 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs @@ -189,8 +189,8 @@ where self.super_terminator(terminator, location); match terminator.kind { - mir::TerminatorKind::Drop { location: dropped_place, .. } - | mir::TerminatorKind::DropAndReplace { location: dropped_place, .. } => { + mir::TerminatorKind::Drop { place: dropped_place, .. } + | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // See documentation for `unsound_ignore_borrow_on_drop` for an explanation. if !self.ignore_borrow_on_drop { self.trans.gen(dropped_place.local); diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 41c7bd95a96..7c8aa1db71f 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -387,13 +387,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.gather_init(place.as_ref(), InitKind::Deep); } - TerminatorKind::Drop { location, target: _, unwind: _ } => { - self.gather_move(location); + TerminatorKind::Drop { place, target: _, unwind: _ } => { + self.gather_move(place); } - TerminatorKind::DropAndReplace { location, ref value, .. } => { - self.create_move_path(location); + TerminatorKind::DropAndReplace { place, ref value, .. } => { + self.create_move_path(place); self.gather_operand(value); - self.gather_init(location.as_ref(), InitKind::Deep); + self.gather_init(place.as_ref(), InitKind::Deep); } TerminatorKind::Call { ref func, diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 3c724c79b40..cab13d379a2 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -293,7 +293,6 @@ pub enum InternKind { Static(hir::Mutability), Constant, Promoted, - ConstProp, } /// Intern `ret` and everything it references. @@ -314,9 +313,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>( let base_intern_mode = match intern_kind { InternKind::Static(mutbl) => InternMode::Static(mutbl), // FIXME: what about array lengths, array initializers? - InternKind::Constant | InternKind::ConstProp | InternKind::Promoted => { - InternMode::ConstBase - } + InternKind::Constant | InternKind::Promoted => InternMode::ConstBase, }; // Type based interning. @@ -358,7 +355,10 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>( Err(error) => { ecx.tcx.sess.delay_span_bug( ecx.tcx.span, - "error during interning should later cause validation failure", + &format!( + "error during interning should later cause validation failure: {}", + error + ), ); // Some errors shouldn't come up because creating them causes // an allocation, which we should avoid. When that happens, @@ -399,7 +399,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>( // immutability is so important. alloc.mutability = Mutability::Not; } - InternKind::Constant | InternKind::ConstProp => { + InternKind::Constant => { // If it's a constant, we should not have any "leftovers" as everything // is tracked by const-checking. // FIXME: downgrade this to a warning? It rejects some legitimate consts, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 47e5b8b4fce..ac28ccd1815 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -389,6 +389,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); self.copy_op(self.operand_index(args[0], index)?, dest)?; } + // FIXME(#73156): Handle source code coverage in const eval + sym::count_code_region => (), _ => return Ok(false), } diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs index 71cca725982..379117f3b84 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/src/librustc_mir/interpret/intrinsics/type_name.rs @@ -50,7 +50,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Dynamic(_, _) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => { + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { write!(self, "_")?; Ok(self) } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 38f5988d0eb..35e433c4bd5 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer}; use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Abi, DiscriminantKind, HasDataLayout, LayoutOf, Size}; +use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ @@ -527,7 +527,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Early-return cases. let val_val = match val.val { ty::ConstKind::Param(_) => throw_inval!(TooGeneric), - ty::ConstKind::Error => throw_inval!(TypeckError(ErrorReported)), + ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def_id, substs, promoted) => { let instance = self.resolve(def_id, substs)?; // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. @@ -587,7 +587,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> { trace!("read_discriminant_value {:#?}", op.layout); - // Get type and layout of the discriminant. let discr_layout = self.layout_of(op.layout.ty.discriminant_ty(*self.tcx))?; trace!("discriminant type: {:?}", discr_layout.ty); @@ -596,10 +595,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // This is not to be confused with its "variant index", which is just determining its position in the // declared list of variants -- they can differ with explicitly assigned discriminants. // We use "tag" to refer to how the discriminant is encoded in memory, which can be either - // straight-forward (`DiscriminantKind::Tag`) or with a niche (`DiscriminantKind::Niche`). - // Unfortunately, the rest of the compiler calls the latter "discriminant", too, which makes things - // rather confusing. - let (tag_scalar_layout, tag_kind, tag_index) = match op.layout.variants { + // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). + let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout.variants { Variants::Single { index } => { let discr = match op.layout.ty.discriminant_for_variant(*self.tcx, index) { Some(discr) => { @@ -615,8 +612,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; return Ok((discr, index)); } - Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { - (discr, discr_kind, discr_index) + Variants::Multiple { ref tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) } }; @@ -633,21 +630,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(self.operand_field(op, tag_index)?)?; + let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed()); let tag_val = tag_val.to_scalar()?; trace!("tag value: {:?}", tag_val); // Figure out which discriminant and variant this corresponds to. - Ok(match *tag_kind { - DiscriminantKind::Tag => { + Ok(match *tag_encoding { + TagEncoding::Direct => { let tag_bits = self .force_bits(tag_val, tag_layout.size) - .map_err(|_| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; + .map_err(|_| err_ub!(InvalidTag(tag_val.erase_tag())))?; // Cast bits from tag layout to discriminant layout. - let discr_val_cast = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); - let discr_bits = discr_val_cast.assert_bits(discr_layout.size); + let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty); + let discr_bits = discr_val.assert_bits(discr_layout.size); // Convert discriminant to variant index, and catch invalid discriminants. let index = match op.layout.ty.kind { ty::Adt(adt, _) => { @@ -661,11 +658,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => bug!("tagged layout for non-adt non-generator"), } - .ok_or_else(|| err_ub!(InvalidDiscriminant(tag_val.erase_tag())))?; + .ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_tag())))?; // Return the cast value, and the index. - (discr_val_cast, index.0) + (discr_val, index.0) } - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { // Compute the variant this niche value/"tag" corresponds to. With niche layout, // discriminant (encoded in niche/tag) and variant index are the same. let variants_start = niche_variants.start().as_u32(); @@ -677,7 +674,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { && variants_start == variants_end && !self.memory.ptr_may_be_null(ptr); if !ptr_valid { - throw_ub!(InvalidDiscriminant(tag_val.erase_tag())) + throw_ub!(InvalidTag(tag_val.erase_tag())) } dataful_variant } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 24b191e9b53..396aec0a8f8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -9,7 +9,7 @@ use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Abi, Align, DiscriminantKind, FieldsShape}; +use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ @@ -1045,7 +1045,8 @@ where MPlaceTy { mplace, layout } } - pub fn write_discriminant_index( + /// Writes the discriminant of the given variant. + pub fn write_discriminant( &mut self, variant_index: VariantIdx, dest: PlaceTy<'tcx, M::PointerTag>, @@ -1061,9 +1062,9 @@ where assert_eq!(index, variant_index); } Variants::Multiple { - discr_kind: DiscriminantKind::Tag, - discr: ref discr_layout, - discr_index, + tag_encoding: TagEncoding::Direct, + tag: ref tag_layout, + tag_field, .. } => { // No need to validate that the discriminant here because the @@ -1075,17 +1076,17 @@ where // raw discriminants for enums are isize or bigger during // their computation, but the in-memory tag is the smallest possible // representation - let size = discr_layout.value.size(self); - let discr_val = truncate(discr_val, size); + let size = tag_layout.value.size(self); + let tag_val = truncate(discr_val, size); - let discr_dest = self.place_field(dest, discr_index)?; - self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; + let tag_dest = self.place_field(dest, tag_field)?; + self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?; } Variants::Multiple { - discr_kind: - DiscriminantKind::Niche { dataful_variant, ref niche_variants, niche_start }, - discr: ref discr_layout, - discr_index, + tag_encoding: + TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag: ref tag_layout, + tag_field, .. } => { // No need to validate that the discriminant here because the @@ -1098,19 +1099,19 @@ where .checked_sub(variants_start) .expect("overflow computing relative variant idx"); // We need to use machine arithmetic when taking into account `niche_start`: - // discr_val = variant_index_relative + niche_start_val - let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; - let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); + // tag_val = variant_index_relative + niche_start_val + let tag_layout = self.layout_of(tag_layout.value.to_int_ty(*self.tcx))?; + let niche_start_val = ImmTy::from_uint(niche_start, tag_layout); let variant_index_relative_val = - ImmTy::from_uint(variant_index_relative, discr_layout); - let discr_val = self.binary_op( + ImmTy::from_uint(variant_index_relative, tag_layout); + let tag_val = self.binary_op( mir::BinOp::Add, variant_index_relative_val, niche_start_val, )?; // Write result. - let niche_dest = self.place_field(dest, discr_index)?; - self.write_immediate(*discr_val, niche_dest)?; + let niche_dest = self.place_field(dest, tag_field)?; + self.write_immediate(*tag_val, niche_dest)?; } } } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 16c6396799e..18f9bbd2e31 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -88,7 +88,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { SetDiscriminant { place, variant_index } => { let dest = self.eval_place(**place)?; - self.write_discriminant_index(*variant_index, dest)?; + self.write_discriminant(*variant_index, dest)?; } // Mark locals as alive @@ -179,7 +179,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { - self.write_discriminant_index(variant_index, dest)?; + self.write_discriminant(variant_index, dest)?; if adt_def.is_enum() { (self.place_downcast(dest, variant_index)?, active_field_index) } else { diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index cd7621ea975..1d57fce3973 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -91,10 +91,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - Drop { location, target, unwind } => { - let place = self.eval_place(location)?; + Drop { place, target, unwind } => { + let place = self.eval_place(place)?; let ty = place.layout.ty; - trace!("TerminatorKind::drop: {:?}, type {}", location, ty); + trace!("TerminatorKind::drop: {:?}, type {}", place, ty); let instance = Instance::resolve_drop_in_place(*self.tcx, ty); self.drop_in_place(place, instance, target, unwind)?; diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7e3b6c08e08..3bb9ba37120 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -208,8 +208,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize) -> PathElem { // First, check if we are projecting to a variant. match layout.variants { - Variants::Multiple { discr_index, .. } => { - if discr_index == field { + Variants::Multiple { tag_field, .. } => { + if tag_field == field { return match layout.ty.kind { ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Generator(..) => PathElem::GeneratorTag, @@ -561,7 +561,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Generator(..) => Ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. - ty::Error + ty::Error(_) | ty::Infer(..) | ty::Placeholder(..) | ty::Bound(..) @@ -697,8 +697,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> try_validation!( self.walk_value(op), self.path, - err_ub!(InvalidDiscriminant(val)) => - { "{}", val } expected { "a valid enum discriminant" }, + err_ub!(InvalidTag(val)) => + { "{}", val } expected { "a valid enum tag" }, err_unsup!(ReadPointerAsBytes) => { "a pointer" } expected { "plain (non-pointer) bytes" }, ); diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 994d1e69f2e..36f3947d830 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -586,6 +586,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output.push(create_fn_mono_item(instance)); } } + mir::Rvalue::ThreadLocalRef(def_id) => { + assert!(self.tcx.is_thread_local_static(def_id)); + let instance = Instance::mono(self.tcx, def_id); + if should_monomorphize_locally(self.tcx, &instance) { + trace!("collecting thread-local static {:?}", def_id); + self.output.push(MonoItem::Static(def_id)); + } + } _ => { /* not interesting */ } } @@ -616,19 +624,19 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_const(constant); } - fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) { - debug!("visiting terminator {:?} @ {:?}", kind, location); + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { + debug!("visiting terminator {:?} @ {:?}", terminator, location); let tcx = self.tcx; - match *kind { + match terminator.kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); let callee_ty = self.monomorphize(callee_ty); visit_fn_use(self.tcx, callee_ty, true, &mut self.output); } - mir::TerminatorKind::Drop { ref location, .. } - | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.body, self.tcx).ty; + mir::TerminatorKind::Drop { ref place, .. } + | mir::TerminatorKind::DropAndReplace { ref place, .. } => { + let ty = place.ty(self.body, self.tcx).ty; let ty = self.monomorphize(ty); visit_drop_use(self.tcx, ty, true, self.output); } @@ -663,7 +671,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { | mir::TerminatorKind::FalseUnwind { .. } => bug!(), } - self.super_terminator_kind(kind, location); + self.super_terminator(terminator, location); } fn visit_local( diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index db1ea72c0a5..a945c1d626a 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -454,18 +454,11 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit fn merge_codegen_units<'tcx>( tcx: TyCtxt<'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - mut target_cgu_count: usize, + target_cgu_count: usize, ) { assert!(target_cgu_count >= 1); let codegen_units = &mut initial_partitioning.codegen_units; - if tcx.is_compiler_builtins(LOCAL_CRATE) { - // Compiler builtins require some degree of control over how mono items - // are partitioned into compilation units. Provide it by keeping the - // original partitioning when compiling the compiler builtins crate. - target_cgu_count = codegen_units.len(); - } - // Note that at this point in time the `codegen_units` here may not be in a // deterministic order (but we know they're deterministically the same set). // We want this merging to produce a deterministic ordering of codegen units diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index f95fd9b9e90..15a2e9130a3 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -32,13 +32,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut result = match instance { ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VtableShim(def_id) => build_call_shim( - tcx, - instance, - Some(Adjustment::DerefMove), - CallKind::Direct(def_id), - None, - ), + ty::InstanceDef::VtableShim(def_id) => { + build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None) + } ty::InstanceDef::FnPtrShim(def_id, ty) => { // FIXME(eddyb) support generating shims for a "shallow type", // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic @@ -60,7 +56,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect, Some(arg_tys)) + build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys)) } // We are generating a call back to our def-id, which the // codegen backend knows to turn to an actual call, be it @@ -134,15 +130,28 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' #[derive(Copy, Clone, Debug, PartialEq)] enum Adjustment { + /// Pass the receiver as-is. Identity, + + /// We get passed `&[mut] self` and call the target with `*self`. + /// + /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it + /// (for `VtableShim`, which effectively is passed `&own Self`). Deref, - DerefMove, + + /// We get passed `self: Self` and call the target with `&mut self`. + /// + /// In this case we need to ensure that the `Self` is dropped after the call, as the callee + /// won't do it for us. RefMut, } #[derive(Copy, Clone, Debug, PartialEq)] -enum CallKind { - Indirect, +enum CallKind<'tcx> { + /// Call the `FnPtr` that was passed as the receiver. + Indirect(Ty<'tcx>), + + /// Call a known `FnDef`. Direct(DefId), } @@ -582,7 +591,7 @@ impl CloneShimBuilder<'tcx> { self.block( vec![], TerminatorKind::Drop { - location: self.tcx.mk_place_index(dest, beg), + place: self.tcx.mk_place_index(dest, beg), target: BasicBlock::new(8), unwind: None, }, @@ -634,7 +643,7 @@ impl CloneShimBuilder<'tcx> { self.block( vec![], TerminatorKind::Drop { - location: previous_field, + place: previous_field, target: previous_cleanup, unwind: None, }, @@ -662,7 +671,7 @@ fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, rcvr_adjustment: Option<Adjustment>, - call_kind: CallKind, + call_kind: CallKind<'tcx>, untuple_args: Option<&[Ty<'tcx>]>, ) -> Body<'tcx> { debug!( @@ -675,6 +684,29 @@ fn build_call_shim<'tcx>( let sig = tcx.fn_sig(def_id); let mut sig = tcx.erase_late_bound_regions(&sig); + if let CallKind::Indirect(fnty) = call_kind { + // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This + // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from + // the implemented `FnX` trait. + + // Apply the opposite adjustment to the MIR input. + let mut inputs_and_output = sig.inputs_and_output.to_vec(); + + // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the + // fn arguments. `Self` may be passed via (im)mutable reference or by-value. + assert_eq!(inputs_and_output.len(), 3); + + // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for + // `FnDef` and `FnPtr` callees, not the `Self` type param. + let self_arg = &mut inputs_and_output[0]; + *self_arg = match rcvr_adjustment.unwrap() { + Adjustment::Identity => fnty, + Adjustment::Deref => tcx.mk_imm_ptr(fnty), + Adjustment::RefMut => tcx.mk_mut_ptr(fnty), + }; + sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output); + } + // FIXME(eddyb) avoid having this snippet both here and in // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). if let ty::InstanceDef::VtableShim(..) = instance { @@ -701,8 +733,7 @@ fn build_call_shim<'tcx>( let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment { Adjustment::Identity => Operand::Move(rcvr_place()), - Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), // Can't copy `&mut` - Adjustment::DerefMove => Operand::Move(tcx.mk_place_deref(rcvr_place())), + Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())), Adjustment::RefMut => { // let rcvr = &mut rcvr; let ref_rcvr = local_decls.push( @@ -728,7 +759,10 @@ fn build_call_shim<'tcx>( }); let (callee, mut args) = match call_kind { - CallKind::Indirect => (rcvr.unwrap(), vec![]), + // `FnPtr` call has no receiver. Args are untupled below. + CallKind::Indirect(_) => (rcvr.unwrap(), vec![]), + + // `FnDef` call with optional receiver. CallKind::Direct(def_id) => { let ty = tcx.type_of(def_id); ( @@ -799,11 +833,7 @@ fn build_call_shim<'tcx>( block( &mut blocks, vec![], - TerminatorKind::Drop { - location: rcvr_place(), - target: BasicBlock::new(2), - unwind: None, - }, + TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None }, false, ); } @@ -814,11 +844,7 @@ fn build_call_shim<'tcx>( block( &mut blocks, vec![], - TerminatorKind::Drop { - location: rcvr_place(), - target: BasicBlock::new(4), - unwind: None, - }, + TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None }, true, ); 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 39ce2340aed..a02d0f65560 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -64,8 +64,8 @@ fn add_moves_for_packed_drops_patch<'tcx>( let terminator = data.terminator(); match terminator.kind { - TerminatorKind::Drop { location, .. } - if util::is_disaligned(tcx, body, param_env, location) => + TerminatorKind::Drop { place, .. } + if util::is_disaligned(tcx, body, param_env, place) => { add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup); } @@ -88,13 +88,13 @@ fn add_move_for_packed_drop<'tcx>( is_cleanup: bool, ) { debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc); - let (location, target, unwind) = match terminator.kind { - TerminatorKind::Drop { ref location, target, unwind } => (location, target, unwind), + let (place, target, unwind) = match terminator.kind { + TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind), _ => unreachable!(), }; let source_info = terminator.source_info; - let ty = location.ty(body, tcx).ty; + let ty = place.ty(body, tcx).ty; let temp = patch.new_temp(ty, terminator.source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { @@ -104,9 +104,9 @@ fn add_move_for_packed_drop<'tcx>( }); patch.add_statement(loc, StatementKind::StorageLive(temp)); - patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*location))); + patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place))); patch.patch_terminator( loc.block, - TerminatorKind::Drop { location: Place::from(temp), target: storage_dead_block, unwind }, + TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind }, ); } diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index d5059c98c95..733ae908451 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -205,22 +205,34 @@ impl NonConstOp for CellBorrow { #[derive(Debug)] pub struct MutBorrow; impl NonConstOp for MutBorrow { + fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { + // Forbid everywhere except in const fn + ccx.const_kind() == hir::ConstContext::ConstFn + && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) + } + fn feature_gate() -> Option<Symbol> { Some(sym::const_mut_refs) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!( - "references in {}s may only refer \ - to immutable values", - ccx.const_kind() - ), - ); - err.span_label(span, format!("{}s require immutable values", ccx.const_kind())); + let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + } else { + struct_span_err!( + ccx.tcx.sess, + span, + E0764, + "mutable references are not allowed in {}s", + ccx.const_kind(), + ) + }; + err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "References in statics and constants may only refer \ diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs index 226e0e2049e..124606fb423 100644 --- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs +++ b/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs @@ -78,7 +78,7 @@ impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); match &terminator.kind { - mir::TerminatorKind::Drop { location: dropped_place, .. } => { + mir::TerminatorKind::Drop { place: dropped_place, .. } => { let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { return; diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index a81d7a23be2..b8104292aab 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -121,25 +121,25 @@ where self.super_assign(place, rvalue, location); } - fn visit_terminator_kind(&mut self, kind: &mir::TerminatorKind<'tcx>, location: Location) { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { // The effect of assignment to the return place in `TerminatorKind::Call` is not applied // here; that occurs in `apply_call_return_effect`. - if let mir::TerminatorKind::DropAndReplace { value, location: dest, .. } = kind { + if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind { let qualif = qualifs::in_operand::<Q, _>( self.ccx, &mut |l| self.qualifs_per_local.contains(l), value, ); - if !dest.is_indirect() { - self.assign_qualif_direct(dest, qualif); + if !place.is_indirect() { + self.assign_qualif_direct(place, qualif); } } // We need to assign qualifs to the dropped location before visiting the operand that // replaces it since qualifs can be cleared on move. - self.super_terminator_kind(kind, location); + self.super_terminator(terminator, location); } } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 428a74bcdcb..35a8df62cb8 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -560,8 +560,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Forbid all `Drop` terminators unless the place being dropped is a local with no // projections that cannot be `NeedsDrop`. - TerminatorKind::Drop { location: dropped_place, .. } - | TerminatorKind::DropAndReplace { location: dropped_place, .. } => { + TerminatorKind::Drop { place: dropped_place, .. } + | TerminatorKind::DropAndReplace { place: dropped_place, .. } => { // If we are checking live drops after drop-elaboration, don't emit duplicate // errors here. if super::post_drop_elaboration::checking_enabled(self.tcx) { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 83ed2fc2d43..17ca918d32c 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -27,9 +27,9 @@ use rustc_trait_selection::traits; use crate::const_eval::error_to_const_error; use crate::interpret::{ - self, compile_time_machine, intern_const_alloc_recursive, AllocId, Allocation, Frame, ImmTy, - Immediate, InternKind, InterpCx, LocalState, LocalValue, Memory, MemoryKind, OpTy, - Operand as InterpOperand, PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup, + self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState, + LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, + ScalarMaybeUninit, StackPopCleanup, }; use crate::transform::{MirPass, MirSource}; @@ -702,11 +702,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ScalarMaybeUninit::Scalar(l), ScalarMaybeUninit::Scalar(r), )) => l.is_bits() && r.is_bits(), - interpret::Operand::Indirect(_) if mir_opt_level >= 2 => { - let mplace = op.assert_mem_place(&self.ecx); - intern_const_alloc_recursive(&mut self.ecx, InternKind::ConstProp, mplace, false); - true - } _ => false, } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index e4129f447d5..1704d8baabd 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -85,15 +85,15 @@ fn find_dead_unwinds<'tcx>( .iterate_to_fixpoint() .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks().iter_enumerated() { - let location = match bb_data.terminator().kind { - TerminatorKind::Drop { ref location, unwind: Some(_), .. } - | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location, + let place = match bb_data.terminator().kind { + TerminatorKind::Drop { ref place, unwind: Some(_), .. } + | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, _ => continue, }; debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data); - let path = match env.move_data.rev_lookup.find(location.as_ref()) { + let path = match env.move_data.rev_lookup.find(place.as_ref()) { LookupResult::Exact(e) => e, LookupResult::Parent(..) => { debug!("find_dead_unwinds: has parent; skipping"); @@ -105,7 +105,7 @@ fn find_dead_unwinds<'tcx>( debug!( "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", bb, - location, + place, path, flow_inits.get() ); @@ -294,16 +294,16 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn collect_drop_flags(&mut self) { for (bb, data) in self.body.basic_blocks().iter_enumerated() { let terminator = data.terminator(); - let location = match terminator.kind { - TerminatorKind::Drop { ref location, .. } - | TerminatorKind::DropAndReplace { ref location, .. } => location, + let place = match terminator.kind { + TerminatorKind::Drop { ref place, .. } + | TerminatorKind::DropAndReplace { ref place, .. } => place, _ => continue, }; self.init_data.seek_before(self.body.terminator_loc(bb)); - let path = self.move_data().rev_lookup.find(location.as_ref()); - debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, location, path); + let path = self.move_data().rev_lookup.find(place.as_ref()); + debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path); let path = match path { LookupResult::Exact(e) => e, @@ -315,7 +315,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { terminator.source_info.span, "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", bb, - location, + place, path ); } @@ -328,7 +328,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", child, - location, + place, path, (maybe_live, maybe_dead) ); @@ -346,13 +346,13 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let resume_block = self.patch.resume_block(); match terminator.kind { - TerminatorKind::Drop { location, target, unwind } => { + TerminatorKind::Drop { place, target, unwind } => { self.init_data.seek_before(loc); - match self.move_data().rev_lookup.find(location.as_ref()) { + match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(path) => elaborate_drop( &mut Elaborator { ctxt: self }, terminator.source_info, - location, + place, path, target, if data.is_cleanup { @@ -371,10 +371,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } } } - TerminatorKind::DropAndReplace { location, ref value, target, unwind } => { + TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { assert!(!data.is_cleanup); - self.elaborate_replace(loc, location, value, target, unwind); + self.elaborate_replace(loc, place, value, target, unwind); } _ => continue, } @@ -396,7 +396,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn elaborate_replace( &mut self, loc: Location, - location: Place<'tcx>, + place: Place<'tcx>, value: &Operand<'tcx>, target: BasicBlock, unwind: Option<BasicBlock>, @@ -407,7 +407,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); let assign = Statement { - kind: StatementKind::Assign(box (location, Rvalue::Use(value.clone()))), + kind: StatementKind::Assign(box (place, Rvalue::Use(value.clone()))), source_info: terminator.source_info, }; @@ -427,14 +427,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { is_cleanup: false, }); - match self.move_data().rev_lookup.find(location.as_ref()) { + match self.move_data().rev_lookup.find(place.as_ref()) { LookupResult::Exact(path) => { debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); self.init_data.seek_before(loc); elaborate_drop( &mut Elaborator { ctxt: self }, terminator.source_info, - location, + place, path, target, Unwind::To(unwind), @@ -459,7 +459,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); self.patch.patch_terminator( bb, - TerminatorKind::Drop { location, target, unwind: Some(unwind) }, + TerminatorKind::Drop { place, target, unwind: Some(unwind) }, ); } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 25b6a51d91b..c8702eeae1d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -93,13 +93,13 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> { } } - fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) { - match kind { + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + match terminator.kind { TerminatorKind::Return => { // Do not replace the implicit `_0` access here, as that's not possible. The // transform already handles `return` correctly. } - _ => self.super_terminator_kind(kind, location), + _ => self.super_terminator(terminator, location), } } } @@ -835,8 +835,8 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, body: &mut for (block, block_data) in body.basic_blocks().iter_enumerated() { let (target, unwind, source_info) = match block_data.terminator() { - Terminator { source_info, kind: TerminatorKind::Drop { location, target, unwind } } => { - if let Some(local) = location.as_local() { + Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => { + if let Some(local) = place.as_local() { if local == SELF_ARG { (target, unwind, source_info) } else { @@ -1102,11 +1102,8 @@ fn create_generator_resume_function<'tcx>( fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock { let return_block = insert_term_block(body, TerminatorKind::Return); - let term = TerminatorKind::Drop { - location: Place::from(SELF_ARG), - target: return_block, - unwind: None, - }; + let term = + TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None }; let source_info = SourceInfo::outermost(body.span); // Create a block to destroy an unresumed generators. This can only destroy upvars. @@ -1222,7 +1219,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform { movability == hir::Movability::Movable, ) } - _ => bug!(), + _ => { + tcx.sess + .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty)); + return; + } }; // Compute GeneratorState<yield_ty, return_ty> diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 47aa4fbf60c..068d055fa78 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -9,7 +9,6 @@ use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; -use rustc_session::config::Sanitizer; use rustc_target::spec::abi::Abi; use super::simplify::{remove_dead_blocks, CfgSimplifier}; @@ -232,24 +231,8 @@ impl Inliner<'tcx> { // Avoid inlining functions marked as no_sanitize if sanitizer is enabled, // since instrumentation might be enabled and performed on the caller. - match self.tcx.sess.opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) => { - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_ADDRESS) { - return false; - } - } - Some(Sanitizer::Memory) => { - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_MEMORY) { - return false; - } - } - Some(Sanitizer::Thread) => { - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_SANITIZE_THREAD) { - return false; - } - } - Some(Sanitizer::Leak) => {} - None => {} + if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) { + return false; } let hinted = match codegen_fn_attrs.inline { @@ -319,13 +302,13 @@ impl Inliner<'tcx> { let term = blk.terminator(); let mut is_drop = false; match term.kind { - TerminatorKind::Drop { ref location, target, unwind } - | TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => { + TerminatorKind::Drop { ref place, target, unwind } + | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => { is_drop = true; work_list.push(target); - // If the location doesn't actually need dropping, treat it like + // If the place doesn't actually need dropping, treat it like // a regular goto. - let ty = location.ty(callee_body, tcx).subst(tcx, callsite.substs).ty; + let ty = place.ty(callee_body, tcx).subst(tcx, callsite.substs).ty; if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { @@ -731,14 +714,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } - fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, loc: Location) { + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) { // Don't try to modify the implicit `_0` access on return (`return` terminators are // replaced down below anyways). - if !matches!(kind, TerminatorKind::Return) { - self.super_terminator_kind(kind, loc); + if !matches!(terminator.kind, TerminatorKind::Return) { + self.super_terminator(terminator, loc); } - match *kind { + match terminator.kind { TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(), TerminatorKind::Goto { ref mut target } => { *target = self.update_target(*target); @@ -782,11 +765,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } TerminatorKind::Return => { - *kind = TerminatorKind::Goto { target: self.return_block }; + terminator.kind = TerminatorKind::Goto { target: self.return_block }; } TerminatorKind::Resume => { if let Some(tgt) = self.cleanup_block { - *kind = TerminatorKind::Goto { target: tgt } + terminator.kind = TerminatorKind::Goto { target: tgt } } } TerminatorKind::Abort => {} diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs new file mode 100644 index 00000000000..c36614938e1 --- /dev/null +++ b/src/librustc_mir/transform/instrument_coverage.rs @@ -0,0 +1,92 @@ +use crate::transform::{MirPass, MirSource}; +use crate::util::patch::MirPatch; +use rustc_hir::lang_items; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::*; +use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::DefId; +use rustc_span::Span; + +/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with +/// the intrinsic llvm.instrprof.increment. +pub struct InstrumentCoverage; + +impl<'tcx> MirPass<'tcx> for InstrumentCoverage { + fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.instrument_coverage { + debug!("instrumenting {:?}", src.def_id()); + instrument_coverage(tcx, body); + } + } +} + +// The first counter (start of the function) is index zero. +const INIT_FUNCTION_COUNTER: u32 = 0; + +/// Injects calls to placeholder function `count_code_region()`. +// FIXME(richkadel): As a first step, counters are only injected at the top of each function. +// The complete solution will inject counters at each conditional code branch. +pub fn instrument_coverage<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let span = body.span.shrink_to_lo(); + + let count_code_region_fn = function_handle( + tcx, + tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None), + span, + ); + let counter_index = Operand::const_from_scalar( + tcx, + tcx.types.u32, + Scalar::from_u32(INIT_FUNCTION_COUNTER), + span, + ); + + let mut patch = MirPatch::new(body); + + let new_block = patch.new_block(placeholder_block(SourceInfo::outermost(body.span))); + let next_block = START_BLOCK; + + let temp = patch.new_temp(tcx.mk_unit(), body.span); + patch.patch_terminator( + new_block, + TerminatorKind::Call { + func: count_code_region_fn, + args: vec![counter_index], + // new_block will swapped with the next_block, after applying patch + destination: Some((Place::from(temp), new_block)), + cleanup: None, + from_hir_call: false, + fn_span: span, + }, + ); + + patch.add_statement(new_block.start_location(), StatementKind::StorageLive(temp)); + patch.add_statement(next_block.start_location(), StatementKind::StorageDead(temp)); + + patch.apply(body); + + // To insert the `new_block` in front of the first block in the counted branch (for example, + // the START_BLOCK, at the top of the function), just swap the indexes, leaving the rest of the + // graph unchanged. + body.basic_blocks_mut().swap(next_block, new_block); +} + +fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> { + let ret_ty = tcx.fn_sig(fn_def_id).output(); + let ret_ty = ret_ty.no_bound_vars().unwrap(); + let substs = tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(ret_ty))); + Operand::function_handle(tcx, fn_def_id, substs, span) +} + +fn placeholder_block<'tcx>(source_info: SourceInfo) -> BasicBlockData<'tcx> { + BasicBlockData { + statements: vec![], + terminator: Some(Terminator { + source_info, + // this gets overwritten by the counter Call + kind: TerminatorKind::Unreachable, + }), + is_cleanup: false, + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 4240b528a61..846ed1f86d8 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -28,6 +28,7 @@ pub mod elaborate_drops; pub mod generator; pub mod inline; pub mod instcombine; +pub mod instrument_coverage; pub mod no_landing_pads; pub mod nrvo; pub mod promote_consts; @@ -288,6 +289,10 @@ fn mir_validated( // What we need to run borrowck etc. &promote_pass, &simplify::SimplifyCfg::new("qualify-consts"), + // If the `instrument-coverage` option is enabled, analyze the CFG, identify each + // conditional branch, construct a coverage map to be passed to LLVM, and inject counters + // where needed. + &instrument_coverage::InstrumentCoverage, ]], ); diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 3bffafa1b2f..1d83733e4cd 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -34,10 +34,10 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads<'tcx> { self.tcx } - fn visit_terminator_kind(&mut self, kind: &mut TerminatorKind<'tcx>, location: Location) { - if let Some(unwind) = kind.unwind_mut() { + fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { + if let Some(unwind) = terminator.kind.unwind_mut() { unwind.take(); } - self.super_terminator_kind(kind, location); + self.super_terminator(terminator, location); } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index e1311ccd374..330f6c1640f 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -147,7 +147,6 @@ struct Collector<'a, 'tcx> { ccx: &'a ConstCx<'a, 'tcx>, temps: IndexVec<Local, TempState>, candidates: Vec<Candidate>, - span: Span, } impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { @@ -216,10 +215,10 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } } - fn visit_terminator_kind(&mut self, kind: &TerminatorKind<'tcx>, location: Location) { - self.super_terminator_kind(kind, location); + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + self.super_terminator(terminator, location); - match *kind { + match terminator.kind { TerminatorKind::Call { ref func, .. } => { if let ty::FnDef(def_id, _) = func.ty(self.ccx.body, self.ccx.tcx).kind { let fn_sig = self.ccx.tcx.fn_sig(def_id); @@ -254,10 +253,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { _ => {} } } - - fn visit_source_info(&mut self, source_info: &SourceInfo) { - self.span = source_info.span; - } } pub fn collect_temps_and_candidates( @@ -267,7 +262,6 @@ pub fn collect_temps_and_candidates( let mut collector = Collector { temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls), candidates: vec![], - span: ccx.body.span, ccx, }; for (bb, data) in rpo { @@ -1192,7 +1186,7 @@ pub fn promote_candidates<'tcx>( _ => true, }); let terminator = block.terminator_mut(); - if let TerminatorKind::Drop { location: place, target, .. } = &terminator.kind { + if let TerminatorKind::Drop { place, target, .. } = &terminator.kind { if let Some(index) = place.as_local() { if promoted(index) { terminator.kind = TerminatorKind::Goto { target: *target }; diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 4c8fc49099b..caf6c7715a9 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -349,9 +349,9 @@ fn check_terminator( | TerminatorKind::Resume | TerminatorKind::Unreachable => Ok(()), - TerminatorKind::Drop { location, .. } => check_place(tcx, *location, span, def_id, body), - TerminatorKind::DropAndReplace { location, value, .. } => { - check_place(tcx, *location, span, def_id, body)?; + TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body), + TerminatorKind::DropAndReplace { place, value, .. } => { + check_place(tcx, *place, span, def_id, body)?; check_operand(tcx, value, span, def_id, body) } diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index 8150c328316..625f40cd792 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -9,7 +9,6 @@ use rustc_middle::{ }, ty::{self, ParamEnv, TyCtxt}, }; -use rustc_span::def_id::DefId; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -24,15 +23,14 @@ pub struct Validator { impl<'tcx> MirPass<'tcx> for Validator { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - let def_id = source.def_id(); - let param_env = tcx.param_env(def_id); - TypeChecker { when: &self.when, def_id, body, tcx, param_env }.visit_body(body); + let param_env = tcx.param_env(source.def_id()); + TypeChecker { when: &self.when, source, body, tcx, param_env }.visit_body(body); } } struct TypeChecker<'a, 'tcx> { when: &'a str, - def_id: DefId, + source: MirSource<'tcx>, body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, @@ -47,7 +45,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span, &format!( "broken MIR in {:?} ({}) at {:?}:\n{}", - self.def_id, + self.source.instance, self.when, location, msg.as_ref() diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index a1345452ca9..5f55a812a4e 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -238,7 +238,7 @@ where self.elaborator.patch().patch_terminator( bb, TerminatorKind::Drop { - location: self.place, + place: self.place, target: self.succ, unwind: self.unwind.into_option(), }, @@ -723,7 +723,7 @@ where self.elaborator.patch().patch_terminator( drop_block, TerminatorKind::Drop { - location: tcx.mk_place_deref(ptr), + place: tcx.mk_place_deref(ptr), target: loop_block, unwind: unwind.into_option(), }, @@ -1000,7 +1000,7 @@ where fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock { let block = - TerminatorKind::Drop { location: self.place, target, unwind: unwind.into_option() }; + TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_option() }; self.new_block(unwind, block) } diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 2efe93d057b..e2cf1bce733 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -687,7 +687,7 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t let tcx = hir.tcx(); let owner_id = tcx.hir().body_owner(body_id); let span = tcx.hir().span(owner_id); - let ty = tcx.types.err; + let ty = tcx.ty_error(); let num_params = match hir.body_owner_kind { hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(), hir::BodyOwnerKind::Closure => { @@ -909,7 +909,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; self.local_decls[local].local_info = if let Some(kind) = self_binding { - Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))) + Some(box LocalInfo::User(ClearCrossCrate::Set( + BindingForm::ImplicitSelf(*kind), + ))) } else { let binding_mode = ty::BindingMode::BindByValue(mutability); Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( diff --git a/src/librustc_mir_build/build/scope.rs b/src/librustc_mir_build/build/scope.rs index 4daf567d7d4..b8df2709447 100644 --- a/src/librustc_mir_build/build/scope.rs +++ b/src/librustc_mir_build/build/scope.rs @@ -1037,7 +1037,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, block: BasicBlock, span: Span, - location: Place<'tcx>, + place: Place<'tcx>, value: Operand<'tcx>, ) -> BlockAnd<()> { let source_info = self.source_info(span); @@ -1047,7 +1047,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::DropAndReplace { - location, + place, value, target: next_target, unwind: Some(diverge_target), @@ -1158,7 +1158,7 @@ fn build_scope_drops<'tcx>( block, source_info, TerminatorKind::Drop { - location: local.into(), + place: local.into(), target: next, unwind: Some(unwind_to), }, @@ -1272,7 +1272,7 @@ fn build_diverge_scope<'tcx>( block, source_info(drop_data.span), TerminatorKind::Drop { - location: drop_data.local.into(), + place: drop_data.local.into(), target, unwind: None, }, diff --git a/src/librustc_mir_build/hair/cx/expr.rs b/src/librustc_mir_build/hair/cx/expr.rs index 703f6ef8dc4..a1796c9433e 100644 --- a/src/librustc_mir_build/hair/cx/expr.rs +++ b/src/librustc_mir_build/hair/cx/expr.rs @@ -478,7 +478,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( ); // Not a real fn, but we're not reaching codegen anyways... - ty = cx.tcx.types.err; + ty = cx.tcx.ty_error(); InlineAsmOperand::SymFn { expr: Expr { ty, diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 4a4de6c420b..6ac5d41ec61 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -800,7 +800,11 @@ impl<'tcx> Constructor<'tcx> { assert!(!adt.is_enum()); VariantIdx::new(0) } - ConstantValue(c) => cx.tcx.destructure_const(cx.param_env.and(c)).variant, + ConstantValue(c) => cx + .tcx + .destructure_const(cx.param_env.and(c)) + .variant + .expect("destructed const of adt without variant id"), _ => bug!("bad constructor {:?} for adt {:?}", self, adt), } } diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index 087c2c064cf..6dd7e0871b4 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -107,8 +107,15 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { cv.ty, structural ); + // This can occur because const qualification treats all associated constants as + // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them + // before it runs. + // + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation`. if structural.is_none() && mir_structural_match_violation { - bug!("MIR const-checker found novel structural match violation"); + warn!("MIR const-checker found novel structural match violation. See #73448."); + return inlined_const_as_pat; } if let Some(non_sm_ty) = structural { @@ -268,7 +275,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Variant { adt_def, substs, - variant_index: destructured.variant, + variant_index: destructured + .variant + .expect("destructed const of adt without variant id"), subpatterns: field_pats(destructured.fields), } } diff --git a/src/librustc_mir_build/hair/pattern/mod.rs b/src/librustc_mir_build/hair/pattern/mod.rs index e9aa7f597be..5c30b2a448c 100644 --- a/src/librustc_mir_build/hair/pattern/mod.rs +++ b/src/librustc_mir_build/hair/pattern/mod.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { let mut ty = self.tables.node_type(pat.hir_id); - if let ty::Error = ty.kind { + if let ty::Error(_) = ty.kind { // Avoid ICEs (e.g., #50577 and #50585). return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) }; } @@ -708,7 +708,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if adt_def.is_enum() { let substs = match ty.kind { ty::Adt(_, substs) | ty::FnDef(_, substs) => substs, - ty::Error => { + ty::Error(_) => { // Avoid ICE (#50585) return PatKind::Wild; } @@ -1051,7 +1051,7 @@ crate fn compare_const_vals<'tcx>( let b_bits = b.try_eval_bits(tcx, param_env, ty); if let (Some(a), Some(b)) = (a_bits, b_bits) { - use ::rustc_apfloat::Float; + use rustc_apfloat::Float; return match ty.kind { ty::Float(ast::FloatTy::F32) => { let l = ::rustc_apfloat::ieee::Single::from_bits(a); diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 84b3335a0f6..2e3cf4e746a 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -339,8 +339,15 @@ impl<'a> StringReader<'a> { } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { - self.fatal_span_(start + BytePos(1), suffix_start, "unterminated byte constant") - .raise() + self.sess + .span_diagnostic + .struct_span_fatal_with_code( + self.mk_sp(start + BytePos(1), suffix_start), + "unterminated byte constant", + error_code!(E0763), + ) + .emit(); + FatalError.raise(); } (token::Byte, Mode::Byte, 2, 1) // b' ' } diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 8792605c08d..fc9ffc30924 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -961,7 +961,7 @@ impl<'a> Parser<'a> { self.bump(); let sp = self.prev_token.span; self.struct_span_err(sp, &msg) - .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) + .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); return Ok(()); } else if self.look_ahead(0, |t| { diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index 849193151c3..53f32b7c800 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -216,8 +216,28 @@ impl<'a> Parser<'a> { } /// Parses the RHS of a local variable declaration (e.g., '= 14;'). - fn parse_initializer(&mut self, skip_eq: bool) -> PResult<'a, Option<P<Expr>>> { - if self.eat(&token::Eq) || skip_eq { Ok(Some(self.parse_expr()?)) } else { Ok(None) } + fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option<P<Expr>>> { + let eq_consumed = match self.token.kind { + token::BinOpEq(..) => { + // Recover `let x <op>= 1` as `let x = 1` + self.struct_span_err( + self.token.span, + "can't reassign to an uninitialized variable", + ) + .span_suggestion_short( + self.token.span, + "initialize the variable", + "=".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + self.bump(); + true + } + _ => self.eat(&token::Eq), + }; + + Ok(if eq_consumed || eq_optional { Some(self.parse_expr()?) } else { None }) } /// Parses a block. No inner attributes are allowed. diff --git a/src/librustc_parse_format/lib.rs b/src/librustc_parse_format/lib.rs index 23bf7b35419..a5b5a1090cb 100644 --- a/src/librustc_parse_format/lib.rs +++ b/src/librustc_parse_format/lib.rs @@ -178,7 +178,7 @@ pub struct Parser<'a> { /// Error messages accumulated during parsing pub errors: Vec<ParseError>, /// Current position of implicit positional argument pointer - curarg: usize, + pub curarg: usize, /// `Some(raw count)` when the string is "raw", used to position spans correctly style: Option<usize>, /// Start and end byte offset of every successfully parsed argument @@ -243,11 +243,13 @@ impl<'a> Iterator for Parser<'a> { _ => Some(String(self.string(pos))), } } else { - if self.is_literal && self.cur_line_start != self.input.len() { + if self.is_literal { let start = self.to_span_index(self.cur_line_start); let end = self.to_span_index(self.input.len()); - self.line_spans.push(start.to(end)); - self.cur_line_start = self.input.len(); + let span = start.to(end); + if self.line_spans.last() != Some(&span) { + self.line_spans.push(span); + } } None } diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index e2bfcf18edb..88fb78f85e4 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -150,7 +150,7 @@ impl ExprVisitor<'tcx> { _ => unreachable!(), }; let asm_ty = match ty.kind { - ty::Never | ty::Error => return None, + ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32), @@ -167,7 +167,7 @@ impl ExprVisitor<'tcx> { let fields = &adt.non_enum_variant().fields; let elem_ty = fields[0].ty(self.tcx, substs); match elem_ty.kind { - ty::Never | ty::Error => return None, + ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => { Some(InlineAsmType::VecI8(fields.len() as u64)) } diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs index 96ec23692df..f2f07b5d4fb 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/src/librustc_passes/weak_lang_items.rs @@ -5,10 +5,12 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::lang_items; +use rustc_hir::lang_items::ITEM_REFS; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::whitelisted; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -70,11 +72,21 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { } impl<'a, 'tcx> Context<'a, 'tcx> { - fn register(&mut self, name: Symbol, span: Span) { + fn register(&mut self, name: Symbol, span: Span, hir_id: hir::HirId) { if let Some(&item) = WEAK_ITEMS_REFS.get(&name) { if self.items.require(item).is_err() { self.items.missing.push(item); } + } else if name == sym::count_code_region { + // `core::intrinsics::code_count_region()` is (currently) the only `extern` lang item + // that is never actually linked. It is not a `weak_lang_item` that can be registered + // when used, and should be registered here instead. + if let Some((item_index, _)) = ITEM_REFS.get(&*name.as_str()).cloned() { + if self.items.items[item_index].is_none() { + let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); + self.items.items[item_index] = Some(item_def_id); + } + } } else { struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name) .emit(); @@ -91,7 +103,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) { if let Some((lang_item, _)) = hir::lang_items::extract(&i.attrs) { - self.register(lang_item, i.span); + self.register(lang_item, i.span, i.hir_id); } intravisit::walk_foreign_item(self, i) } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 3c1b56a9ef4..9e6e7ea962b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -220,7 +220,7 @@ where | ty::Ref(..) | ty::FnPtr(..) | ty::Param(..) - | ty::Error + | ty::Error(_) | ty::GeneratorWitness(..) => {} ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index e633bd1843e..8432e34a527 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -485,6 +485,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { module_path.push(Segment { ident: Ident { name: kw::PathRoot, span: source.ident.span }, id: Some(self.r.next_node_id()), + has_generic_args: false, }); source.ident.name = crate_name; } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 7166fef2d13..61f20df8cc6 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -24,6 +24,7 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::TraitCandidate; use rustc_middle::{bug, span_bug}; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use smallvec::{smallvec, SmallVec}; @@ -2188,7 +2189,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut ident: Ident, ns: Namespace, - ) -> Vec<TraitCandidate<NodeId>> { + ) -> Vec<TraitCandidate> { debug!("(getting traits containing item) looking for '{}'", ident.name); let mut found_traits = Vec::new(); @@ -2233,7 +2234,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ident: Ident, ns: Namespace, module: Module<'a>, - found_traits: &mut Vec<TraitCandidate<NodeId>>, + found_traits: &mut Vec<TraitCandidate>, ) { assert!(ns == TypeNS || ns == ValueNS); let mut traits = module.traits.borrow_mut(); @@ -2292,13 +2293,13 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &mut self, mut kind: &NameBindingKind<'_>, trait_name: Ident, - ) -> SmallVec<[NodeId; 1]> { + ) -> SmallVec<[LocalDefId; 1]> { let mut import_ids = smallvec![]; while let NameBindingKind::Import { import, binding, .. } = kind { let id = self.r.definitions.local_def_id(import.id); self.r.maybe_unused_trait_imports.insert(id); self.r.add_to_glob_map(&import, trait_name); - import_ids.push(import.id); + import_ids.push(id); kind = &binding.kind; } import_ids diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index ed7adefcb8c..05ef0aa0bb6 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -920,20 +920,47 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { &self, path: &[Segment], ) -> Option<(Span, &'static str, String, Applicability)> { - let ident = match path { - [segment] => segment.ident, + let (ident, span) = match path { + [segment] if !segment.has_generic_args => { + (segment.ident.to_string(), segment.ident.span) + } _ => return None, }; - match ( - self.diagnostic_metadata.current_item, - self.diagnostic_metadata.currently_processing_generics, - ) { - (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => { + let mut iter = ident.chars().map(|c| c.is_uppercase()); + let single_uppercase_char = + matches!(iter.next(), Some(true)) && matches!(iter.next(), None); + if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char { + return None; + } + match (self.diagnostic_metadata.current_item, single_uppercase_char) { + (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _) if ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main<T>()` } - (Some(Item { kind, .. }), true) => { + ( + Some(Item { + kind: + kind @ ItemKind::Fn(..) + | kind @ ItemKind::Enum(..) + | kind @ ItemKind::Struct(..) + | kind @ ItemKind::Union(..), + .. + }), + true, + ) + | (Some(Item { kind, .. }), false) => { // Likely missing type parameter. if let Some(generics) = kind.generics() { + if span.overlaps(generics.span) { + // Avoid the following: + // error[E0405]: cannot find trait `A` in this scope + // --> $DIR/typo-suggestion-named-underscore.rs:CC:LL + // | + // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore + // | ^- help: you might be missing a type parameter: `, A` + // | | + // | not found in this scope + return None; + } let msg = "you might be missing a type parameter"; let (span, sugg) = if let [.., param] = &generics.params[..] { let span = if let [.., bound] = ¶m.bounds[..] { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 61792e039c7..66e5612b627 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -38,7 +38,7 @@ use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, Definitions}; use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint}; -use rustc_hir::TraitMap; +use rustc_hir::TraitCandidate; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; @@ -225,13 +225,15 @@ enum VisResolutionError<'a> { ModuleOnly(Span), } -// A minimal representation of a path segment. We use this in resolve because -// we synthesize 'path segments' which don't have the rest of an AST or HIR -// `PathSegment`. +/// A minimal representation of a path segment. We use this in resolve because we synthesize 'path +/// segments' which don't have the rest of an AST or HIR `PathSegment`. #[derive(Clone, Copy, Debug)] pub struct Segment { ident: Ident, id: Option<NodeId>, + /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing + /// nonsensical suggestions. + has_generic_args: bool, } impl Segment { @@ -240,7 +242,7 @@ impl Segment { } fn from_ident(ident: Ident) -> Segment { - Segment { ident, id: None } + Segment { ident, id: None, has_generic_args: false } } fn names_to_string(segments: &[Segment]) -> String { @@ -250,7 +252,7 @@ impl Segment { impl<'a> From<&'a ast::PathSegment> for Segment { fn from(seg: &'a ast::PathSegment) -> Segment { - Segment { ident: seg.ident, id: Some(seg.id) } + Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() } } } @@ -879,7 +881,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, export_map: ExportMap<LocalDefId>, - trait_map: TraitMap<NodeId>, + trait_map: NodeMap<Vec<TraitCandidate>>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1285,14 +1287,7 @@ impl<'a> Resolver<'a> { let trait_map = self .trait_map .into_iter() - .map(|(k, v)| { - ( - definitions.node_id_to_hir_id(k), - v.into_iter() - .map(|tc| tc.map_import_ids(|id| definitions.node_id_to_hir_id(id))) - .collect(), - ) - }) + .map(|(k, v)| (definitions.node_id_to_hir_id(k), v)) .collect(); let maybe_unused_trait_imports = self.maybe_unused_trait_imports; let maybe_unused_extern_crates = self.maybe_unused_extern_crates; @@ -1323,17 +1318,7 @@ impl<'a> Resolver<'a> { trait_map: self .trait_map .iter() - .map(|(&k, v)| { - ( - self.definitions.node_id_to_hir_id(k), - v.iter() - .cloned() - .map(|tc| { - tc.map_import_ids(|id| self.definitions.node_id_to_hir_id(id)) - }) - .collect(), - ) - }) + .map(|(&k, v)| (self.definitions.node_id_to_hir_id(k), v.clone())) .collect(), glob_map: self.glob_map.clone(), maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(), @@ -2017,7 +2002,7 @@ impl<'a> Resolver<'a> { path, opt_ns, record_used, path_span, crate_lint, ); - for (i, &Segment { ident, id }) in path.iter().enumerate() { + for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", i, ident, id); let record_segment_res = |this: &mut Self, res| { if record_used { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 12d2c8c7eb9..f5c3e84c624 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -518,24 +518,13 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { } pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> { - let hir_node = self.tcx.hir().expect_expr(expr.hir_id); - let ty = self.tables.expr_ty_adjusted_opt(&hir_node); - if ty.is_none() || ty.unwrap().kind == ty::Error { + let ty = self.tables.expr_ty_adjusted_opt(expr)?; + if matches!(ty.kind, ty::Error(_)) { return None; } match expr.kind { hir::ExprKind::Field(ref sub_ex, ident) => { - let hir_node = match self.tcx.hir().find(sub_ex.hir_id) { - Some(Node::Expr(expr)) => expr, - _ => { - debug!( - "Missing or weird node for sub-expression {} in {:?}", - sub_ex.hir_id, expr - ); - return None; - } - }; - match self.tables.expr_ty_adjusted(&hir_node).kind { + match self.tables.expr_ty_adjusted(&sub_ex).kind { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); filter!(self.span_utils, ident.span); @@ -562,8 +551,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { hir::QPath::Resolved(_, path) => path.segments.last().unwrap(), hir::QPath::TypeRelative(_, segment) => segment, }; - match self.tables.expr_ty_adjusted(&hir_node).kind { - ty::Adt(def, _) if !def.is_enum() => { + match ty.kind { + ty::Adt(def, _) => { let sub_span = segment.ident.span; filter!(self.span_utils, sub_span); let span = self.span_from_span(sub_span); @@ -574,9 +563,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { })) } _ => { - // FIXME ty could legitimately be an enum, but then we will fail - // later if we try to look up the fields. - debug!("expected struct or union, found {:?}", ty); + debug!("expected adt, found {:?}", ty); None } } diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml index 4d57c6384dd..abce7359c0e 100644 --- a/src/librustc_session/Cargo.toml +++ b/src/librustc_session/Cargo.toml @@ -9,6 +9,7 @@ name = "rustc_session" path = "lib.rs" [dependencies] +bitflags = "1.2.1" getopts = "0.2" log = "0.4" rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 562f71e8e92..f77bf5ddefd 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -10,6 +10,7 @@ use crate::{early_error, early_warn, Session}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_target::spec::{Target, TargetTriple}; @@ -37,35 +38,55 @@ pub struct Config { pub ptr_width: u32, } -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub enum Sanitizer { - Address, - Leak, - Memory, - Thread, +bitflags! { + #[derive(Default, RustcEncodable, RustcDecodable)] + pub struct SanitizerSet: u8 { + const ADDRESS = 1 << 0; + const LEAK = 1 << 1; + const MEMORY = 1 << 2; + const THREAD = 1 << 3; + } } -impl fmt::Display for Sanitizer { +/// Formats a sanitizer set as a comma separated list of sanitizers' names. +impl fmt::Display for SanitizerSet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Sanitizer::Address => "address".fmt(f), - Sanitizer::Leak => "leak".fmt(f), - Sanitizer::Memory => "memory".fmt(f), - Sanitizer::Thread => "thread".fmt(f), + let mut first = true; + for s in *self { + let name = match s { + SanitizerSet::ADDRESS => "address", + SanitizerSet::LEAK => "leak", + SanitizerSet::MEMORY => "memory", + SanitizerSet::THREAD => "thread", + _ => panic!("unrecognized sanitizer {:?}", s), + }; + if !first { + f.write_str(",")?; + } + f.write_str(name)?; + first = false; } + Ok(()) } } -impl FromStr for Sanitizer { - type Err = (); - fn from_str(s: &str) -> Result<Sanitizer, ()> { - match s { - "address" => Ok(Sanitizer::Address), - "leak" => Ok(Sanitizer::Leak), - "memory" => Ok(Sanitizer::Memory), - "thread" => Ok(Sanitizer::Thread), - _ => Err(()), - } +impl IntoIterator for SanitizerSet { + type Item = SanitizerSet; + type IntoIter = std::vec::IntoIter<SanitizerSet>; + + fn into_iter(self) -> Self::IntoIter { + [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD] + .iter() + .copied() + .filter(|&s| self.contains(s)) + .collect::<Vec<_>>() + .into_iter() + } +} + +impl<CTX> HashStable<CTX> for SanitizerSet { + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.bits().hash_stable(ctx, hasher); } } @@ -726,10 +747,12 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } } } - if let Some(s) = &sess.opts.debugging_opts.sanitizer { + + for s in sess.opts.debugging_opts.sanitizer { let symbol = Symbol::intern(&s.to_string()); ret.insert((sym::sanitize, Some(symbol))); } + if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); } @@ -1995,7 +2018,7 @@ impl PpMode { crate mod dep_tracking { use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, - OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath, + OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, }; use crate::lint; @@ -2069,8 +2092,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(UnstableFeatures); impl_dep_tracking_hash_via_hash!(OutputTypes); impl_dep_tracking_hash_via_hash!(NativeLibKind); - impl_dep_tracking_hash_via_hash!(Sanitizer); - impl_dep_tracking_hash_via_hash!(Option<Sanitizer>); + impl_dep_tracking_hash_via_hash!(SanitizerSet); impl_dep_tracking_hash_via_hash!(CFGuard); impl_dep_tracking_hash_via_hash!(TargetTriple); impl_dep_tracking_hash_via_hash!(Edition); @@ -2085,7 +2107,6 @@ crate mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind)); impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); - impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer); impl<T1, T2> DepTrackingHash for (T1, T2) where diff --git a/src/librustc_session/filesearch.rs b/src/librustc_session/filesearch.rs index e98746231fb..5586b82b0ed 100644 --- a/src/librustc_session/filesearch.rs +++ b/src/librustc_session/filesearch.rs @@ -41,6 +41,10 @@ impl<'a> FileSearch<'a> { make_target_lib_path(self.sysroot, self.triple) } + pub fn get_selfcontained_lib_path(&self) -> PathBuf { + self.get_lib_path().join("self-contained") + } + pub fn search<F>(&self, mut pick: F) where F: FnMut(&SearchPathFile, PathKind) -> FileMatch, @@ -94,7 +98,7 @@ impl<'a> FileSearch<'a> { p.push(RUST_LIB_DIR); p.push(&self.triple); p.push("bin"); - vec![p] + vec![p.clone(), p.join("self-contained")] } } diff --git a/src/librustc_session/lib.rs b/src/librustc_session/lib.rs index 80b693fe1ab..be9d2e7be27 100644 --- a/src/librustc_session/lib.rs +++ b/src/librustc_session/lib.rs @@ -1,6 +1,9 @@ #![feature(crate_visibility_modifier)] #![feature(or_patterns)] +#[macro_use] +extern crate bitflags; + pub mod cgu_reuse_tracker; pub mod utils; #[macro_use] diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index ffb45793090..0dcbee08abe 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -88,6 +88,8 @@ pub struct Lint { /// `Some` if this lint is feature gated, otherwise `None`. pub feature_gate: Option<Symbol>, + + pub crate_level_only: bool, } /// Extra information for a future incompatibility lint. @@ -111,6 +113,7 @@ impl Lint { report_in_external_macro: false, future_incompatible: None, feature_gate: None, + crate_level_only: false, } } @@ -336,6 +339,7 @@ macro_rules! declare_tool_lint { future_incompatible: None, is_plugin: true, feature_gate: None, + crate_level_only: false, }; ); } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 58388bafbed..5deee6eb48e 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -17,6 +17,7 @@ declare_lint! { reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>", edition: None, }; + crate_level_only } declare_lint! { @@ -75,7 +76,8 @@ declare_lint! { declare_lint! { pub UNUSED_CRATE_DEPENDENCIES, Allow, - "crate dependencies that are never used" + "crate dependencies that are never used", + crate_level_only } declare_lint! { @@ -166,7 +168,8 @@ declare_lint! { declare_lint! { pub UNKNOWN_CRATE_TYPES, Deny, - "unknown crate type found in `#[crate_type]` directive" + "unknown crate type found in `#[crate_type]` directive", + crate_level_only } declare_lint! { @@ -339,7 +342,8 @@ declare_lint! { declare_lint! { pub ELIDED_LIFETIMES_IN_PATHS, Allow, - "hidden lifetime parameters in types are deprecated" + "hidden lifetime parameters in types are deprecated", + crate_level_only } declare_lint! { @@ -459,6 +463,7 @@ declare_lint! { reference: "issue #52234 <https://github.com/rust-lang/rust/issues/52234>", edition: None, }; + crate_level_only } declare_lint! { @@ -534,6 +539,16 @@ declare_lint! { @feature_gate = sym::unsafe_block_in_unsafe_fn; } +declare_lint! { + pub CENUM_IMPL_DROP_CAST, + Warn, + "a C-like enum implementing Drop is cast", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>", + edition: None, + }; +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -607,6 +622,7 @@ declare_lint_pass! { ASM_SUB_REGISTER, UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, + CENUM_IMPL_DROP_CAST, ] } diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index e822e79bf4f..6c6f27502b6 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -248,8 +248,7 @@ macro_rules! options { pub const parse_passes: &str = "a space-separated list of passes, or `all`"; pub const parse_panic_strategy: &str = "either `unwind` or `abort`"; pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`"; - pub const parse_sanitizer: &str = "one of: `address`, `leak`, `memory` or `thread`"; - pub const parse_sanitizer_list: &str = "comma separated list of sanitizers"; + pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`"; pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2"; pub const parse_cfguard: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; @@ -460,24 +459,15 @@ macro_rules! options { true } - fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool { - if let Some(Ok(s)) = v.map(str::parse) { - *slot = Some(s); - true - } else { - false - } - } - - fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool { + fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool { if let Some(v) = v { - for s in v.split(',').map(str::parse) { - if let Ok(s) = s { - if !slot.contains(&s) { - slot.push(s); - } - } else { - return false; + for s in v.split(',') { + *slot |= match s { + "address" => SanitizerSet::ADDRESS, + "leak" => SanitizerSet::LEAK, + "memory" => SanitizerSet::MEMORY, + "thread" => SanitizerSet::THREAD, + _ => return false, } } true @@ -889,6 +879,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "fix undefined behavior when a thread doesn't eventually make progress \ (such as entering an empty infinite loop) by inserting llvm.sideeffect \ (default: no)"), + instrument_coverage: bool = (false, parse_bool, [TRACKED], + "instrument the generated code with LLVM code region counters to \ + (in the future) generate coverage reports (experimental; default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], @@ -984,11 +977,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, // soon. run_dsymutil: bool = (true, parse_bool, [TRACKED], "if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"), - sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED], + sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], "enable origins tracking in MemorySanitizer"), - sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED], + sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "enable recovery for selected sanitizers"), saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED], "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 06d7d4f14d8..2ea312c42dc 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -1,7 +1,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; -use crate::config::{self, CrateType, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath}; +use crate::config::{self, CrateType, OutputType, PrintRequest, SanitizerSet, SwitchWithOptPath}; use crate::filesearch; use crate::lint; use crate::parse::ParseSess; @@ -650,14 +650,9 @@ impl Session { } pub fn fewer_names(&self) -> bool { let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) - || self.opts.output_types.contains_key(&OutputType::Bitcode); - - // Address sanitizer and memory sanitizer use alloca name when reporting an issue. - let more_names = match self.opts.debugging_opts.sanitizer { - Some(Sanitizer::Address) => true, - Some(Sanitizer::Memory) => true, - _ => more_names, - }; + || self.opts.output_types.contains_key(&OutputType::Bitcode) + // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); self.opts.debugging_opts.fewer_names || !more_names } @@ -1020,12 +1015,10 @@ impl Session { /// Checks if LLVM lifetime markers should be emitted. pub fn emit_lifetime_markers(&self) -> bool { - match self.opts.debugging_opts.sanitizer { - // AddressSanitizer uses lifetimes to detect use after scope bugs. - // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. - Some(Sanitizer::Address | Sanitizer::Memory) => true, - _ => self.opts.optimize != config::OptLevel::No, - } + self.opts.optimize != config::OptLevel::No + // AddressSanitizer uses lifetimes to detect use after scope bugs. + // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY) } } @@ -1356,33 +1349,44 @@ fn validate_commandline_args_with_session_available(sess: &Session) { ); } + const ASAN_SUPPORTED_TARGETS: &[&str] = &[ + "aarch64-fuchsia", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-fuchsia", + "x86_64-unknown-linux-gnu", + ]; + const LSAN_SUPPORTED_TARGETS: &[&str] = + &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; + const MSAN_SUPPORTED_TARGETS: &[&str] = + &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]; + const TSAN_SUPPORTED_TARGETS: &[&str] = + &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; + // Sanitizers can only be used on some tested platforms. - if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { - const ASAN_SUPPORTED_TARGETS: &[&str] = &[ - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin", - "x86_64-fuchsia", - "aarch64-fuchsia", - ]; - const TSAN_SUPPORTED_TARGETS: &[&str] = - &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"]; - const LSAN_SUPPORTED_TARGETS: &[&str] = - &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"]; - const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"]; - - let supported_targets = match *sanitizer { - Sanitizer::Address => ASAN_SUPPORTED_TARGETS, - Sanitizer::Thread => TSAN_SUPPORTED_TARGETS, - Sanitizer::Leak => LSAN_SUPPORTED_TARGETS, - Sanitizer::Memory => MSAN_SUPPORTED_TARGETS, + for s in sess.opts.debugging_opts.sanitizer { + let supported_targets = match s { + SanitizerSet::ADDRESS => ASAN_SUPPORTED_TARGETS, + SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS, + SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS, + SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS, + _ => panic!("unrecognized sanitizer {}", s), }; - if !supported_targets.contains(&&*sess.opts.target_triple.triple()) { sess.err(&format!( - "{:?}Sanitizer only works with the `{}` target", - sanitizer, - supported_targets.join("` or `") + "`-Zsanitizer={}` only works with targets: {}", + s, + supported_targets.join(", ") + )); + } + let conflicting = sess.opts.debugging_opts.sanitizer - s; + if !conflicting.is_empty() { + sess.err(&format!( + "`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", + s, conflicting, )); + // Don't report additional errors. + break; } } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index fdeb58b7b7a..970a2632592 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -240,6 +240,7 @@ symbols! { copy_closures, core, core_intrinsics, + count_code_region, crate_id, crate_in_paths, crate_local, @@ -345,6 +346,7 @@ symbols! { from_method, from_ok, from_usize, + from_trait, fundamental, future, Future, diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs index 1a536b6a429..7d117b77cf5 100644 --- a/src/librustc_symbol_mangling/v0.rs +++ b/src/librustc_symbol_mangling/v0.rs @@ -345,7 +345,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Never => "z", // Placeholders (should be demangled as `_`). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => "p", + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => "p", _ => "", }; @@ -367,7 +367,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { ty::Tuple(_) if ty.is_unit() => unreachable!(), // Placeholders, also handled as part of basic types. - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error => { + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { unreachable!() } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index dcf181cb59f..c79e9bb2890 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -809,25 +809,30 @@ pub enum Variants { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, - /// Enum-likes with more than one inhabited variant: for each case there is - /// a struct, and they all have space reserved for the discriminant. - /// For enums this is the sole field of the layout. + /// Enum-likes with more than one inhabited variant: each variant comes with + /// a *discriminant* (usually the same as the variant index but the user can + /// assign explicit discriminant values). That discriminant is encoded + /// as a *tag* on the machine. The layout of each variant is + /// a struct, and they all have space reserved for the tag. + /// For enums, the tag is the sole field of the layout. Multiple { - discr: Scalar, - discr_kind: DiscriminantKind, - discr_index: usize, + tag: Scalar, + tag_encoding: TagEncoding, + tag_field: usize, variants: IndexVec<VariantIdx, Layout>, }, } #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)] -pub enum DiscriminantKind { - /// Integer tag holding the discriminant value itself. - Tag, +pub enum TagEncoding { + /// The tag directly stores the discriminant, but possibly with a smaller layout + /// (so converting the tag to the discriminant can require sign extension). + Direct, /// Niche (values invalid for a type) encoding the discriminant: - /// the variant `dataful_variant` contains a niche at an arbitrary - /// offset (field `discr_index` of the enum), which for a variant with + /// Discriminant and variant index coincide. + /// The variant `dataful_variant` contains a niche at an arbitrary + /// offset (field `tag_field` of the enum), which for a variant with /// discriminant `d` is set to /// `(d - niche_variants.start).wrapping_add(niche_start)`. /// diff --git a/src/librustc_target/asm/hexagon.rs b/src/librustc_target/asm/hexagon.rs new file mode 100644 index 00000000000..d41941d0b4c --- /dev/null +++ b/src/librustc_target/asm/hexagon.rs @@ -0,0 +1,93 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Hexagon HexagonInlineAsmRegClass { + reg, + } +} + +impl HexagonInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + } + } +} + +def_regs! { + Hexagon HexagonInlineAsmReg HexagonInlineAsmRegClass { + r0: reg = ["r0"], + r1: reg = ["r1"], + r2: reg = ["r2"], + r3: reg = ["r3"], + r4: reg = ["r4"], + r5: reg = ["r5"], + r6: reg = ["r6"], + r7: reg = ["r7"], + r8: reg = ["r8"], + r9: reg = ["r9"], + r10: reg = ["r10"], + r11: reg = ["r11"], + r12: reg = ["r12"], + r13: reg = ["r13"], + r14: reg = ["r14"], + r15: reg = ["r15"], + r16: reg = ["r16"], + r17: reg = ["r17"], + r18: reg = ["r18"], + r19: reg = ["r19"], + r20: reg = ["r20"], + r21: reg = ["r21"], + r22: reg = ["r22"], + r23: reg = ["r23"], + r24: reg = ["r24"], + r25: reg = ["r25"], + r26: reg = ["r26"], + r27: reg = ["r27"], + r28: reg = ["r28"], + #error = ["r29", "sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["r30", "fr"] => + "the frame register cannot be used as an operand for inline asm", + #error = ["r31", "lr"] => + "the link register cannot be used as an operand for inline asm", + } +} + +impl HexagonInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + out.write_str(self.name()) + } + + pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {} +} diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index a18a4dbd3e2..834d7c6d381 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -148,12 +148,14 @@ macro_rules! types { mod aarch64; mod arm; +mod hexagon; mod nvptx; mod riscv; mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; +pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -167,6 +169,7 @@ pub enum InlineAsmArch { RiscV32, RiscV64, Nvptx64, + Hexagon, } impl FromStr for InlineAsmArch { @@ -181,6 +184,7 @@ impl FromStr for InlineAsmArch { "riscv32" => Ok(Self::RiscV32), "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), + "hexagon" => Ok(Self::Hexagon), _ => Err(()), } } @@ -203,6 +207,7 @@ pub enum InlineAsmReg { AArch64(AArch64InlineAsmReg), RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), + Hexagon(HexagonInlineAsmReg), } impl InlineAsmReg { @@ -212,6 +217,7 @@ impl InlineAsmReg { Self::Arm(r) => r.name(), Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), + Self::Hexagon(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::Arm(r) => InlineAsmRegClass::Arm(r.reg_class()), Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), + Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), } } @@ -246,6 +253,9 @@ impl InlineAsmReg { InlineAsmArch::Nvptx64 => { Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?) } + InlineAsmArch::Hexagon => { + Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?) + } }) } @@ -262,6 +272,7 @@ impl InlineAsmReg { Self::Arm(r) => r.emit(out, arch, modifier), Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), + Self::Hexagon(r) => r.emit(out, arch, modifier), } } @@ -271,6 +282,7 @@ impl InlineAsmReg { Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))), Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), + Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), } } } @@ -292,6 +304,7 @@ pub enum InlineAsmRegClass { AArch64(AArch64InlineAsmRegClass), RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), + Hexagon(HexagonInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), + Self::Hexagon(r) => r.name(), } } @@ -315,6 +329,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), + Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), } } @@ -335,6 +350,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.suggest_modifier(arch, ty), Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), + Self::Hexagon(r) => r.suggest_modifier(arch, ty), } } @@ -351,6 +367,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.default_modifier(arch), Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), + Self::Hexagon(r) => r.default_modifier(arch), } } @@ -366,6 +383,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.supported_types(arch), Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), + Self::Hexagon(r) => r.supported_types(arch), } } @@ -384,6 +402,9 @@ impl InlineAsmRegClass { Self::RiscV(RiscVInlineAsmRegClass::parse(arch, name)?) } InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Hexagon => { + Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) + } }) }) } @@ -397,6 +418,7 @@ impl InlineAsmRegClass { Self::AArch64(r) => r.valid_modifiers(arch), Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), + Self::Hexagon(r) => r.valid_modifiers(arch), } } } @@ -541,5 +563,10 @@ pub fn allocatable_registers( nvptx::fill_reg_map(arch, has_feature, &mut map); map } + InlineAsmArch::Hexagon => { + let mut map = hexagon::regclass_map(); + hexagon::fill_reg_map(arch, has_feature, &mut map); + map + } } } diff --git a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs b/src/librustc_target/spec/riscv32i_unknown_none_elf.rs index aade1e70823..d7b3e7e1530 100644 --- a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32i_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs index e2990eeb826..b93b6fcf800 100644 --- a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs index 55a4d58dfcc..a16e7e31c66 100644 --- a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs @@ -25,7 +25,6 @@ pub fn target() -> TargetResult { relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs index 7376a14e951..e5147a12ed3 100644 --- a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs @@ -26,7 +26,6 @@ pub fn target() -> TargetResult { code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs index a3b0eb5334f..dc056b55b38 100644 --- a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs +++ b/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs @@ -26,7 +26,6 @@ pub fn target() -> TargetResult { code_model: Some(CodeModel::Medium), emit_debug_gdb_scripts: false, abi_blacklist: super::riscv_base::abi_blacklist(), - eliminate_frame_pointer: false, ..Default::default() }, }) diff --git a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs index 34c628e8f67..3a22290da68 100644 --- a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs @@ -6,6 +6,7 @@ pub fn target() -> TargetResult { base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.stack_probes = true; + base.static_position_independent_executables = true; Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index d53a0ec9ef8..adccdd0b261 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -941,7 +941,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().types.err + self.tcx().ty_error() } } } @@ -974,7 +974,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty }) + self.tcx().const_error(ct.ty) } } } @@ -1002,7 +1002,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { tcx, ty_op: |ty| { if ty.references_error() { - return tcx.types.err; + return tcx.ty_error(); } else if let ty::Opaque(def_id, substs) = ty.kind { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose diff --git a/src/librustc_trait_selection/traits/coherence.rs b/src/librustc_trait_selection/traits/coherence.rs index 85c2f9246af..706cbf058b7 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/src/librustc_trait_selection/traits/coherence.rs @@ -565,7 +565,7 @@ fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> } } - ty::Error => None, + ty::Error(_) => None, ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => { bug!("ty_is_local invoked on unexpected type: {:?}", ty) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index d31e04cffd5..060877f80ad 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; @@ -25,7 +26,7 @@ use rustc_middle::ty::{ TypeFoldable, WithConstness, }; use rustc_session::DiagnosticMessageId; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP}; use std::fmt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1246,7 +1247,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Generator(..) => Some(18), ty::Foreign(..) => Some(19), ty::GeneratorWitness(..) => Some(20), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -1695,36 +1696,95 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, obligation: &PredicateObligation<'tcx>, ) { - if let ( - ty::PredicateKind::Trait(pred, _), - ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (obligation.predicate.kind(), &obligation.cause.code) - { - if let (Some(generics), true) = ( - self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), - ) { - for param in generics.params { - if param.span == *span - && !param.bounds.iter().any(|bound| { - bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) - == self.tcx.lang_items().sized_trait() - }) - { - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " +"), - }; - err.span_suggestion_verbose( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), - Applicability::MachineApplicable, + let (pred, item_def_id, span) = + match (obligation.predicate.kind(), &obligation.cause.code.peel_derives()) { + ( + ty::PredicateKind::Trait(pred, _), + ObligationCauseCode::BindingObligation(item_def_id, span), + ) => (pred, item_def_id, span), + _ => return, + }; + + let node = match ( + self.tcx.hir().get_if_local(*item_def_id), + Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), + ) { + (Some(node), true) => node, + _ => return, + }; + let generics = match node.generics() { + Some(generics) => generics, + None => return, + }; + for param in generics.params { + if param.span != *span + || param.bounds.iter().any(|bound| { + bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id()) + == self.tcx.lang_items().sized_trait() + }) + { + continue; + } + match node { + hir::Node::Item( + item + @ + hir::Item { + kind: + hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..), + .. + }, + ) => { + // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a + // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);` + // is not. + let mut visitor = FindTypeParam { + param: param.name.ident().name, + invalid_spans: vec![], + nested: false, + }; + visitor.visit_item(item); + if !visitor.invalid_spans.is_empty() { + let mut multispan: MultiSpan = param.span.into(); + multispan.push_span_label( + param.span, + format!("this could be changed to `{}: ?Sized`...", param.name.ident()), + ); + for sp in visitor.invalid_spans { + multispan.push_span_label( + sp, + format!( + "...if indirection was used here: `Box<{}>`", + param.name.ident(), + ), + ); + } + err.span_help( + multispan, + &format!( + "you could relax the implicit `Sized` bound on `{T}` if it were \ + used through indirection like `&{T}` or `Box<{T}>`", + T = param.name.ident(), + ), ); return; } } + _ => {} } + let (span, separator) = match param.bounds { + [] => (span.shrink_to_hi(), ":"), + [.., bound] => (bound.span().shrink_to_hi(), " +"), + }; + err.span_suggestion_verbose( + span, + "consider relaxing the implicit `Sized` restriction", + format!("{} ?Sized", separator), + Applicability::MachineApplicable, + ); + return; } } @@ -1744,6 +1804,50 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } } +/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting +/// `param: ?Sized` would be a valid constraint. +struct FindTypeParam { + param: rustc_span::Symbol, + invalid_spans: Vec<Span>, + nested: bool, +} + +impl<'v> Visitor<'v> for FindTypeParam { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // We collect the spans of all uses of the "bare" type param, like in `field: T` or + // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be + // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized` + // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases + // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors + // in that case should make what happened clear enough. + match ty.kind { + hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {} + hir::TyKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].ident.name == self.param => + { + if !self.nested { + self.invalid_spans.push(ty.span); + } + } + hir::TyKind::Path(_) => { + let prev = self.nested; + self.nested = true; + hir::intravisit::walk_ty(self, ty); + self.nested = prev; + } + _ => { + hir::intravisit::walk_ty(self, ty); + } + } + } +} + pub fn recursive_type_with_infinite_size_error( tcx: TyCtxt<'tcx>, type_def_id: DefId, diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 8796cfb5216..dfd7dac72d8 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -948,7 +948,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty| { let ty = self.resolve_vars_if_possible(&ty); same &= - ty.kind != ty::Error + !matches!(ty.kind, ty::Error(_)) && last_ty.map_or(true, |last_ty| { // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes // *after* in the dependency graph. @@ -1992,8 +1992,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// Collect all the returned expressions within the input expression. /// Used to point at the return spans when we want to suggest some change to them. #[derive(Default)] -struct ReturnsVisitor<'v> { - returns: Vec<&'v hir::Expr<'v>>, +pub struct ReturnsVisitor<'v> { + pub returns: Vec<&'v hir::Expr<'v>>, in_block_tail: bool, } diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 9492c3c3409..19640542547 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -24,6 +24,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::{FnOnceTraitLangItem, GeneratorTraitLangItem}; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::util::IntTypeExt; @@ -360,7 +361,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // handle normalization within binders because // otherwise we wind up a need to normalize when doing // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but + // obligation like `for<'a> T::B: Fn(&'a i32)`), but // we can't normalize with bound regions in scope. So // far now we just ignore binders but only normalize // if all bound regions are gone (and then we still @@ -784,7 +785,7 @@ struct Progress<'tcx> { impl<'tcx> Progress<'tcx> { fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.types.err, obligations: vec![] } + Progress { ty: tcx.ty_error(), obligations: vec![] } } fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { @@ -1085,7 +1086,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) - | ty::Error => false, + | ty::Error(_) => false, } } super::ImplSourceParam(..) => { @@ -1146,7 +1147,7 @@ fn confirm_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - match candidate { + let mut progress = match candidate { ProjectionTyCandidate::ParamEnv(poly_projection) | ProjectionTyCandidate::TraitDef(poly_projection) => { confirm_param_env_candidate(selcx, obligation, poly_projection) @@ -1155,7 +1156,16 @@ fn confirm_candidate<'cx, 'tcx>( ProjectionTyCandidate::Select(impl_source) => { confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source) } + }; + // When checking for cycle during evaluation, we compare predicates with + // "syntactic" equality. Since normalization generally introduces a type + // with new region variables, we need to resolve them to existing variables + // when possible for this to work. See `auto-trait-projection-recursion.rs` + // for a case where this matters. + if progress.ty.has_infer_regions() { + progress.ty = OpportunisticRegionResolver::new(selcx.infcx()).fold_ty(progress.ty); } + progress } fn confirm_select_candidate<'cx, 'tcx>( @@ -1440,8 +1450,8 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation, poly_cache_entry, e, ); debug!("confirm_param_env_candidate: {}", msg); - infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); - Progress { ty: infcx.tcx.types.err, obligations: vec![] } + let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); + Progress { ty: err, obligations: vec![] } } } } @@ -1460,7 +1470,7 @@ fn confirm_impl_candidate<'cx, 'tcx>( let param_env = obligation.param_env; let assoc_ty = match assoc_ty_def(selcx, impl_def_id, assoc_item_id) { Ok(assoc_ty) => assoc_ty, - Err(ErrorReported) => return Progress { ty: tcx.types.err, obligations: nested }, + Err(ErrorReported) => return Progress { ty: tcx.ty_error(), obligations: nested }, }; if !assoc_ty.item.defaultness.has_value() { @@ -1472,16 +1482,18 @@ fn confirm_impl_candidate<'cx, 'tcx>( "confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.item.ident, obligation.predicate ); - return Progress { ty: tcx.types.err, obligations: nested }; + return Progress { ty: tcx.ty_error(), obligations: nested }; } let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node); let ty = tcx.type_of(assoc_ty.item.def_id); if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { - tcx.sess - .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); - Progress { ty: tcx.types.err, obligations: nested } + let err = tcx.ty_error_with_message( + DUMMY_SP, + "impl item and trait item have different parameter counts", + ); + Progress { ty: err, obligations: nested } } else { Progress { ty: ty.subst(tcx, substs), obligations: nested } } diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/src/librustc_trait_selection/traits/query/dropck_outlives.rs index 856a2111fc8..d07c95270e0 100644 --- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs +++ b/src/librustc_trait_selection/traits/query/dropck_outlives.rs @@ -101,7 +101,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Ref(..) | ty::Str | ty::Foreign(..) - | ty::Error => true, + | ty::Error(_) => true, // [T; N] and [T] have same properties as T. ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 3e7749356d2..ca49ff5884f 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -145,7 +145,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // handle normalization within binders because // otherwise we wind up a need to normalize when doing // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but + // obligation like `for<'a> T::B: Fn(&'a i32)`), but // we can't normalize with bound regions in scope. So // far now we just ignore binders but only normalize // if all bound regions are gone (and then we still diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index f8d26c06a21..50c04e8fc34 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -553,14 +553,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// /// Here is an example. Imagine we have a closure expression /// and we desugared it so that the type of the expression is - /// `Closure`, and `Closure` expects an int as argument. Then it + /// `Closure`, and `Closure` expects `i32` as argument. Then it /// is "as if" the compiler generated this impl: /// - /// impl Fn(int) for Closure { ... } + /// impl Fn(i32) for Closure { ... } /// - /// Now imagine our obligation is `Fn(usize) for Closure`. So far + /// Now imagine our obligation is `Closure: Fn(usize)`. So far /// we have matched the self type `Closure`. At this point we'll - /// compare the `int` to `usize` and generate an error. + /// compare the `i32` to `usize` and generate an error. /// /// Note that this checking occurs *after* the impl has selected, /// because these output type parameters should not affect the diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 7ebf30f61c0..7dc8c2cf4cd 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -1569,7 +1569,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never - | ty::Error => { + | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) } @@ -1613,7 +1613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Infer(ty::FloatVar(_)) | ty::FnDef(..) | ty::FnPtr(_) - | ty::Error => Where(ty::Binder::dummy(Vec::new())), + | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())), ty::Uint(_) | ty::Int(_) @@ -1690,7 +1690,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnDef(..) | ty::FnPtr(_) | ty::Str - | ty::Error + | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never | ty::Char => Vec::new(), @@ -1754,27 +1754,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec<PredicateObligation<'tcx>> { // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we + // regions. For example, `for<'a> Foo<&'a i32> : Copy` would + // yield a type like `for<'a> &'a i32`. In general, we // maintain the invariant that we never manipulate bound // regions, so we have to process these bound regions somehow. // // The strategy is to: // // 1. Instantiate those regions to placeholder regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` + // `for<'a> &'a i32` becomes `&0 i32`. + // 2. Produce something like `&'0 i32 : Copy` + // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy` types - .skip_binder() + .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - // binder moved -\ let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ self.infcx.commit_unconditionally(|_| { - let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); + let (placeholder_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, mut obligations } = ensure_sufficient_stack(|| { project::normalize_with_depth( @@ -1782,10 +1781,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env, cause.clone(), recursion_depth, - &skol_ty, + &placeholder_ty, ) }); - let skol_obligation = predicate_for_trait_def( + let placeholder_obligation = predicate_for_trait_def( self.tcx(), param_env, cause.clone(), @@ -1794,7 +1793,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { normalized_ty, &[], ); - obligations.push(skol_obligation); + obligations.push(placeholder_obligation); obligations }) }) @@ -1844,9 +1843,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let (skol_obligation, placeholder_map) = + let (placeholder_obligation, placeholder_map) = self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let skol_obligation_trait_ref = skol_obligation.trait_ref; + let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); @@ -1865,14 +1864,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!( "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref + impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})", + impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref ); let InferOk { obligations, .. } = self .infcx .at(&obligation.cause, obligation.param_env) - .eq(skol_obligation_trait_ref, impl_trait_ref) + .eq(placeholder_obligation_trait_ref, impl_trait_ref) .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; nested_obligations.extend(obligations); diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/src/librustc_trait_selection/traits/specialize/mod.rs index 2b596be9542..42901102c10 100644 --- a/src/librustc_trait_selection/traits/specialize/mod.rs +++ b/src/librustc_trait_selection/traits/specialize/mod.rs @@ -130,7 +130,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // We determine whether there's a subset relationship by: // - // - skolemizing impl1, + // - replacing bound vars with placeholders in impl1, // - assuming the where clauses for impl1, // - instantiating impl2 with fresh inference variables, // - unifying, diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index c4deb639140..201edf27a65 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -219,7 +219,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); } - ty::Error => { + ty::Error(_) => { self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. diff --git a/src/librustc_trait_selection/traits/util.rs b/src/librustc_trait_selection/traits/util.rs index 8b5b4128e66..d3484b8af89 100644 --- a/src/librustc_trait_selection/traits/util.rs +++ b/src/librustc_trait_selection/traits/util.rs @@ -302,7 +302,7 @@ pub fn get_vtable_index_of_object_method<N>( ) -> usize { // Count number of methods preceding the one we are selecting and // add them to the total offset. - // Skip over associated types and constants. + // Skip over associated types and constants, as those aren't stored in the vtable. let mut entries = object.vtable_base; for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()).in_definition_order() { if trait_item.def_id == method_def_id { diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 90a9b876d8d..1825c159ff3 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -392,7 +392,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { )); } } - ty::ConstKind::Error + ty::ConstKind::Error(_) | ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => { @@ -412,7 +412,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { | ty::Int(..) | ty::Uint(..) | ty::Float(..) - | ty::Error + | ty::Error(_) | ty::Str | ty::GeneratorWitness(..) | ty::Never diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index 9530b07e47c..c9dd06e9f1b 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -168,7 +168,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi ty::PredicateKind::WellFormed(arg) => match arg.unpack() { GenericArgKind::Type(ty) => match ty.kind { // These types are always WF. - ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { + ty::Str | ty::Placeholder(..) | ty::Error(_) | ty::Never => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } @@ -376,7 +376,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> { }) .intern(interner), Infer(_infer) => unimplemented!(), - Error => unimplemented!(), + Error(_) => unimplemented!(), } } } diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 11c48559bd6..6339f8288d5 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -271,7 +271,7 @@ fn dtorck_constraint_for_ty<'tcx>( constraints.dtorck_types.push(ty); } - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => { + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { // By the time this code runs, all type variables ought to // be fully resolved. return Err(NoSolution); diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index 99094246a63..cf70a845af0 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -20,7 +20,7 @@ fn sized_constraint_for_ty<'tcx>( Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], - Str | Dynamic(..) | Slice(_) | Foreign(..) | Error | GeneratorWitness(..) => { + Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => { // these are never sized - return the target type vec![ty] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 267f3d9f3ef..33d57e25711 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -819,7 +819,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { inferred_params.push(ty.span); - tcx.types.err.into() + tcx.ty_error().into() } else { self.ast_ty_to_ty(&ty).into() } @@ -845,7 +845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // careful! if default_needs_object_self(param) { missing_type_params.push(param.name.to_string()); - tcx.types.err.into() + tcx.ty_error().into() } else { // This is a default type parameter. self.normalize_ty( @@ -865,7 +865,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ty_infer(param, span).into() } else { // We've already errored above about the mismatch. - tcx.types.err.into() + tcx.ty_error().into() } } GenericParamDefKind::Const => { @@ -876,7 +876,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ct_infer(ty, Some(param), span).into() } else { // We've already errored above about the mismatch. - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty }).into() + tcx.const_error(ty).into() } } } @@ -1394,13 +1394,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // That is, consider this case: // // ``` - // trait SubTrait: SuperTrait<int> { } + // trait SubTrait: SuperTrait<i32> { } // trait SuperTrait<A> { type T; } // // ... B: SubTrait<T = foo> ... // ``` // - // We want to produce `<B as SuperTrait<int>>::T == foo`. + // We want to produce `<B as SuperTrait<i32>>::T == foo`. // Find any late-bound regions declared in `ty` that are not // declared in the trait-ref. These are not well-formed. @@ -1607,7 +1607,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "at least one trait is required for an object type" ) .emit(); - return tcx.types.err; + return tcx.ty_error(); } // Check that there are no gross object safety violations; @@ -1624,7 +1624,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &object_safety_violations[..], ) .emit(); - return tcx.types.err; + return tcx.ty_error(); } } @@ -2434,7 +2434,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &path_str, item_segment.ident.name, ); - return tcx.types.err; + return tcx.ty_error(); }; debug!("qpath_to_ty: self_type={:?}", self_ty); @@ -2787,12 +2787,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::PrimTy::Int(it) => tcx.mk_mach_int(it), hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit), hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft), - hir::PrimTy::Str => tcx.mk_str(), + hir::PrimTy::Str => tcx.types.str_, } } Res::Err => { self.set_tainted_by_errors(); - self.tcx().types.err + self.tcx().ty_error() } _ => span_bug!(span, "unexpected resolution: {:?}", path.res), } @@ -2860,7 +2860,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false) .map(|(ty, _, _)| ty) - .unwrap_or(tcx.types.err) + .unwrap_or_else(|_| tcx.ty_error()) } hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); @@ -2878,7 +2878,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .span_label(ast_ty.span, "reserved keyword") .emit(); - tcx.types.err + tcx.ty_error() } hir::TyKind::Infer => { // Infer also appears as the type of arguments or return @@ -2887,7 +2887,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // handled specially and will not descend into this routine. self.ty_infer(None, ast_ty.span) } - hir::TyKind::Err => tcx.types.err, + hir::TyKind::Err => tcx.ty_error(), }; debug!("ast_ty_to_ty: result_ty={:?}", result_ty); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index fb139b5033b..9e23f5df3c6 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && i != 0 && self.if_fallback_coercion(expr.span, &arms[0].body, &mut coercion) { - tcx.types.err + tcx.ty_error() } 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) diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 73d4e2b7820..2570025959c 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -1,5 +1,5 @@ use super::method::MethodCallee; -use super::{FnCtxt, Needs, PlaceOp}; +use super::{FnCtxt, PlaceOp}; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -170,14 +170,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } /// Returns the adjustment steps. - pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> { - fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs)) + pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec<Adjustment<'tcx>> { + fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx)) } pub fn adjust_steps_as_infer_ok( &self, fcx: &FnCtxt<'a, 'tcx>, - needs: Needs, ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> { let mut obligations = vec![]; let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty)); @@ -186,7 +185,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { .iter() .map(|&(source, kind)| { if let AutoderefKind::Overloaded = kind { - fcx.try_overloaded_deref(self.span, source, needs).and_then( + fcx.try_overloaded_deref(self.span, source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); if let ty::Ref(region, _, mutbl) = method.sig.output().kind { @@ -266,8 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, base_ty: Ty<'tcx>, - needs: Needs, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref) + self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index aa316105f7f..fe200a0ad2a 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -1,6 +1,6 @@ use super::autoderef::Autoderef; use super::method::MethodCallee; -use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag}; +use super::{Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; @@ -115,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.kind { ty::FnDef(..) | ty::FnPtr(_) => { - let adjustments = autoderef.adjust_steps(self, Needs::None); + let adjustments = autoderef.adjust_steps(self); self.apply_adjustments(callee_expr, adjustments); return Some(CallStep::Builtin(adjusted_ty)); } @@ -135,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &closure_sig, ) .0; - let adjustments = autoderef.adjust_steps(self, Needs::None); + let adjustments = autoderef.adjust_steps(self); self.record_deferred_call_resolution( def_id, DeferredCallResolution { @@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs)) .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None)) .map(|(autoref, method)| { - let mut adjustments = autoderef.adjust_steps(self, Needs::None); + let mut adjustments = autoderef.adjust_steps(self); adjustments.extend(autoref); self.apply_adjustments(callee_expr, adjustments); CallStep::Overloaded(method) @@ -220,21 +220,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = self.register_infer_ok_obligations(ok); let mut autoref = None; if borrow { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind { - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded function call ops. - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; - autoref = Some(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target: method.sig.inputs()[0], - }); - } + // Check for &self vs &mut self in the method signature. Since this is either + // the Fn or FnMut trait, it should be one of those. + let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind + { + (r, mutbl) + } else { + span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); + }; + + let mutbl = match mutbl { + hir::Mutability::Not => AutoBorrowMutability::Not, + hir::Mutability::Mut => AutoBorrowMutability::Mut { + // For initial two-phase borrow + // deployment, conservatively omit + // overloaded function call ops. + allow_two_phase_borrow: AllowTwoPhase::No, + }, + }; + autoref = Some(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), + target: method.sig.inputs()[0], + }); } return Some((autoref, method)); } @@ -383,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ( ty::Binder::bind(self.tcx.mk_fn_sig( self.err_args(arg_exprs.len()).into_iter(), - self.tcx.types.err, + self.tcx.ty_error(), false, hir::Unsafety::Normal, abi::Abi::Rust, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 46d6706cbf4..1ea7bf25ef2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -43,6 +43,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable}; use rustc_session::lint; use rustc_session::Session; +use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; @@ -135,7 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Generator(..) | ty::Adt(..) | ty::Never - | ty::Error => { + | ty::Error(_) => { self.tcx .sess .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t)); @@ -333,10 +334,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { "only `u8` can be cast as `char`, not `{}`", self.expr_ty ) + .span_label(self.span, "invalid cast") .emit(); } CastError::NonScalar => { - type_error_struct!( + let mut err = type_error_struct!( fcx.tcx.sess, self.span, self.expr_ty, @@ -344,12 +346,75 @@ impl<'a, 'tcx> CastCheck<'tcx> { "non-primitive cast: `{}` as `{}`", self.expr_ty, fcx.ty_to_string(self.cast_ty) - ) - .note( - "an `as` expression can only be used to convert between \ - primitive types. Consider using the `From` trait", - ) - .emit(); + ); + let mut sugg = None; + if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind { + if fcx + .try_coerce( + self.expr, + fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), + self.cast_ty, + AllowTwoPhase::No, + ) + .is_ok() + { + sugg = Some(format!("&{}", mutbl.prefix_str())); + } + } + if let Some(sugg) = sugg { + err.span_label(self.span, "invalid cast"); + err.span_suggestion_verbose( + self.expr.span.shrink_to_lo(), + "borrow the value for the cast to be valid", + sugg, + Applicability::MachineApplicable, + ); + } else if !matches!( + self.cast_ty.kind, + ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) + ) { + let mut label = true; + // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion: + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { + let ty = fcx.resolve_vars_if_possible(&self.cast_ty); + // Erase regions to avoid panic in `prove_value` when calling + // `type_implements_trait`. + let ty = fcx.tcx.erase_regions(&ty); + let expr_ty = fcx.resolve_vars_if_possible(&self.expr_ty); + let expr_ty = fcx.tcx.erase_regions(&expr_ty); + let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]); + // Check for infer types because cases like `Option<{integer}>` would + // panic otherwise. + if !expr_ty.has_infer_types() + && fcx.tcx.type_implements_trait(( + from_trait, + ty, + ty_params, + fcx.param_env, + )) + { + label = false; + err.span_suggestion( + self.span, + "consider using the `From` trait instead", + format!("{}::from({})", self.cast_ty, snippet), + Applicability::MaybeIncorrect, + ); + } + } + } + let msg = "an `as` expression can only be used to convert between primitive \ + types or to coerce to a specific trait object"; + if label { + err.span_label(self.span, msg); + } else { + err.note(msg); + } + } else { + err.span_label(self.span, "invalid cast"); + } + err.emit(); } CastError::SizedUnsizedCast => { use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic}; @@ -370,21 +435,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let mut err = struct_span_err!( fcx.tcx.sess, - self.span, + if unknown_cast_to { self.cast_span } else { self.span }, E0641, "cannot cast {} a pointer of an unknown kind", if unknown_cast_to { "to" } else { "from" } ); - err.note( - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); if unknown_cast_to { - err.span_suggestion_short( - self.cast_span, - "consider giving more type information", - String::new(), - Applicability::Unspecified, + err.span_label(self.cast_span, "needs more type information"); + err.note( + "the type information given here is insufficient to check whether \ + the pointer cast is valid", + ); + } else { + err.span_label( + self.span, + "the type information given here is insufficient to check whether \ + the pointer cast is valid", ); } err.emit(); @@ -438,13 +504,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { Ok(s) => { err.span_suggestion( self.cast_span, - "try casting to a `Box` instead", + "you can cast to a `Box` instead", format!("Box<{}>", s), Applicability::MachineApplicable, ); } Err(_) => { - err.span_help(self.cast_span, &format!("did you mean `Box<{}>`?", tstr)); + err.span_help( + self.cast_span, + &format!("you might have meant `Box<{}>`", tstr), + ); } } } @@ -609,7 +678,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // prim -> prim - (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast), + (Int(CEnum), Int(_)) => { + self.cenum_impl_drop_lint(fcx); + Ok(CastKind::EnumCast) + } (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), @@ -706,11 +778,13 @@ impl<'a, 'tcx> CastCheck<'tcx> { // Coerce to a raw pointer so that we generate AddressOf in MIR. let array_ptr_type = fcx.tcx.mk_ptr(m_expr); fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No) - .unwrap_or_else(|_| bug!( + .unwrap_or_else(|_| { + bug!( "could not cast from reference to array to pointer to array ({:?} to {:?})", self.expr_ty, array_ptr_type, - )); + ) + }); // this will report a type mismatch if needed fcx.demand_eqtype(self.span, ety, m_cast.ty); @@ -740,6 +814,25 @@ impl<'a, 'tcx> CastCheck<'tcx> { Err(err) => Err(err), } } + + fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + if let ty::Adt(d, _) = self.expr_ty.kind { + if d.has_dtor(fcx.tcx) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::CENUM_IMPL_DROP_CAST, + self.expr.hir_id, + self.span, + |err| { + err.build(&format!( + "cannot cast enum `{}` into integer `{}` because it implements `Drop`", + self.expr_ty, self.cast_ty + )) + .emit(); + }, + ); + } + } + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 206619588c7..6d09ddc925f 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -700,7 +700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let supplied_arguments = decl.inputs.iter().map(|a| { // Convert the types that the user supplied (if any), but ignore them. astconv.ast_ty_to_ty(a); - self.tcx.types.err + self.tcx.ty_error() }); if let hir::FnRetTy::Return(ref output) = decl.output { @@ -709,7 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, - self.tcx.types.err, + self.tcx.ty_error(), decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 15ec92568fb..15d210b89b6 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -10,48 +10,33 @@ //! //! Note that if we are expecting a reference, we will *reborrow* //! even if the argument provided was already a reference. This is -//! useful for freezing mut/const things (that is, when the expected is &T -//! but you have &const T or &mut T) and also for avoiding the linearity +//! useful for freezing mut things (that is, when the expected type is &T +//! but you have &mut T) and also for avoiding the linearity //! of mut things (when the expected is &mut T and you have &mut T). See -//! the various `src/test/ui/coerce-reborrow-*.rs` tests for +//! the various `src/test/ui/coerce/*.rs` tests for //! examples of where this is useful. //! //! ## Subtle note //! -//! When deciding what type coercions to consider, we do not attempt to -//! resolve any type variables we may encounter. This is because `b` -//! represents the expected type "as the user wrote it", meaning that if -//! the user defined a generic function like +//! When infering the generic arguments of functions, the argument +//! order is relevant, which can lead to the following edge case: //! -//! fn foo<A>(a: A, b: A) { ... } +//! ```rust +//! fn foo<T>(a: T, b: T) { +//! // ... +//! } //! -//! and then we wrote `foo(&1, @2)`, we will not auto-borrow -//! either argument. In older code we went to some lengths to -//! resolve the `b` variable, which could mean that we'd -//! auto-borrow later arguments but not earlier ones, which -//! seems very confusing. +//! foo(&7i32, &mut 7i32); +//! // This compiles, as we first infer `T` to be `&i32`, +//! // and then coerce `&mut 7i32` to `&7i32`. //! -//! ## Subtler note -//! -//! However, right now, if the user manually specifies the -//! values for the type variables, as so: -//! -//! foo::<&int>(@1, @2) -//! -//! then we *will* auto-borrow, because we can't distinguish this from a -//! function that declared `&int`. This is inconsistent but it's easiest -//! at the moment. The right thing to do, I think, is to consider the -//! *unsubstituted* type when deciding whether to auto-borrow, but the -//! *substituted* type when considering the bounds and so forth. But most -//! of our methods don't give access to the unsubstituted type, and -//! rightly so because they'd be error-prone. So maybe the thing to do is -//! to actually determine the kind of coercions that should occur -//! separately and pass them in. Or maybe it's ok as is. Anyway, it's -//! sort of a minor point so I've opted to leave it for later -- after all, -//! we may want to adjust precisely when coercions occur. +//! foo(&mut 7i32, &7i32); +//! // This does not compile, as we first infer `T` to be `&mut i32` +//! // and are then unable to coerce `&7i32` to `&mut i32`. +//! ``` use crate::astconv::AstConv; -use crate::check::{FnCtxt, Needs}; +use crate::check::FnCtxt; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -96,6 +81,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>; +/// Coercing a mutable reference to an immutable works, while +/// coercing `&T` to `&mut T` should be forbidden. fn coerce_mutbls<'tcx>( from_mutbl: hir::Mutability, to_mutbl: hir::Mutability, @@ -162,7 +149,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return success(vec![], self.fcx.tcx.types.err, vec![]); + return success(vec![], self.fcx.tcx.ty_error(), vec![]); } if a.is_never() { @@ -421,9 +408,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return success(vec![], ty, obligations); } - let needs = Needs::maybe_mut_place(mutbl_b); let InferOk { value: mut adjustments, obligations: o } = - autoderef.adjust_steps_as_infer_ok(self, needs); + autoderef.adjust_steps_as_infer_ok(self); obligations.extend(o); obligations.extend(autoderef.into_obligations()); @@ -864,7 +850,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (adjustments, _) = self.register_infer_ok_obligations(ok); self.apply_adjustments(expr, adjustments); - Ok(if expr_ty.references_error() { self.tcx.types.err } else { target }) + Ok(if expr_ty.references_error() { self.tcx.ty_error() } else { target }) } /// Same as `try_coerce()`, but without side-effects. @@ -1239,7 +1225,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // If we see any error types, just propagate that error // upwards. if expression_ty.references_error() || self.merged_ty().references_error() { - self.final_ty = Some(fcx.tcx.types.err); + self.final_ty = Some(fcx.tcx.ty_error()); return; } @@ -1396,7 +1382,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err.emit_unless(assign_to_bool || unsized_return); - self.final_ty = Some(fcx.tcx.types.err); + self.final_ty = Some(fcx.tcx.ty_error()); } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b39cfcb3775..1d47e64630c 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -91,14 +91,14 @@ fn compare_predicate_entailment<'tcx>( // This code is best explained by example. Consider a trait: // - // trait Trait<'t,T> { - // fn method<'a,M>(t: &'t T, m: &'a M) -> Self; + // trait Trait<'t, T> { + // fn method<'a, M>(t: &'t T, m: &'a M) -> Self; // } // // And an impl: // // impl<'i, 'j, U> Trait<'j, &'i U> for Foo { - // fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo; + // fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo; // } // // We wish to decide if those two method types are compatible. @@ -116,9 +116,9 @@ fn compare_predicate_entailment<'tcx>( // regions (Note: but only early-bound regions, i.e., those // declared on the impl or used in type parameter bounds). // - // impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 } + // impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 } // - // Now we can apply skol_substs to the type of the impl method + // Now we can apply placeholder_substs to the type of the impl method // to yield a new function type in terms of our fresh, placeholder // types: // @@ -127,11 +127,11 @@ fn compare_predicate_entailment<'tcx>( // We now want to extract and substitute the type of the *trait* // method and compare it. To do so, we must create a compound // substitution by combining trait_to_impl_substs and - // impl_to_skol_substs, and also adding a mapping for the method + // impl_to_placeholder_substs, and also adding a mapping for the method // type parameters. We extend the mapping to also include // the method parameters. // - // trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 } + // trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 } // // Applying this to the trait method type yields: // @@ -145,20 +145,20 @@ fn compare_predicate_entailment<'tcx>( // satisfied by the implementation's method. // // We do this by creating a parameter environment which contains a - // substitution corresponding to impl_to_skol_substs. We then build - // trait_to_skol_substs and use it to convert the predicates contained + // substitution corresponding to impl_to_placeholder_substs. We then build + // trait_to_placeholder_substs and use it to convert the predicates contained // in the trait_m.generics to the placeholder form. // // Finally we register each of these predicates as an obligation in // a fresh FulfillmentCtxt, and invoke select_all_or_error. // Create mapping from impl to placeholder. - let impl_to_skol_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); + let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id); // Create mapping from trait to placeholder. - let trait_to_skol_substs = - impl_to_skol_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs); - debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); + let trait_to_placeholder_substs = + impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs); + debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs); let impl_m_generics = tcx.generics_of(impl_m.def_id); let trait_m_generics = tcx.generics_of(trait_m.def_id); @@ -194,7 +194,7 @@ fn compare_predicate_entailment<'tcx>( // if all constraints hold. hybrid_preds .predicates - .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + .extend(trait_m_predicates.instantiate_own(tcx, trait_to_placeholder_substs).predicates); // Construct trait parameter environment and then shift it into the placeholder viewpoint. // The key step here is to update the caller_bounds's predicates to be @@ -220,7 +220,7 @@ fn compare_predicate_entailment<'tcx>( let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); + let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, @@ -261,7 +261,7 @@ fn compare_predicate_entailment<'tcx>( debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, &tcx.fn_sig(trait_m.def_id)); - let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); + let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 019b4ca6606..bcfc0cf347c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -783,6 +783,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| { if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false } }; + let is_negative_int = + |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..)); + let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..)); let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); @@ -807,7 +810,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "you can convert `{}` from `{}` to `{}`, matching the type of `{}`", lhs_src, expected_ty, checked_ty, src ); - let suggestion = format!("{}::from({})", checked_ty, lhs_src,); + let suggestion = format!("{}::from({})", checked_ty, lhs_src); (lhs_expr.span, msg, suggestion) } else { let msg = format!("{} and panic if the converted value wouldn't fit", msg); @@ -822,8 +825,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { + let always_fallible = found_to_exp_is_fallible + && (exp_to_found_is_fallible || expected_ty_expr.is_none()); let msg = if literal_is_ty_suffixed(expr) { &lit_msg + } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) { + // We now know that converting either the lhs or rhs is fallible. Before we + // suggest a fallible conversion, check if the value can never fit in the + // expected type. + let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty); + err.note(&msg); + return; } else if in_const_context { // Do not recommend `into` or `try_into` in const contexts. return; diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index bc3ef73d851..6a006676371 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -29,9 +29,7 @@ use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty; -use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, -}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::Ty; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{AdtKind, Visibility}; @@ -113,12 +111,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(expr, ExpectHasType(expected)) } - pub(super) fn check_expr_with_expectation( + fn check_expr_with_expectation_and_needs( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, + needs: Needs, ) -> Ty<'tcx> { - self.check_expr_with_expectation_and_needs(expr, expected, Needs::None) + let ty = self.check_expr_with_expectation(expr, expected); + + // If the expression is used in a place whether mutable place is required + // e.g. LHS of assignment, perform the conversion. + if let Needs::MutPlace = needs { + self.convert_place_derefs_to_mutable(expr); + } + + ty } pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { @@ -143,11 +150,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `Error`, so avoid /// that when err needs to be handled differently. - fn check_expr_with_expectation_and_needs( + pub(super) fn check_expr_with_expectation( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - needs: Needs, ) -> Ty<'tcx> { debug!(">> type-checking: expr={:?} expected={:?}", expr, expected); @@ -171,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_diverges = self.diverges.replace(Diverges::Maybe); let old_has_errors = self.has_errors.replace(false); - let ty = self.check_expr_kind(expr, expected, needs); + let ty = self.check_expr_kind(expr, expected); // Warn for non-block expressions with diverging children. match expr.kind { @@ -213,9 +219,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - needs: Needs, ) -> Ty<'tcx> { - debug!("check_expr_kind(expr={:?}, expected={:?}, needs={:?})", expr, expected, needs,); + debug!("check_expr_kind(expr={:?}, expected={:?})", expr, expected); let tcx = self.tcx; match expr.kind { @@ -226,9 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_assign(expr, expected, lhs, rhs, span) } ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs), - ExprKind::Unary(unop, ref oprnd) => { - self.check_expr_unary(unop, oprnd, expected, needs, expr) - } + ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr), ExprKind::AddrOf(kind, mutbl, ref oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } @@ -248,7 +251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.types.never } else { // There was an error; make type-check fail. - tcx.types.err + tcx.ty_error() } } ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr), @@ -264,7 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected), ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected), ExprKind::MethodCall(ref segment, span, ref args, _) => { - self.check_method_call(expr, segment, span, args, expected, needs) + self.check_method_call(expr, segment, span, args, expected) } ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr), ExprKind::Type(ref e, ref t) => { @@ -281,10 +284,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Struct(ref qpath, fields, ref base_expr) => { self.check_expr_struct(expr, expected, qpath, fields, base_expr) } - ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field), - ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr), + ExprKind::Field(ref base, field) => self.check_field(expr, &base, field), + ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr), ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src), - hir::ExprKind::Err => tcx.types.err, + hir::ExprKind::Err => tcx.ty_error(), } } @@ -302,7 +305,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unop: hir::UnOp, oprnd: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, - needs: Needs, expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -310,40 +312,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::UnNot | hir::UnOp::UnNeg => expected, hir::UnOp::UnDeref => NoExpectation, }; - let needs = match unop { - hir::UnOp::UnDeref => needs, - _ => Needs::None, - }; - let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs); + let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner); if !oprnd_t.references_error() { oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t); match unop { hir::UnOp::UnDeref => { - if let Some(mt) = oprnd_t.builtin_deref(true) { - oprnd_t = mt.ty; - } else if let Some(ok) = self.try_overloaded_deref(expr.span, oprnd_t, needs) { - let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind { - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // (It shouldn't actually matter for unary ops whether - // we enable two-phase borrows or not, since a unary - // op has no additional operands.) - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; - self.apply_adjustments( - oprnd, - vec![Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target: method.sig.inputs()[0], - }], - ); - } - oprnd_t = self.make_overloaded_place_return_type(method).ty; - self.write_method_call(expr.hir_id, method); + if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { + oprnd_t = ty; } else { let mut err = type_error_struct!( tcx.sess, @@ -360,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp, None); } err.emit(); - oprnd_t = tcx.types.err; + oprnd_t = tcx.ty_error(); } } hir::UnOp::UnNot => { @@ -405,12 +381,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => NoExpectation, } }); - let needs = Needs::maybe_mut_place(mutbl); - let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs); + let ty = + self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl)); let tm = ty::TypeAndMut { ty, mutbl }; match kind { - _ if tm.ty.references_error() => self.tcx.types.err, + _ if tm.ty.references_error() => self.tcx.ty_error(), hir::BorrowKind::Raw => { self.check_named_place_expr(oprnd); self.tcx.mk_ptr(tm) @@ -476,11 +452,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match res { Res::Err => { self.set_tainted_by_errors(); - tcx.types.err + tcx.ty_error() } Res::Def(DefKind::Ctor(_, CtorKind::Fictive), _) => { report_unexpected_variant_res(tcx, res, expr.span); - tcx.types.err + tcx.ty_error() } _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; @@ -560,11 +536,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ctxt) => ctxt.coerce.as_ref().map(|coerce| coerce.expected_ty()), None => { // Avoid ICE when `break` is inside a closure (#65383). - self.tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( expr.span, "break was outside loop, but no error was emitted", ); - return tcx.types.err; } } }; @@ -572,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the loop context is not a `loop { }`, then break with // a value is illegal, and `opt_coerce_to` will be `None`. // Just set expectation to error in that case. - let coerce_to = opt_coerce_to.unwrap_or(tcx.types.err); + let coerce_to = opt_coerce_to.unwrap_or_else(|| tcx.ty_error()); // Recurse without `enclosing_breakables` borrowed. e_ty = self.check_expr_with_hint(e, coerce_to); @@ -592,11 +567,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(ctxt) => ctxt, None => { // Avoid ICE when `break` is inside a closure (#65383). - self.tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( expr.span, "break was outside loop, but no error was emitted", ); - return tcx.types.err; } }; @@ -649,14 +623,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this can only happen if the `break` was not // inside a loop at all, which is caught by the // loop-checking pass. - self.tcx - .sess - .delay_span_bug(expr.span, "break was outside loop, but no error was emitted"); + let err = self.tcx.ty_error_with_message( + expr.span, + "break was outside loop, but no error was emitted", + ); // We still need to assign a type to the inner expression to // prevent the ICE in #43162. if let Some(ref e) = expr_opt { - self.check_expr_with_hint(e, tcx.types.err); + self.check_expr_with_hint(e, err); // ... except when we try to 'break rust;'. // ICE this expression in particular (see #43162). @@ -666,8 +641,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + // There was an error; make type-check fail. - tcx.types.err + err } } @@ -803,7 +779,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { - self.tcx.types.err + self.tcx.ty_error() } else { self.tcx.mk_unit() } @@ -861,10 +837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, - needs: Needs, ) -> Ty<'tcx> { let rcvr = &args[0]; - let rcvr_t = self.check_expr_with_needs(&rcvr, needs); + let rcvr_t = self.check_expr(&rcvr); // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); @@ -913,10 +888,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr, probe::ProbeScope::AllTraits, ) { - err.span_label( - pick.item.ident.span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); + debug!("try_alt_rcvr: pick candidate {:?}", pick); + // Make sure the method is defined for the *actual* receiver: + // we don't want to treat `Box<Self>` as a receiver if + // it only works because of an autoderef to `&self` + if pick.autoderefs == 0 { + err.span_label( + pick.item.ident.span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + } } } }; @@ -957,7 +938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Eagerly check for some obvious errors. if t_expr.references_error() || t_cast.references_error() { - self.tcx.types.err + self.tcx.ty_error() } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -966,7 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(ErrorReported) => self.tcx.types.err, + Err(ErrorReported) => self.tcx.ty_error(), } } } @@ -1041,7 +1022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if element_ty.references_error() { - return tcx.types.err; + return tcx.ty_error(); } tcx.mk_ty(ty::Array(t, count)) @@ -1071,7 +1052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); let tuple = self.tcx.mk_tup(elt_ts_iter); if tuple.references_error() { - self.tcx.types.err + self.tcx.ty_error() } else { self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); tuple @@ -1092,7 +1073,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant_ty } else { self.check_struct_fields_on_error(fields, base_expr); - return self.tcx.types.err; + return self.tcx.ty_error(); }; let path_span = match *qpath { @@ -1233,7 +1214,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); } - tcx.types.err + tcx.ty_error() }; // Make sure to give a type to the field even if there's @@ -1443,11 +1424,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_field( &self, expr: &'tcx hir::Expr<'tcx>, - needs: Needs, base: &'tcx hir::Expr<'tcx>, field: Ident, ) -> Ty<'tcx> { - let expr_t = self.check_expr_with_needs(base, needs); + let expr_t = self.check_expr(base); let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); @@ -1467,7 +1447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // of error recovery. self.write_field_index(expr.hir_id, index); if field.vis.is_accessible_from(def_scope, self.tcx) { - let adjustments = autoderef.adjust_steps(self, needs); + let adjustments = autoderef.adjust_steps(self); self.apply_adjustments(base, adjustments); autoderef.finalize(self); @@ -1482,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = fstr.parse::<usize>() { if fstr == index.to_string() { if let Some(field_ty) = tys.get(index) { - let adjustments = autoderef.adjust_steps(self, needs); + let adjustments = autoderef.adjust_steps(self); self.apply_adjustments(base, adjustments); autoderef.finalize(self); @@ -1519,7 +1499,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } - self.tcx().types.err + self.tcx().ty_error() } fn ban_nonexisting_field( @@ -1721,10 +1701,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, base: &'tcx hir::Expr<'tcx>, idx: &'tcx hir::Expr<'tcx>, - needs: Needs, expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { - let base_t = self.check_expr_with_needs(&base, needs); + let base_t = self.check_expr(&base); let idx_t = self.check_expr(&idx); if base_t.references_error() { @@ -1733,7 +1712,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { idx_t } else { let base_t = self.structurally_resolved_type(base.span, base_t); - match self.lookup_indexing(expr, base, base_t, idx_t, needs) { + match self.lookup_indexing(expr, base, base_t, idx_t) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); @@ -1775,7 +1754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.emit(); - self.tcx.types.err + self.tcx.ty_error() } } } @@ -1887,7 +1866,7 @@ pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { ty::Char => "'a'", ty::Int(_) | ty::Uint(_) => "42", ty::Float(_) => "3.14159", - ty::Error | ty::Never => return None, + ty::Error(_) | ty::Never => return None, _ => "value", }) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index bded2c695c9..3ec6973a17d 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -347,6 +347,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { return; } + "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()), + ref other => { struct_span_err!( tcx.sess, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 007794ce1b7..6844c9416af 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -1,12 +1,12 @@ use super::{probe, MethodCallee}; use crate::astconv::AstConv; -use crate::check::{callee, FnCtxt, Needs, PlaceOp}; +use crate::check::{callee, FnCtxt}; use crate::hir::def_id::DefId; use crate::hir::GenericArg; use rustc_hir as hir; use rustc_infer::infer::{self, InferOk}; -use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{Subst, SubstsRef}; @@ -119,11 +119,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Create the final `MethodCallee`. let callee = MethodCallee { def_id: pick.item.def_id, substs: all_substs, sig: method_sig }; - - if let Some(hir::Mutability::Mut) = pick.autoref { - self.convert_place_derefs_to_mutable(); - } - ConfirmResult { callee, illegal_sized_bound } } @@ -141,16 +136,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let (_, n) = match autoderef.nth(pick.autoderefs) { Some(n) => n, None => { - self.tcx.sess.delay_span_bug( + return self.tcx.ty_error_with_message( rustc_span::DUMMY_SP, &format!("failed autoderef {}", pick.autoderefs), ); - return self.tcx.types.err; } }; assert_eq!(n, pick.autoderefs); - let mut adjustments = autoderef.adjust_steps(self, Needs::None); + let mut adjustments = autoderef.adjust_steps(self); let mut target = autoderef.unambiguous_final_ty(self); @@ -417,151 +411,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } /////////////////////////////////////////////////////////////////////////// - // RECONCILIATION - - /// When we select a method with a mutable autoref, we have to go convert any - /// auto-derefs, indices, etc from `Deref` and `Index` into `DerefMut` and `IndexMut` - /// respectively. - fn convert_place_derefs_to_mutable(&self) { - // Gather up expressions we want to munge. - let mut exprs = vec![self.self_expr]; - - loop { - match exprs.last().unwrap().kind { - hir::ExprKind::Field(ref expr, _) - | hir::ExprKind::Index(ref expr, _) - | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr), - _ => break, - } - } - - debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); - - // Fix up autoderefs and derefs. - for (i, &expr) in exprs.iter().rev().enumerate() { - debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); - - // Fix up the autoderefs. Autorefs can only occur immediately preceding - // overloaded place ops, and will be fixed by them in order to get - // the correct region. - let mut source = self.node_ty(expr.hir_id); - // Do not mutate adjustments in place, but rather take them, - // and replace them after mutating them, to avoid having the - // tables borrowed during (`deref_mut`) method resolution. - let previous_adjustments = - self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id); - if let Some(mut adjustments) = previous_adjustments { - let needs = Needs::MutPlace; - for adjustment in &mut adjustments { - if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind { - if let Some(ok) = self.try_overloaded_deref(expr.span, source, needs) { - let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = method.sig.output().kind { - *deref = OverloadedDeref { region, mutbl }; - } - } - } - source = adjustment.target; - } - self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments); - } - - match expr.kind { - hir::ExprKind::Index(ref base_expr, ref index_expr) => { - // We need to get the final type in case dereferences were needed for the trait - // to apply (#72002). - let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr); - self.convert_place_op_to_mutable( - PlaceOp::Index, - expr, - base_expr, - &[index_expr_ty], - ); - } - hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => { - self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]); - } - _ => {} - } - } - } - - fn convert_place_op_to_mutable( - &self, - op: PlaceOp, - expr: &hir::Expr<'_>, - base_expr: &hir::Expr<'_>, - arg_tys: &[Ty<'tcx>], - ) { - debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); - if !self.tables.borrow().is_method_call(expr) { - debug!("convert_place_op_to_mutable - builtin, nothing to do"); - return; - } - - let base_ty = self - .tables - .borrow() - .expr_adjustments(base_expr) - .last() - .map_or_else(|| self.node_ty(expr.hir_id), |adj| adj.target); - let base_ty = self.resolve_vars_if_possible(&base_ty); - - // Need to deref because overloaded place ops take self by-reference. - let base_ty = - base_ty.builtin_deref(false).expect("place op takes something that is not a ref").ty; - - let method = self.try_overloaded_place_op(expr.span, base_ty, arg_tys, Needs::MutPlace, op); - let method = match method { - Some(ok) => self.register_infer_ok_obligations(ok), - None => return self.tcx.sess.delay_span_bug(expr.span, "re-trying op failed"), - }; - debug!("convert_place_op_to_mutable: method={:?}", method); - self.write_method_call(expr.hir_id, method); - - let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind { - (r, mutbl) - } else { - span_bug!(expr.span, "input to place op is not a ref?"); - }; - - // Convert the autoref in the base expr to mutable with the correct - // region and mutability. - let base_expr_ty = self.node_ty(base_expr.hir_id); - if let Some(adjustments) = - self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id) - { - let mut source = base_expr_ty; - for adjustment in &mut adjustments[..] { - if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { - debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment); - let mutbl = match mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // For initial two-phase borrow - // deployment, conservatively omit - // overloaded operators. - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; - adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl)); - adjustment.target = - self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); - } - source = adjustment.target; - } - - // If we have an autoref followed by unsizing at the end, fix the unsize target. - - if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] = - adjustments[..] - { - *target = method.sig.inputs()[0]; - } - } - } - - /////////////////////////////////////////////////////////////////////////// // MISCELLANY fn predicates_require_illegal_sized_bound( diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index ac3fa15417e..259c4a8664f 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -194,11 +194,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; for import_id in &pick.import_ids { - let import_def_id = self.tcx.hir().local_def_id(*import_id); - debug!("used_trait_import: {:?}", import_def_id); + debug!("used_trait_import: {:?}", import_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap() - .insert(import_def_id.to_def_id()); + .insert(*import_id); } self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span); @@ -461,9 +460,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut tables = self.tables.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut tables.used_trait_imports).unwrap(); for import_id in pick.import_ids { - let import_def_id = tcx.hir().local_def_id(import_id); - debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); - used_trait_imports.insert(import_def_id.to_def_id()); + debug!("resolve_ufcs: used_trait_import: {:?}", import_id); + used_trait_imports.insert(import_id); } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 37652330108..efd23894d02 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -28,6 +28,7 @@ use rustc_middle::ty::{ }; use rustc_session::config::nightly_options; use rustc_session::lint; +use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; @@ -129,7 +130,7 @@ struct Candidate<'tcx> { xform_ret_ty: Option<Ty<'tcx>>, item: ty::AssocItem, kind: CandidateKind<'tcx>, - import_ids: SmallVec<[hir::HirId; 1]>, + import_ids: SmallVec<[LocalDefId; 1]>, } #[derive(Debug)] @@ -158,7 +159,7 @@ enum ProbeResult { pub struct Pick<'tcx> { pub item: ty::AssocItem, pub kind: PickKind<'tcx>, - pub import_ids: SmallVec<[hir::HirId; 1]>, + pub import_ids: SmallVec<[LocalDefId; 1]>, // Indicates that the source expression should be autoderef'd N times // @@ -400,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.structurally_resolved_type(span, ty.value); - assert_eq!(ty, self.tcx.types.err); + assert!(matches!(ty.kind, ty::Error(_))); return Err(MethodError::NoMatch(NoMatchData::new( Vec::new(), Vec::new(), @@ -478,7 +479,7 @@ fn method_autoderef_steps<'tcx>( let final_ty = autoderef.maybe_ambiguous_final_ty(); let opt_bad_ty = match final_ty.kind { - ty::Infer(ty::TyVar(_)) | ty::Error => Some(MethodAutoderefBadTy { + ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx .make_query_response_ignoring_pending_obligations(inference_vars, final_ty), @@ -930,7 +931,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_extension_candidates_for_trait( &mut self, - import_ids: &SmallVec<[hir::HirId; 1]>, + import_ids: &SmallVec<[LocalDefId; 1]>, trait_def_id: DefId, ) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); @@ -1467,7 +1468,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// /// ``` /// trait Foo { ... } - /// impl Foo for Vec<int> { ... } + /// impl Foo for Vec<i32> { ... } /// impl Foo for Vec<usize> { ... } /// ``` /// diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c26acd7a477..775441cb746 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -79,6 +79,7 @@ pub mod intrinsic; pub mod method; mod op; mod pat; +mod place_op; mod regionck; mod upvar; mod wfcheck; @@ -96,7 +97,7 @@ use rustc_errors::ErrorReported; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{ @@ -114,7 +115,7 @@ use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, + Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; @@ -138,6 +139,7 @@ use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; +use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -155,7 +157,6 @@ use std::slice; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; -use self::autoderef::Autoderef; use self::callee::DeferredCallResolution; use self::coercion::{CoerceMany, DynamicCoerceMany}; use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; @@ -839,7 +840,7 @@ fn has_typeck_tables(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &DefIdSet { +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> { &*tcx.typeck_tables_of(def_id).used_trait_imports } @@ -967,8 +968,7 @@ fn diagnostic_only_typeck_tables_of<'tcx>( ) -> &ty::TypeckTables<'tcx> { let fallback = move || { let span = tcx.hir().span(tcx.hir().as_local_hir_id(def_id)); - tcx.sess.delay_span_bug(span, "diagnostic only typeck table used"); - tcx.types.err + tcx.ty_error_with_message(span, "diagnostic only typeck table used") }; typeck_tables_of_with_fallback(tcx, def_id, fallback) } @@ -1711,6 +1711,173 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, } } +/// Given a `DefId` for an opaque type in return position, find its parent item's return +/// expressions. +fn get_owner_return_paths( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> { + let hir_id = tcx.hir().as_local_hir_id(def_id); + let id = tcx.hir().get_parent_item(hir_id); + tcx.hir() + .find(id) + .map(|n| (id, n)) + .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b))) + .map(|(hir_id, body_id)| { + let body = tcx.hir().body(body_id); + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(body); + (hir_id, visitor) + }) +} + +/// Emit an error for recursive opaque types. +/// +/// If this is a return `impl Trait`, find the item's return expressions and point at them. For +/// direct recursion this is enough, but for indirect recursion also point at the last intermediary +/// `impl Trait`. +/// +/// If all the return expressions evaluate to `!`, then we explain that the error will go away +/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. +fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + + let mut label = false; + if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { + let tables = tcx.typeck_tables_of(tcx.hir().local_def_id(hir_id)); + if visitor + .returns + .iter() + .filter_map(|expr| tables.node_type_opt(expr.hir_id)) + .all(|ty| matches!(ty.kind, ty::Never)) + { + let spans = visitor + .returns + .iter() + .filter(|expr| tables.node_type_opt(expr.hir_id).is_some()) + .map(|expr| expr.span) + .collect::<Vec<Span>>(); + let span_len = spans.len(); + if span_len == 1 { + err.span_label(spans[0], "this returned value is of `!` type"); + } else { + let mut multispan: MultiSpan = spans.clone().into(); + for span in spans { + multispan + .push_span_label(span, "this returned value is of `!` type".to_string()); + } + err.span_note(multispan, "these returned values have a concrete \"never\" type"); + } + err.help("this error will resolve once the item's body returns a concrete type"); + } else { + let mut seen = FxHashSet::default(); + seen.insert(span); + err.span_label(span, "recursive opaque type"); + label = true; + for (sp, ty) in visitor + .returns + .iter() + .filter_map(|e| tables.node_type_opt(e.hir_id).map(|t| (e.span, t))) + .filter(|(_, ty)| !matches!(ty.kind, ty::Never)) + { + struct VisitTypes(Vec<DefId>); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind { + ty::Opaque(def, _) => { + self.0.push(def); + false + } + _ => t.super_visit_with(self), + } + } + } + let mut visitor = VisitTypes(vec![]); + ty.visit_with(&mut visitor); + for def_id in visitor.0 { + let ty_span = tcx.def_span(def_id); + if !seen.contains(&ty_span) { + err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); + seen.insert(ty_span); + } + err.span_label(sp, &format!("returning here with type `{}`", ty)); + } + } + } + } + if !label { + err.span_label(span, "cannot resolve opaque type"); + } + err.emit(); +} + +/// Emit an error for recursive opaque types in a `let` binding. +fn binding_opaque_type_cycle_error( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, + partially_expanded_type: Ty<'tcx>, +) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + err.span_label(span, "cannot resolve opaque type"); + // Find the the owner that declared this `impl Trait` type. + let hir_id = tcx.hir().as_local_hir_id(def_id); + let mut prev_hir_id = hir_id; + let mut hir_id = tcx.hir().get_parent_node(hir_id); + while let Some(node) = tcx.hir().find(hir_id) { + match node { + hir::Node::Local(hir::Local { + pat, + init: None, + ty: Some(ty), + source: hir::LocalSource::Normal, + .. + }) => { + err.span_label(pat.span, "this binding might not have a concrete type"); + err.span_suggestion_verbose( + ty.span.shrink_to_hi(), + "set the binding to a value for a concrete type to be resolved", + " = /* value */".to_string(), + Applicability::HasPlaceholders, + ); + } + hir::Node::Local(hir::Local { + init: Some(expr), + source: hir::LocalSource::Normal, + .. + }) => { + let hir_id = tcx.hir().as_local_hir_id(def_id); + let tables = + tcx.typeck_tables_of(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id))); + if let Some(ty) = tables.node_type_opt(expr.hir_id) { + err.span_label( + expr.span, + &format!( + "this is of type `{}`, which doesn't constrain \ + `{}` enough to arrive to a concrete type", + ty, partially_expanded_type + ), + ); + } + } + _ => {} + } + if prev_hir_id == hir_id { + break; + } + prev_hir_id = hir_id; + hir_id = tcx.hir().get_parent_node(hir_id); + } + err.emit(); +} + +fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { + struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") + .span_label(span, "recursive `async fn`") + .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") + .emit(); +} + /// Checks that an opaque type does not contain cycles. fn check_opaque_for_cycles<'tcx>( tcx: TyCtxt<'tcx>, @@ -1721,21 +1888,12 @@ fn check_opaque_for_cycles<'tcx>( ) { if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) { - if let hir::OpaqueTyOrigin::AsyncFn = origin { - struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing",) - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .emit(); - } else { - let mut err = - struct_span_err!(tcx.sess, span, E0720, "opaque type expands to a recursive type",); - err.span_label(span, "expands to a recursive type"); - if let ty::Opaque(..) = partially_expanded_type.kind { - err.note("type resolves to itself"); - } else { - err.note(&format!("expanded type is `{}`", partially_expanded_type)); + match origin { + hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), + hir::OpaqueTyOrigin::Binding => { + binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) } - err.emit(); + _ => opaque_type_cycle_error(tcx, def_id, span), } } } @@ -3175,6 +3333,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + let autoborrow_mut = adj.iter().any(|adj| { + matches!(adj, &Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + .. + }) + }); + match self.tables.borrow_mut().adjustments_mut().entry(expr.hir_id) { Entry::Vacant(entry) => { entry.insert(adj); @@ -3204,6 +3369,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *entry.get_mut() = adj; } } + + // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`. + // In this case implicit use of `Deref` and `Index` within `<expr>` should + // instead be `DerefMut` and `IndexMut`, so fix those up. + if autoborrow_mut { + self.convert_place_derefs_to_mutable(expr); + } } /// Basically whenever we are converting from a type scheme into @@ -3387,7 +3559,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.tables.borrow().node_types().get(id) { Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.types.err, + None if self.is_tainted_by_errors() => self.tcx.ty_error(), None => { bug!( "no type for node {}: {} in fcx {}", @@ -3501,7 +3673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(ty.is_ty_infer()); let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().types.err, + _ if self.is_tainted_by_errors() => self.tcx().ty_error(), UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), @@ -3595,154 +3767,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } - fn lookup_indexing( - &self, - expr: &hir::Expr<'_>, - base_expr: &'tcx hir::Expr<'tcx>, - base_ty: Ty<'tcx>, - idx_ty: Ty<'tcx>, - needs: Needs, - ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - // FIXME(#18741) -- this is almost but not quite the same as the - // autoderef that normal method probing does. They could likely be - // consolidated. - - let mut autoderef = self.autoderef(base_expr.span, base_ty); - let mut result = None; - while result.is_none() && autoderef.next().is_some() { - result = self.try_index_step(expr, base_expr, &autoderef, needs, idx_ty); - } - autoderef.finalize(self); - result - } - - /// To type-check `base_expr[index_expr]`, we progressively autoderef - /// (and otherwise adjust) `base_expr`, looking for a type which either - /// supports builtin indexing or overloaded indexing. - /// This loop implements one step in that search; the autoderef loop - /// is implemented by `lookup_indexing`. - fn try_index_step( - &self, - expr: &hir::Expr<'_>, - base_expr: &hir::Expr<'_>, - autoderef: &Autoderef<'a, 'tcx>, - needs: Needs, - index_ty: Ty<'tcx>, - ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { - let adjusted_ty = autoderef.unambiguous_final_ty(self); - debug!( - "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ - index_ty={:?})", - expr, base_expr, adjusted_ty, index_ty - ); - - for &unsize in &[false, true] { - let mut self_ty = adjusted_ty; - if unsize { - // We only unsize arrays here. - if let ty::Array(element_ty, _) = adjusted_ty.kind { - self_ty = self.tcx.mk_slice(element_ty); - } else { - continue; - } - } - - // If some lookup succeeds, write callee into table and extract index/element - // type from the method signature. - // If some lookup succeeded, install method in table - let input_ty = self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AutoDeref, - span: base_expr.span, - }); - let method = self.try_overloaded_place_op( - expr.span, - self_ty, - &[input_ty], - needs, - PlaceOp::Index, - ); - - let result = method.map(|ok| { - debug!("try_index_step: success, using overloaded indexing"); - let method = self.register_infer_ok_obligations(ok); - - let mut adjustments = autoderef.adjust_steps(self, needs); - if let ty::Ref(region, _, r_mutbl) = method.sig.inputs()[0].kind { - let mutbl = match r_mutbl { - hir::Mutability::Not => AutoBorrowMutability::Not, - hir::Mutability::Mut => AutoBorrowMutability::Mut { - // Indexing can be desugared to a method call, - // so maybe we could use two-phase here. - // See the documentation of AllowTwoPhase for why that's - // not the case today. - allow_two_phase_borrow: AllowTwoPhase::No, - }, - }; - adjustments.push(Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target: self - .tcx - .mk_ref(region, ty::TypeAndMut { mutbl: r_mutbl, ty: adjusted_ty }), - }); - } - if unsize { - adjustments.push(Adjustment { - kind: Adjust::Pointer(PointerCast::Unsize), - target: method.sig.inputs()[0], - }); - } - self.apply_adjustments(base_expr, adjustments); - - self.write_method_call(expr.hir_id, method); - (input_ty, self.make_overloaded_place_return_type(method).ty) - }); - if result.is_some() { - return result; - } - } - - None - } - - fn resolve_place_op(&self, op: PlaceOp, is_mut: bool) -> (Option<DefId>, Ident) { - let (tr, name) = match (op, is_mut) { - (PlaceOp::Deref, false) => (self.tcx.lang_items().deref_trait(), sym::deref), - (PlaceOp::Deref, true) => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), - (PlaceOp::Index, false) => (self.tcx.lang_items().index_trait(), sym::index), - (PlaceOp::Index, true) => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), - }; - (tr, Ident::with_dummy_span(name)) - } - - fn try_overloaded_place_op( - &self, - span: Span, - base_ty: Ty<'tcx>, - arg_tys: &[Ty<'tcx>], - needs: Needs, - op: PlaceOp, - ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { - debug!("try_overloaded_place_op({:?},{:?},{:?},{:?})", span, base_ty, needs, op); - - // Try Mut first, if needed. - let (mut_tr, mut_op) = self.resolve_place_op(op, true); - let method = match (needs, mut_tr) { - (Needs::MutPlace, Some(trait_did)) => { - self.lookup_method_in_trait(span, mut_op, trait_did, base_ty, Some(arg_tys)) - } - _ => None, - }; - - // Otherwise, fall back to the immutable version. - let (imm_tr, imm_op) = self.resolve_place_op(op, false); - match (method, imm_tr) { - (None, Some(trait_did)) => { - self.lookup_method_in_trait(span, imm_op, trait_did, base_ty, Some(arg_tys)) - } - (method, _) => method, - } - } - fn check_method_argument_types( &self, sp: Span, @@ -3774,7 +3798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tuple_arguments, None, ); - return self.tcx.types.err; + return self.tcx.ty_error(); } let method = method.unwrap(); @@ -4161,7 +4185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { - vec![self.tcx.types.err; len] + vec![self.tcx.ty_error(); len] } /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk @@ -4305,7 +4329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_ty.unwrap_or_else(|| self.next_float_var()) } ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.types.err, + ast::LitKind::Err(_) => tcx.ty_error(), } } @@ -4442,7 +4466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let result = AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or(self.tcx().types.err); + let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); let result = result.map(|(_, kind, def_id)| (kind, def_id)); // Write back the new resolution. @@ -4570,7 +4594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) { if ty.references_error() { - // Override the types everywhere with `types.err` to avoid knock on errors. + // Override the types everywhere with `err()` to avoid knock on errors. self.write_ty(local.hir_id, ty); self.write_ty(local.pat.hir_id, ty); let local_ty = LocalTy { decl_ty, revealed_ty: ty }; @@ -4790,7 +4814,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut ty = ctxt.coerce.unwrap().complete(self); if self.has_errors.get() || ty.references_error() { - ty = self.tcx.types.err + ty = self.tcx.ty_error() } self.write_ty(blk.hir_id, ty); @@ -5378,7 +5402,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind, ty::Error) + if matches!(last_expr_ty.kind, ty::Error(_)) || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return None; @@ -5538,7 +5562,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); - return (tcx.types.err, res); + return (tcx.ty_error(), res); } } } else { @@ -5731,8 +5755,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .note("type must be known at this point") .emit(); } - self.demand_suptype(sp, self.tcx.types.err, ty); - self.tcx.types.err + let err = self.tcx.ty_error(); + self.demand_suptype(sp, err, ty); + err } } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index a3a27dc138b..56804792b19 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -1,7 +1,7 @@ //! Code related to processing overloaded binary and unary operators. use super::method::MethodCallee; -use super::{FnCtxt, Needs}; +use super::FnCtxt; use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // trait matching creating lifetime constraints that are too strict. // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. - let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None); + let lhs_ty = self.check_expr(lhs_expr); let fresh_var = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: lhs_expr.span, @@ -177,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // equivalence on the LHS of an assign-op like `+=`; // overwritten or mutably-borrowed places cannot be // coerced to a supertype. - self.check_expr_with_needs(lhs_expr, Needs::MutPlace) + self.check_expr(lhs_expr) } }; let lhs_ty = self.resolve_vars_with_obligations(lhs_ty); @@ -497,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - self.tcx.types.err + self.tcx.ty_error() } }; @@ -709,7 +709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } err.emit(); } - self.tcx.types.err + self.tcx.ty_error() } } } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 8a10427260e..ea47ae68ce7 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // errors in some cases, such as this one: // // ``` - // fn foo<'x>(x: &'x int) { + // fn foo<'x>(x: &'x i32) { // let a = 1; // let mut z = x; // z = &a; @@ -220,7 +220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` // // The reason we might get an error is that `z` might be - // assigned a type like `&'x int`, and then we would have + // assigned a type like `&'x i32`, 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`. @@ -229,11 +229,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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. + // Then we will assign the type of the initializer (`&'x i32`) + // as a subtype of `Z`: `&'x i32 <: Z`. And hence we + // will instantiate `Z` as a type `&'0 i32` 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`). @@ -442,7 +442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There exists a side that didn't meet our criteria that the end-point // be of a numeric or char type, as checked in `calc_side` above. self.emit_err_pat_range(span, lhs, rhs); - return self.tcx.types.err; + return self.tcx.ty_error(); } // Now that we know the types can be unified we find the unified type @@ -673,11 +673,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { variant_ty } else { + let err = self.tcx.ty_error(); for field in fields { let ti = TopInfo { parent_pat: Some(&pat), ..ti }; - self.check_pat(&field.pat, self.tcx.types.err, def_bm, ti); + self.check_pat(&field.pat, err, def_bm, ti); } - return self.tcx.types.err; + return err; }; // Type-check the path. @@ -687,7 +688,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) { pat_ty } else { - self.tcx.types.err + self.tcx.ty_error() } } @@ -705,11 +706,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match res { Res::Err => { self.set_tainted_by_errors(); - return tcx.types.err; + return tcx.ty_error(); } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fictive | CtorKind::Fn), _) => { report_unexpected_variant_res(tcx, res, pat.span); - return tcx.types.err; + return tcx.ty_error(); } Res::SelfCtor(..) | Res::Def( @@ -788,7 +789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let on_error = || { let parent_pat = Some(pat); for pat in subpats { - self.check_pat(&pat, tcx.types.err, def_bm, TopInfo { parent_pat, ..ti }); + self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti }); } }; let report_unexpected_res = |res: Res| { @@ -824,7 +825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if res == Res::Err { self.set_tainted_by_errors(); on_error(); - return self.tcx.types.err; + return self.tcx.ty_error(); } // Type-check the path. @@ -832,18 +833,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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; + return tcx.ty_error(); } let variant = match res { Res::Err => { self.set_tainted_by_errors(); on_error(); - return tcx.types.err; + return tcx.ty_error(); } Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => { report_unexpected_res(res); - return tcx.types.err; + return tcx.ty_error(); } Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res), _ => bug!("unexpected pattern resolution: {:?}", res), @@ -880,7 +881,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Pattern has wrong number of fields. self.e0023(pat.span, res, qpath, subpats, &variant.fields, expected, had_err); on_error(); - return tcx.types.err; + return tcx.ty_error(); } pat_ty } @@ -1001,9 +1002,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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); + let element_tys_iter = (0..max_len).map(|_| tcx.ty_error()); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &tcx.types.err, def_bm, ti); + self.check_pat(elem, &tcx.ty_error(), def_bm, ti); } tcx.mk_tup(element_tys_iter) } else { @@ -1052,7 +1053,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Occupied(occupied) => { self.error_field_already_bound(span, field.ident, *occupied.get()); no_field_errors = false; - tcx.types.err + tcx.ty_error() } Vacant(vacant) => { vacant.insert(span); @@ -1066,7 +1067,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|| { inexistent_fields.push(field.ident); no_field_errors = false; - tcx.types.err + tcx.ty_error() }) } }; @@ -1281,7 +1282,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(span, expected, box_ty, ti); (box_ty, inner_ty) } else { - (tcx.types.err, tcx.types.err) + let err = tcx.ty_error(); + (err, err) }; self.check_pat(&inner, inner_ty, def_bm, ti); box_ty @@ -1327,7 +1329,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else { - (tcx.types.err, tcx.types.err) + let err = tcx.ty_error(); + (err, err) }; self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); rptr_ty @@ -1378,7 +1381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !expected.references_error() { self.error_expected_array_or_slice(span, expected); } - let err = self.tcx.types.err; + let err = self.tcx.ty_error(); (err, Some(err), err) } }; @@ -1445,7 +1448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If we get here, we must have emitted an error. - (Some(self.tcx.types.err), arr_ty) + (Some(self.tcx.ty_error()), arr_ty) } fn error_scrutinee_inconsistent_length(&self, span: Span, min_len: u64, size: u64) { diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs new file mode 100644 index 00000000000..d1c22cd1ac0 --- /dev/null +++ b/src/librustc_typeck/check/place_op.rs @@ -0,0 +1,336 @@ +use crate::check::autoderef::Autoderef; +use crate::check::method::MethodCallee; +use crate::check::{FnCtxt, PlaceOp}; +use rustc_hir as hir; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::InferOk; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast}; +use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::Span; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. + pub(super) fn lookup_derefing( + &self, + expr: &hir::Expr<'_>, + oprnd_expr: &'tcx hir::Expr<'tcx>, + oprnd_ty: Ty<'tcx>, + ) -> Option<Ty<'tcx>> { + if let Some(mt) = oprnd_ty.builtin_deref(true) { + return Some(mt.ty); + } + + let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; + let method = self.register_infer_ok_obligations(ok); + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + self.apply_adjustments( + oprnd_expr, + vec![Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), + target: method.sig.inputs()[0], + }], + ); + } else { + span_bug!(expr.span, "input to deref is not a ref?"); + } + let ty = self.make_overloaded_place_return_type(method).ty; + self.write_method_call(expr.hir_id, method); + Some(ty) + } + + /// Type-check `*base_expr[index_expr]` with `base_expr` and `index_expr` type-checked already. + pub(super) fn lookup_indexing( + &self, + expr: &hir::Expr<'_>, + base_expr: &'tcx hir::Expr<'tcx>, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { + // FIXME(#18741) -- this is almost but not quite the same as the + // autoderef that normal method probing does. They could likely be + // consolidated. + + let mut autoderef = self.autoderef(base_expr.span, base_ty); + let mut result = None; + while result.is_none() && autoderef.next().is_some() { + result = self.try_index_step(expr, base_expr, &autoderef, idx_ty); + } + autoderef.finalize(self); + result + } + + /// To type-check `base_expr[index_expr]`, we progressively autoderef + /// (and otherwise adjust) `base_expr`, looking for a type which either + /// supports builtin indexing or overloaded indexing. + /// This loop implements one step in that search; the autoderef loop + /// is implemented by `lookup_indexing`. + fn try_index_step( + &self, + expr: &hir::Expr<'_>, + base_expr: &hir::Expr<'_>, + autoderef: &Autoderef<'a, 'tcx>, + index_ty: Ty<'tcx>, + ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { + let adjusted_ty = autoderef.unambiguous_final_ty(self); + debug!( + "try_index_step(expr={:?}, base_expr={:?}, adjusted_ty={:?}, \ + index_ty={:?})", + expr, base_expr, adjusted_ty, index_ty + ); + + for &unsize in &[false, true] { + let mut self_ty = adjusted_ty; + if unsize { + // We only unsize arrays here. + if let ty::Array(element_ty, _) = adjusted_ty.kind { + self_ty = self.tcx.mk_slice(element_ty); + } else { + continue; + } + } + + // If some lookup succeeds, write callee into table and extract index/element + // type from the method signature. + // If some lookup succeeded, install method in table + let input_ty = self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::AutoDeref, + span: base_expr.span, + }); + let method = + self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); + + let result = method.map(|ok| { + debug!("try_index_step: success, using overloaded indexing"); + let method = self.register_infer_ok_obligations(ok); + + let mut adjustments = autoderef.adjust_steps(self); + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + adjustments.push(Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), + target: self.tcx.mk_ref( + region, + ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty }, + ), + }); + } else { + span_bug!(expr.span, "input to index is not a ref?"); + } + if unsize { + adjustments.push(Adjustment { + kind: Adjust::Pointer(PointerCast::Unsize), + target: method.sig.inputs()[0], + }); + } + self.apply_adjustments(base_expr, adjustments); + + self.write_method_call(expr.hir_id, method); + (input_ty, self.make_overloaded_place_return_type(method).ty) + }); + if result.is_some() { + return result; + } + } + + None + } + + /// Try to resolve an overloaded place op. We only deal with the immutable + /// variant here (Deref/Index). In some contexts we would need the mutable + /// variant (DerefMut/IndexMut); those would be later converted by + /// `convert_place_derefs_to_mutable`. + pub(super) fn try_overloaded_place_op( + &self, + span: Span, + base_ty: Ty<'tcx>, + arg_tys: &[Ty<'tcx>], + op: PlaceOp, + ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { + debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); + + let (imm_tr, imm_op) = match op { + PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref), + PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), + }; + imm_tr.and_then(|trait_did| { + self.lookup_method_in_trait( + span, + Ident::with_dummy_span(imm_op), + trait_did, + base_ty, + Some(arg_tys), + ) + }) + } + + fn try_mutable_overloaded_place_op( + &self, + span: Span, + base_ty: Ty<'tcx>, + arg_tys: &[Ty<'tcx>], + op: PlaceOp, + ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { + debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op); + + let (mut_tr, mut_op) = match op { + PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), + PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), + }; + mut_tr.and_then(|trait_did| { + self.lookup_method_in_trait( + span, + Ident::with_dummy_span(mut_op), + trait_did, + base_ty, + Some(arg_tys), + ) + }) + } + + /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` + /// into `DerefMut` and `IndexMut` respectively. + /// + /// This is a second pass of typechecking derefs/indices. We need this we do not + /// always know whether a place needs to be mutable or not in the first pass. + /// This happens whether there is an implicit mutable reborrow, e.g. when the type + /// is used as the receiver of a method call. + pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) { + // Gather up expressions we want to munge. + let mut exprs = vec![expr]; + + loop { + match exprs.last().unwrap().kind { + hir::ExprKind::Field(ref expr, _) + | hir::ExprKind::Index(ref expr, _) + | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr), + _ => break, + } + } + + debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); + + // Fix up autoderefs and derefs. + for (i, &expr) in exprs.iter().rev().enumerate() { + debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); + + // Fix up the autoderefs. Autorefs can only occur immediately preceding + // overloaded place ops, and will be fixed by them in order to get + // the correct region. + let mut source = self.node_ty(expr.hir_id); + // Do not mutate adjustments in place, but rather take them, + // and replace them after mutating them, to avoid having the + // tables borrowed during (`deref_mut`) method resolution. + let previous_adjustments = + self.tables.borrow_mut().adjustments_mut().remove(expr.hir_id); + if let Some(mut adjustments) = previous_adjustments { + for adjustment in &mut adjustments { + if let Adjust::Deref(Some(ref mut deref)) = adjustment.kind { + if let Some(ok) = self.try_mutable_overloaded_place_op( + expr.span, + source, + &[], + PlaceOp::Deref, + ) { + let method = self.register_infer_ok_obligations(ok); + if let ty::Ref(region, _, mutbl) = method.sig.output().kind { + *deref = OverloadedDeref { region, mutbl }; + } + } + } + source = adjustment.target; + } + self.tables.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments); + } + + match expr.kind { + hir::ExprKind::Index(ref base_expr, ref index_expr) => { + // We need to get the final type in case dereferences were needed for the trait + // to apply (#72002). + let index_expr_ty = self.tables.borrow().expr_ty_adjusted(index_expr); + self.convert_place_op_to_mutable( + PlaceOp::Index, + expr, + base_expr, + &[index_expr_ty], + ); + } + hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => { + self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]); + } + _ => {} + } + } + } + + fn convert_place_op_to_mutable( + &self, + op: PlaceOp, + expr: &hir::Expr<'_>, + base_expr: &hir::Expr<'_>, + arg_tys: &[Ty<'tcx>], + ) { + debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); + if !self.tables.borrow().is_method_call(expr) { + debug!("convert_place_op_to_mutable - builtin, nothing to do"); + return; + } + + // Need to deref because overloaded place ops take self by-reference. + let base_ty = self + .tables + .borrow() + .expr_ty_adjusted(base_expr) + .builtin_deref(false) + .expect("place op takes something that is not a ref") + .ty; + + let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); + let method = match method { + Some(ok) => self.register_infer_ok_obligations(ok), + // Couldn't find the mutable variant of the place op, keep the + // current, immutable version. + None => return, + }; + debug!("convert_place_op_to_mutable: method={:?}", method); + self.write_method_call(expr.hir_id, method); + + let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind { + r + } else { + span_bug!(expr.span, "input to mutable place op is not a mut ref?"); + }; + + // Convert the autoref in the base expr to mutable with the correct + // region and mutability. + let base_expr_ty = self.node_ty(base_expr.hir_id); + if let Some(adjustments) = + self.tables.borrow_mut().adjustments_mut().get_mut(base_expr.hir_id) + { + let mut source = base_expr_ty; + for adjustment in &mut adjustments[..] { + if let Adjust::Borrow(AutoBorrow::Ref(..)) = adjustment.kind { + debug!("convert_place_op_to_mutable: converting autoref {:?}", adjustment); + let mutbl = AutoBorrowMutability::Mut { + // Deref/indexing can be desugared to a method call, + // so maybe we could use two-phase here. + // See the documentation of AllowTwoPhase for why that's + // not the case today. + allow_two_phase_borrow: AllowTwoPhase::No, + }; + adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl)); + adjustment.target = + self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() }); + } + source = adjustment.target; + } + + // If we have an autoref followed by unsizing at the end, fix the unsize target. + if let [.., Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), ref mut target }] = + adjustments[..] + { + *target = method.sig.inputs()[0]; + } + } + } +} diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 90ba15aa089..d3bccaaa3e4 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -439,7 +439,10 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. - fn constrain_adjustments(&mut self, expr: &hir::Expr<'_>) -> mc::McResult<mc::Place<'tcx>> { + fn constrain_adjustments( + &mut self, + expr: &hir::Expr<'_>, + ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> { debug!("constrain_adjustments(expr={:?})", expr); let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; @@ -480,12 +483,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn check_safety_of_rvalue_destructor_if_necessary( &mut self, - place: &mc::Place<'tcx>, + place_with_id: &mc::PlaceWithHirId<'tcx>, span: Span, ) { - if let mc::PlaceBase::Rvalue = place.base { - if place.projections.is_empty() { - let typ = self.resolve_type(place.ty); + if let mc::PlaceBase::Rvalue = place_with_id.place.base { + if place_with_id.place.projections.is_empty() { + let typ = self.resolve_type(place_with_id.place.ty); let body_id = self.body_id; let _ = dropck::check_drop_obligations(self, typ, span, body_id); } @@ -570,7 +573,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { /// Link lifetimes of any ref bindings in `root_pat` to the pointers found /// in the discriminant, if needed. - fn link_pattern(&self, discr_cmt: mc::Place<'tcx>, root_pat: &hir::Pat<'_>) { + fn link_pattern(&self, discr_cmt: mc::PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); ignore_err!(self.with_mc(|mc| { mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| { @@ -591,7 +594,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { fn link_autoref( &self, expr: &hir::Expr<'_>, - expr_cmt: &mc::Place<'tcx>, + expr_cmt: &mc::PlaceWithHirId<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>, ) { debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt); @@ -612,7 +615,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { span: Span, id: hir::HirId, mutbl: hir::Mutability, - cmt_borrowed: &mc::Place<'tcx>, + cmt_borrowed: &mc::PlaceWithHirId<'tcx>, ) { debug!( "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})", @@ -635,12 +638,12 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { span: Span, borrow_region: ty::Region<'tcx>, borrow_kind: ty::BorrowKind, - borrow_place: &mc::Place<'tcx>, + borrow_place: &mc::PlaceWithHirId<'tcx>, ) { - let origin = infer::DataBorrowed(borrow_place.ty, span); - self.type_must_outlive(origin, borrow_place.ty, borrow_region); + let origin = infer::DataBorrowed(borrow_place.place.ty, span); + self.type_must_outlive(origin, borrow_place.place.ty, borrow_region); - for pointer_ty in borrow_place.deref_tys() { + for pointer_ty in borrow_place.place.deref_tys() { debug!( "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", borrow_region, borrow_kind, borrow_place @@ -656,7 +659,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty), } } - if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.base { + if let mc::PlaceBase::Upvar(upvar_id) = borrow_place.place.base { self.link_upvar_region(span, borrow_region, upvar_id); } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 19a23e5a594..0f3133e0695 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -91,7 +91,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (closure_def_id, substs) = match ty.kind { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), - ty::Error => { + ty::Error(_) => { // #51714: skip analysis when we have already encountered type errors return; } @@ -270,10 +270,13 @@ struct InferBorrowKind<'a, 'tcx> { impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { fn adjust_upvar_borrow_kind_for_consume( &mut self, - place: &mc::Place<'tcx>, + place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode, ) { - debug!("adjust_upvar_borrow_kind_for_consume(place={:?}, mode={:?})", place, mode); + debug!( + "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})", + place_with_id, mode + ); // we only care about moves match mode { @@ -284,7 +287,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } let tcx = self.fcx.tcx; - let upvar_id = if let PlaceBase::Upvar(upvar_id) = place.base { + let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { upvar_id } else { return; @@ -296,22 +299,22 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { self.adjust_closure_kind( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - place.span, + tcx.hir().span(place_with_id.hir_id), var_name(tcx, upvar_id.var_path.hir_id), ); self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); } - /// Indicates that `place` is being directly mutated (e.g., assigned + /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. - fn adjust_upvar_borrow_kind_for_mut(&mut self, place: &mc::Place<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_mut(place={:?})", place); + fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) { + debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id); - if let PlaceBase::Upvar(upvar_id) = place.base { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; - for pointer_ty in place.deref_tys() { + for pointer_ty in place_with_id.place.deref_tys() { match pointer_ty.kind { // Raw pointers don't inherit mutability. ty::RawPtr(_) => return, @@ -323,20 +326,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { _ => (), } } - self.adjust_upvar_deref(upvar_id, place.span, borrow_kind); + self.adjust_upvar_deref( + upvar_id, + self.fcx.tcx.hir().span(place_with_id.hir_id), + borrow_kind, + ); } } - fn adjust_upvar_borrow_kind_for_unique(&mut self, place: &mc::Place<'tcx>) { - debug!("adjust_upvar_borrow_kind_for_unique(place={:?})", place); + fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>) { + debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id); - if let PlaceBase::Upvar(upvar_id) = place.base { - if place.deref_tys().any(ty::TyS::is_unsafe_ptr) { + if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { + if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. return; } // for a borrowed pointer to be unique, its base must be unique - self.adjust_upvar_deref(upvar_id, place.span, ty::UniqueImmBorrow); + self.adjust_upvar_deref( + upvar_id, + self.fcx.tcx.hir().span(place_with_id.hir_id), + ty::UniqueImmBorrow, + ); } } @@ -453,26 +464,26 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { - fn consume(&mut self, place: &mc::Place<'tcx>, mode: euv::ConsumeMode) { - debug!("consume(place={:?},mode={:?})", place, mode); - self.adjust_upvar_borrow_kind_for_consume(place, mode); + fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) { + debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode); + self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode); } - fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind) { - debug!("borrow(place={:?}, bk={:?})", place, bk); + fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { + debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk); match bk { ty::ImmBorrow => {} ty::UniqueImmBorrow => { - self.adjust_upvar_borrow_kind_for_unique(place); + self.adjust_upvar_borrow_kind_for_unique(place_with_id); } ty::MutBorrow => { - self.adjust_upvar_borrow_kind_for_mut(place); + self.adjust_upvar_borrow_kind_for_mut(place_with_id); } } } - fn mutate(&mut self, assignee_place: &mc::Place<'tcx>) { + fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>) { debug!("mutate(assignee_place={:?})", assignee_place); self.adjust_upvar_borrow_kind_for_mut(assignee_place); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 159d3d7a538..4704d8fc766 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -4,10 +4,8 @@ use crate::check::FnCtxt; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir as hir; -use rustc_hir::def_id::DefIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::InferCtxt; @@ -67,10 +65,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_sigs(); wbcx.visit_generator_interior_types(); - let used_trait_imports = mem::replace( - &mut self.tables.borrow_mut().used_trait_imports, - Lrc::new(DefIdSet::default()), - ); + let used_trait_imports = mem::take(&mut self.tables.borrow_mut().used_trait_imports); debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.tables.used_trait_imports = used_trait_imports; @@ -208,11 +203,10 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // to access an unexistend index. We assume that more relevant errors will // already have been emitted, so we only gate on this with an ICE if no // error has been emitted. (#64638) - self.tcx().sess.delay_span_bug( + self.fcx.tcx.ty_error_with_message( e.span, &format!("bad index {:?} for base: `{:?}`", index, base), - ); - self.fcx.tcx.types.err + ) }); let index_ty = self.fcx.resolve_vars_if_possible(&index_ty); @@ -681,7 +675,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_type_error(t); self.replaced_with_error = true; - self.tcx().types.err + self.tcx().ty_error() } } } @@ -698,7 +692,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); self.report_const_error(ct); self.replaced_with_error = true; - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty: ct.ty }) + self.tcx().const_error(ct.ty) } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index eaaff70472b..81daf064bb3 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -1,14 +1,14 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::TyCtxt; use rustc_session::lint; use rustc_span::{Span, Symbol}; pub fn check_crate(tcx: TyCtxt<'_>) { - let mut used_trait_imports = DefIdSet::default(); + let mut used_trait_imports = FxHashSet::default(); for &body_id in tcx.hir().krate().bodies.keys() { let item_def_id = tcx.hir().body_owner_def_id(body_id); let imports = tcx.used_trait_imports(item_def_id); @@ -39,7 +39,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { struct CheckVisitor<'tcx> { tcx: TyCtxt<'tcx>, - used_trait_imports: DefIdSet, + used_trait_imports: FxHashSet<LocalDefId>, } impl CheckVisitor<'tcx> { @@ -49,7 +49,7 @@ impl CheckVisitor<'tcx> { return; } - if self.used_trait_imports.contains(&def_id.to_def_id()) { + if self.used_trait_imports.contains(&def_id) { return; } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index c5dd314dc65..8c6161a6264 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -50,7 +50,7 @@ impl<'tcx> Checker<'tcx> { fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // Destructors only work on nominal types. - if let ty::Adt(..) | ty::Error = tcx.type_of(impl_did).kind { + if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind { return; } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index 653b7b8f2a5..93ee87f6c57 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -296,7 +296,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { item.span, ); } - ty::Error => {} + ty::Error(_) => {} _ => { struct_span_err!( self.tcx.sess, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1d59d749634..91266eeb9ba 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -40,6 +40,7 @@ use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; +use rustc_session::config::SanitizerSet; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -307,8 +308,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - self.tcx().sess.delay_span_bug(span, "bad placeholder type"); - self.tcx().types.err + self.tcx().ty_error_with_message(span, "bad_placeholder_type") } fn ct_infer( @@ -318,8 +318,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { span: Span, ) -> &'tcx Const<'tcx> { bad_placeholder_type(self.tcx(), vec![span]).emit(); - - self.tcx().mk_const(ty::Const { val: ty::ConstKind::Error, ty }) + self.tcx().const_error(ty) } fn projected_ty_from_poly_trait_ref( @@ -419,7 +418,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> { _ => {} } err.emit(); - self.tcx().types.err + self.tcx().ty_error() } } @@ -1465,7 +1464,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { visitor.visit_ty(ty); let mut diag = bad_placeholder_type(tcx, visitor.0); let ret_ty = fn_sig.output(); - if ret_ty != tcx.types.err { + if ret_ty != tcx.ty_error() { diag.span_suggestion( ty.span, "replace with the correct return type", @@ -2004,12 +2003,11 @@ fn associated_item_predicates( // once they are handled by the trait system. ty::GenericParamDefKind::Type { .. } => { unimplemented_error("type"); - tcx.types.err.into() + tcx.ty_error().into() } ty::GenericParamDefKind::Const => { unimplemented_error("const"); - tcx.mk_const(ty::Const { val: ty::ConstKind::Error, ty: tcx.type_of(param.def_id) }) - .into() + tcx.const_error(tcx.type_of(param.def_id)).into() } } }; @@ -2453,11 +2451,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { if let Some(list) = attr.meta_item_list() { for item in list.iter() { if item.check_name(sym::address) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_ADDRESS; + codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS; } else if item.check_name(sym::memory) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_MEMORY; + codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY; } else if item.check_name(sym::thread) { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_SANITIZE_THREAD; + codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD; } else { tcx.sess .struct_span_err(item.span(), "invalid argument for `no_sanitize`") @@ -2557,7 +2555,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } - if codegen_fn_attrs.flags.intersects(CodegenFnAttrFlags::NO_SANITIZE_ANY) { + if !codegen_fn_attrs.no_sanitize.is_empty() { if codegen_fn_attrs.inline == InlineAttr::Always { if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { let hir_id = tcx.hir().as_local_hir_id(id.expect_local()); diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index 549a20531e2..cf5f2ec69d8 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -127,7 +127,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // Some error in the // owner fn prevented us from populating // the `concrete_opaque_types` table. - tcx.types.err + tcx.ty_error() } else { // We failed to resolve the opaque type or it // resolves to itself. Return the non-revealed @@ -217,11 +217,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { }) | Node::TraitRef(&TraitRef { path, .. }) => &*path, _ => { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( DUMMY_SP, &format!("unexpected const parent path {:?}", parent_node), ); - return tcx.types.err; } }; @@ -254,14 +253,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } Res::Def(_, def_id) => tcx.generics_of(def_id), res => { - tcx.sess.delay_span_bug( + return tcx.ty_error_with_message( DUMMY_SP, &format!( "unexpected anon const res {:?} in path: {:?}", res, path, ), - ); - return tcx.types.err; + ); } }; @@ -283,24 +281,21 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } else { // This is no generic parameter associated with the arg. This is // probably from an extra arg where one is not needed. - tcx.sess.delay_span_bug( + tcx.ty_error_with_message( DUMMY_SP, &format!( - "missing generic parameter for `AnonConst`, parent: {:?}, res: {:?}", + "missing generic parameter for `AnonConst`, \ + parent: {:?}, res: {:?}", parent_node, res ), - ); - tcx.types.err + ) } } - x => { - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!("unexpected const parent in type_of_def_id(): {:?}", x), - ); - tcx.types.err - } + x => tcx.ty_error_with_message( + DUMMY_SP, + &format!("unexpected const parent in type_of_def_id(): {:?}", x), + ), } } @@ -568,7 +563,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { None => { let span = tcx.def_span(def_id); tcx.sess.span_err(span, "could not find defining uses"); - tcx.types.err + tcx.ty_error() } } } @@ -605,7 +600,7 @@ fn let_position_impl_trait_type(tcx: TyCtxt<'_>, opaque_ty_id: LocalDefId) -> Ty if let Some(ErrorReported) = owner_tables.tainted_by_errors { // Some error in the owner fn prevented us from populating the // `concrete_opaque_types` table. - tcx.types.err + tcx.ty_error() } else { // We failed to resolve the opaque type or it resolves to // itself. Return the non-revealed type, which should result in @@ -655,7 +650,7 @@ fn infer_placeholder_type( } None => { let mut diag = bad_placeholder_type(tcx, vec![span]); - if ty != tcx.types.err { + if !matches!(ty.kind, ty::Error(_)) { diag.span_suggestion( span, "replace `_` with the correct type", diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 6baadb8febd..b72fae96e4c 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -5,7 +5,7 @@ pub use self::ConsumeMode::*; // Export these here so that Clippy can use them. -pub use mc::{Place, PlaceBase, Projection}; +pub use mc::{PlaceBase, PlaceWithHirId, Projection}; use rustc_hir as hir; use rustc_hir::def::Res; @@ -25,13 +25,13 @@ use rustc_span::Span; pub trait Delegate<'tcx> { // The value found at `place` is either copied or moved, depending // on mode. - fn consume(&mut self, place: &mc::Place<'tcx>, mode: ConsumeMode); + fn consume(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, mode: ConsumeMode); // The value found at `place` is being borrowed with kind `bk`. - fn borrow(&mut self, place: &mc::Place<'tcx>, bk: ty::BorrowKind); + fn borrow(&mut self, place_with_id: &mc::PlaceWithHirId<'tcx>, bk: ty::BorrowKind); - // The path at `place` is being assigned to. - fn mutate(&mut self, assignee_place: &mc::Place<'tcx>); + // The path at `place_with_id` is being assigned to. + fn mutate(&mut self, assignee_place: &mc::PlaceWithHirId<'tcx>); } #[derive(Copy, Clone, PartialEq, Debug)] @@ -113,11 +113,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.mc.tcx() } - fn delegate_consume(&mut self, place: &Place<'tcx>) { - debug!("delegate_consume(place={:?})", place); + fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) { + debug!("delegate_consume(place_with_id={:?})", place_with_id); - let mode = copy_or_move(&self.mc, place); - self.delegate.consume(place, mode); + let mode = copy_or_move(&self.mc, place_with_id); + self.delegate.consume(place_with_id, mode); } fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { @@ -129,22 +129,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) { debug!("consume_expr(expr={:?})", expr); - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(&place); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate_consume(&place_with_id); self.walk_expr(expr); } fn mutate_expr(&mut self, expr: &hir::Expr<'_>) { - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(&place); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate.mutate(&place_with_id); self.walk_expr(expr); } fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) { debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); - let place = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(&place, bk); + let place_with_id = return_if_err!(self.mc.cat_expr(expr)); + self.delegate.borrow(&place_with_id, bk); self.walk_expr(expr) } @@ -384,7 +384,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_place.ty.kind { + match with_place.place.ty.kind { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -422,14 +422,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // process. fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) { let adjustments = self.mc.tables.expr_adjustments(expr); - let mut place = return_if_err!(self.mc.cat_expr_unadjusted(expr)); + let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr)); for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(&place); + self.delegate_consume(&place_with_id); } adjustment::Adjust::Deref(None) => {} @@ -441,14 +441,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(&place, bk); + self.delegate.borrow(&place_with_id, bk); } adjustment::Adjust::Borrow(ref autoref) => { - self.walk_autoref(expr, &place, autoref); + self.walk_autoref(expr, &place_with_id, autoref); } } - place = return_if_err!(self.mc.cat_expr_adjusted(expr, place, &adjustment)); + place_with_id = + return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment)); } } @@ -458,7 +459,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_autoref( &mut self, expr: &hir::Expr<'_>, - base_place: &mc::Place<'tcx>, + base_place: &mc::PlaceWithHirId<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>, ) { debug!( @@ -479,7 +480,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - fn walk_arm(&mut self, discr_place: &Place<'tcx>, arm: &hir::Arm<'_>) { + fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { self.walk_pat(discr_place, &arm.pat); if let Some(hir::Guard::If(ref e)) = arm.guard { @@ -491,12 +492,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) - fn walk_irrefutable_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) { + fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { self.walk_pat(discr_place, pat); } /// The core driver for walking a pattern - fn walk_pat(&mut self, discr_place: &Place<'tcx>, pat: &hir::Pat<'_>) { + fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); let tcx = self.tcx(); @@ -569,7 +570,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { closure_hir_id: hir::HirId, closure_span: Span, var_id: hir::HirId, - ) -> mc::McResult<mc::Place<'tcx>> { + ) -> mc::McResult<mc::PlaceWithHirId<'tcx>> { // Create the place for the variable being borrowed, from the // perspective of the creator (parent) of the closure. let var_ty = self.mc.node_ty(var_id)?; @@ -579,7 +580,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn copy_or_move<'a, 'tcx>( mc: &mc::MemCategorizationContext<'a, 'tcx>, - place: &Place<'tcx>, + place_with_id: &PlaceWithHirId<'tcx>, ) -> ConsumeMode { - if !mc.type_is_copy_modulo_regions(place.ty, place.span) { Move } else { Copy } + if !mc.type_is_copy_modulo_regions( + place_with_id.place.ty, + mc.tcx().hir().span(place_with_id.hir_id), + ) { + Move + } else { + Copy + } } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index 93d01ccd66f..d619d37be2d 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -74,22 +74,24 @@ pub enum PlaceBase { } #[derive(Clone, Debug)] -pub enum Projection<'tcx> { +pub enum ProjectionKind<'tcx> { /// A dereference of a pointer, reference or `Box<T>` of the given type Deref(Ty<'tcx>), /// An index or a field Other, } +#[derive(Clone, Debug)] +pub struct Projection<'tcx> { + /// Defines the type of access + kind: ProjectionKind<'tcx>, +} + /// A `Place` represents how a value is located in memory. /// /// This is an HIR version of `mir::Place` #[derive(Clone, Debug)] pub struct Place<'tcx> { - /// `HirId` of the expression or pattern producing this value. - pub hir_id: hir::HirId, - /// The `Span` of the expression or pattern producing this value. - pub span: Span, /// The type of the `Place` pub ty: Ty<'tcx>, /// The "outermost" place that holds this value. @@ -98,6 +100,32 @@ pub struct Place<'tcx> { pub projections: Vec<Projection<'tcx>>, } +/// A `PlaceWithHirId` represents how a value is located in memory. +/// +/// This is an HIR version of `mir::Place` +#[derive(Clone, Debug)] +pub struct PlaceWithHirId<'tcx> { + /// `HirId` of the expression or pattern producing this value. + pub hir_id: hir::HirId, + + /// Information about the `Place` + pub place: Place<'tcx>, +} + +impl<'tcx> PlaceWithHirId<'tcx> { + crate fn new( + hir_id: hir::HirId, + ty: Ty<'tcx>, + base: PlaceBase, + projections: Vec<Projection<'tcx>>, + ) -> PlaceWithHirId<'tcx> { + PlaceWithHirId { + hir_id: hir_id, + place: Place { ty: ty, base: base, projections: projections }, + } + } +} + impl<'tcx> Place<'tcx> { /// Returns an iterator of the types that have to be dereferenced to access /// the `Place`. @@ -107,7 +135,7 @@ impl<'tcx> Place<'tcx> { ///`*const u32` then `&*const u32`. crate fn deref_tys(&self) -> impl Iterator<Item = Ty<'tcx>> + '_ { self.projections.iter().rev().filter_map(|proj| { - if let Projection::Deref(deref_ty) = *proj { Some(deref_ty) } else { None } + if let ProjectionKind::Deref(deref_ty) = proj.kind { Some(deref_ty) } else { None } }) } } @@ -280,14 +308,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { Ok(ret_ty) } - crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> { + crate fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { // This recursion helper avoids going through *too many* // adjustments, since *only* non-overloaded deref recurses. fn helper<'a, 'tcx>( mc: &MemCategorizationContext<'a, 'tcx>, expr: &hir::Expr<'_>, adjustments: &[adjustment::Adjustment<'tcx>], - ) -> McResult<Place<'tcx>> { + ) -> McResult<PlaceWithHirId<'tcx>> { match adjustments.split_last() { None => mc.cat_expr_unadjusted(expr), Some((adjustment, previous)) => { @@ -302,9 +330,9 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { crate fn cat_expr_adjusted( &self, expr: &hir::Expr<'_>, - previous: Place<'tcx>, + previous: PlaceWithHirId<'tcx>, adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult<Place<'tcx>> { + ) -> McResult<PlaceWithHirId<'tcx>> { self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) } @@ -313,9 +341,9 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { expr: &hir::Expr<'_>, previous: F, adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult<Place<'tcx>> + ) -> McResult<PlaceWithHirId<'tcx>> where - F: FnOnce() -> McResult<Place<'tcx>>, + F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>, { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); let target = self.resolve_vars_if_possible(&adjustment.target); @@ -342,7 +370,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } } - crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<Place<'tcx>> { + crate fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> { debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr); let expr_ty = self.expr_ty(expr)?; @@ -418,7 +446,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { span: Span, expr_ty: Ty<'tcx>, res: Res, - ) -> McResult<Place<'tcx>> { + ) -> McResult<PlaceWithHirId<'tcx>> { debug!("cat_res: id={:?} expr={:?} def={:?}", hir_id, expr_ty, res); match res { @@ -433,25 +461,15 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)), - Res::Def(DefKind::Static, _) => Ok(Place { - hir_id, - span, - ty: expr_ty, - base: PlaceBase::StaticItem, - projections: Vec::new(), - }), + Res::Def(DefKind::Static, _) => { + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) + } Res::Local(var_id) => { if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) { - self.cat_upvar(hir_id, span, var_id) + self.cat_upvar(hir_id, var_id) } else { - Ok(Place { - hir_id, - span, - ty: expr_ty, - base: PlaceBase::Local(var_id), - projections: Vec::new(), - }) + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new())) } } @@ -464,12 +482,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Note: the actual upvar access contains invisible derefs of closure /// environment and upvar reference as appropriate. Only regionck cares /// about these dereferences, so we let it compute them as needed. - fn cat_upvar( - &self, - hir_id: hir::HirId, - span: Span, - var_id: hir::HirId, - ) -> McResult<Place<'tcx>> { + fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> { let closure_expr_def_id = self.body_owner; let upvar_id = ty::UpvarId { @@ -478,22 +491,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; let var_ty = self.node_ty(var_id)?; - let ret = Place { - hir_id, - span, - ty: var_ty, - base: PlaceBase::Upvar(upvar_id), - projections: Vec::new(), - }; + let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()); debug!("cat_upvar ret={:?}", ret); Ok(ret) } - crate fn cat_rvalue(&self, hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>) -> Place<'tcx> { + crate fn cat_rvalue( + &self, + hir_id: hir::HirId, + span: Span, + expr_ty: Ty<'tcx>, + ) -> PlaceWithHirId<'tcx> { debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span); - let ret = - Place { hir_id, span, base: PlaceBase::Rvalue, projections: Vec::new(), ty: expr_ty }; + let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()); debug!("cat_rvalue ret={:?}", ret); ret } @@ -501,18 +512,12 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { crate fn cat_projection<N: HirNode>( &self, node: &N, - base_place: Place<'tcx>, + base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, - ) -> Place<'tcx> { - let mut projections = base_place.projections; - projections.push(Projection::Other); - let ret = Place { - hir_id: node.hir_id(), - span: node.span(), - ty, - base: base_place.base, - projections, - }; + ) -> PlaceWithHirId<'tcx> { + let mut projections = base_place.place.projections; + projections.push(Projection { kind: ProjectionKind::Other }); + let ret = PlaceWithHirId::new(node.hir_id(), ty, base_place.place.base, projections); debug!("cat_field ret {:?}", ret); ret } @@ -521,7 +526,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { &self, expr: &hir::Expr<'_>, base: &hir::Expr<'_>, - ) -> McResult<Place<'tcx>> { + ) -> McResult<PlaceWithHirId<'tcx>> { debug!("cat_overloaded_place(expr={:?}, base={:?})", expr, base); // Reconstruct the output assuming it's a reference with the @@ -540,10 +545,14 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_deref(expr, base) } - fn cat_deref(&self, node: &impl HirNode, base_place: Place<'tcx>) -> McResult<Place<'tcx>> { + fn cat_deref( + &self, + node: &impl HirNode, + base_place: PlaceWithHirId<'tcx>, + ) -> McResult<PlaceWithHirId<'tcx>> { debug!("cat_deref: base_place={:?}", base_place); - let base_ty = base_place.ty; + let base_ty = base_place.place.ty; let deref_ty = match base_ty.builtin_deref(true) { Some(mt) => mt.ty, None => { @@ -551,28 +560,22 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { return Err(()); } }; - let mut projections = base_place.projections; - projections.push(Projection::Deref(base_ty)); - - let ret = Place { - hir_id: node.hir_id(), - span: node.span(), - ty: deref_ty, - base: base_place.base, - projections, - }; + let mut projections = base_place.place.projections; + projections.push(Projection { kind: ProjectionKind::Deref(base_ty) }); + + let ret = PlaceWithHirId::new(node.hir_id(), deref_ty, base_place.place.base, projections); debug!("cat_deref ret {:?}", ret); Ok(ret) } crate fn cat_pattern<F>( &self, - place: Place<'tcx>, + place: PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, mut op: F, ) -> McResult<()> where - F: FnMut(&Place<'tcx>, &hir::Pat<'_>), + F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { self.cat_pattern_(place, pat, &mut op) } @@ -580,24 +583,24 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_<F>( &self, - mut place: Place<'tcx>, + mut place_with_id: PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, op: &mut F, ) -> McResult<()> where - F: FnMut(&Place<'tcx>, &hir::Pat<'_>), + F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), { - // Here, `place` is the `Place` being matched and pat is the pattern it + // Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it // is being matched against. // // In general, the way that this works is that we walk down the pattern, - // constructing a `Place` that represents the path that will be taken + // constructing a `PlaceWithHirId` that represents the path that will be taken // to reach the value being matched. - debug!("cat_pattern(pat={:?}, place={:?})", pat, place); + debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id); - // If (pattern) adjustments are active for this pattern, adjust the `Place` correspondingly. - // `Place`s are constructed differently from patterns. For example, in + // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. + // `PlaceWithHirId`s are constructed differently from patterns. For example, in // // ``` // match foo { @@ -607,7 +610,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // ``` // // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the - // corresponding `Place` we start with the `Place` for `foo`, and then, by traversing the + // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the // pattern, try to answer the question: given the address of `foo`, how is `x` reached? // // `&&Some(x,)` `place_foo` @@ -629,29 +632,29 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. for _ in 0..self.tables.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0) { - debug!("cat_pattern: applying adjustment to place={:?}", place); - place = self.cat_deref(pat, place)?; + debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id); + place_with_id = self.cat_deref(pat, place_with_id)?; } - let place = place; // lose mutability - debug!("cat_pattern: applied adjustment derefs to get place={:?}", place); + let place_with_id = place_with_id; // lose mutability + debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id); - // Invoke the callback, but only now, after the `place` has adjusted. + // Invoke the callback, but only now, after the `place_with_id` has adjusted. // // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that - // case, the initial `place` will be that for `&Some(3)` and the pattern is `Some(x)`. We + // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We // don't want to call `op` with these incompatible values. As written, what happens instead // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)` // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with // that (where the `ref` on `x` is implied). - op(&place, pat); + op(&place_with_id, pat); match pat.kind { PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => { // S(p1, ..., pN) or (p1, ..., pN) for subpat in subpats.iter() { let subpat_ty = self.pat_ty_adjusted(&subpat)?; - let sub_place = self.cat_projection(pat, place.clone(), subpat_ty); + let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty); self.cat_pattern_(sub_place, &subpat, op)?; } } @@ -660,44 +663,44 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // S { f1: p1, ..., fN: pN } for fp in field_pats { let field_ty = self.pat_ty_adjusted(&fp.pat)?; - let field_place = self.cat_projection(pat, place.clone(), field_ty); + let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty); self.cat_pattern_(field_place, &fp.pat, op)?; } } PatKind::Or(pats) => { for pat in pats { - self.cat_pattern_(place.clone(), &pat, op)?; + self.cat_pattern_(place_with_id.clone(), &pat, op)?; } } PatKind::Binding(.., Some(ref subpat)) => { - self.cat_pattern_(place, &subpat, op)?; + self.cat_pattern_(place_with_id, &subpat, op)?; } PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subplace = self.cat_deref(pat, place)?; + let subplace = self.cat_deref(pat, place_with_id)?; self.cat_pattern_(subplace, &subpat, op)?; } PatKind::Slice(before, ref slice, after) => { - let element_ty = match place.ty.builtin_index() { + let element_ty = match place_with_id.place.ty.builtin_index() { Some(ty) => ty, None => { - debug!("explicit index of non-indexable type {:?}", place); + debug!("explicit index of non-indexable type {:?}", place_with_id); return Err(()); } }; - let elt_place = self.cat_projection(pat, place.clone(), element_ty); + let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty); for before_pat in before { self.cat_pattern_(elt_place.clone(), &before_pat, op)?; } if let Some(ref slice_pat) = *slice { let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; - let slice_place = self.cat_projection(pat, place, slice_pat_ty); + let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty); self.cat_pattern_(slice_place, &slice_pat, op)?; } for after_pat in after { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index eee0f764373..cae09267994 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -339,7 +339,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_sig(current, sig, variance); } - ty::Error => { + ty::Error(_) => { // we encounter this when walking the trait references for object // types, where we use Error as the Self type } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index adb2ae9a5d6..73fe87b05d4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1717,7 +1717,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { ty::Placeholder(..) => panic!("Placeholder"), ty::GeneratorWitness(..) => panic!("GeneratorWitness"), ty::Infer(..) => panic!("Infer"), - ty::Error => panic!("Error"), + ty::Error(_) => panic!("Error"), } } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c129e54c0f2..7a6626766d3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -192,6 +192,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { fn next(&mut self) -> Option<Self::Item> { let event = self.inner.next(); let compile_fail; + let should_panic; let ignore; let edition; if let Some(Event::Start(Tag::CodeBlock(kind))) = event { @@ -205,6 +206,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { return Some(Event::Start(Tag::CodeBlock(kind))); } compile_fail = parse_result.compile_fail; + should_panic = parse_result.should_panic; ignore = parse_result.ignore; edition = parse_result.edition; } else { @@ -280,6 +282,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { Some(("This example is not tested".to_owned(), "ignore")) } else if compile_fail { Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) + } else if should_panic { + Some(("This example panics".to_owned(), "should_panic")) } else if explicit_edition { Some((format!("This code runs with edition {}", edition), "edition")) } else { @@ -295,6 +299,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { " ignore" } else if compile_fail { " compile_fail" + } else if should_panic { + " should_panic" } else if explicit_edition { " edition " } else { @@ -314,6 +320,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { " ignore" } else if compile_fail { " compile_fail" + } else if should_panic { + " should_panic" } else if explicit_edition { " edition " } else { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 07631093edd..1681b73d0c2 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4338,6 +4338,8 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { } } + sidebar.push_str(&sidebar_assoc_items(it)); + sidebar.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>"); if t.auto { sidebar.push_str( @@ -4346,8 +4348,6 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { ); } - sidebar.push_str(&sidebar_assoc_items(it)); - write!(buf, "<div class=\"block items\">{}</div>", sidebar) } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 953f61a3772..8d53b057953 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -100,6 +100,8 @@ function defocusSearchBar() { // 2 for "In Return Types" var currentTab = 0; + var mouseMovedAfterSearch = true; + var titleBeforeSearch = document.title; function clearInputTimeout() { @@ -162,6 +164,7 @@ function defocusSearchBar() { } addClass(main, "hidden"); removeClass(search, "hidden"); + mouseMovedAfterSearch = false; } function hideSearchResults(search) { @@ -424,6 +427,12 @@ function defocusSearchBar() { document.addEventListener("keypress", handleShortcut); document.addEventListener("keydown", handleShortcut); + function resetMouseMoved(ev) { + mouseMovedAfterSearch = true; + } + + document.addEventListener("mousemove", resetMouseMoved); + var handleSourceHighlight = (function() { var prev_line_id = 0; @@ -1353,20 +1362,22 @@ function defocusSearchBar() { } }; var mouseover_func = function(e) { - var el = e.target; - // to retrieve the real "owner" of the event. - while (el.tagName !== "TR") { - el = el.parentNode; - } - clearTimeout(hoverTimeout); - hoverTimeout = setTimeout(function() { - onEachLazy(document.getElementsByClassName("search-results"), function(e) { - onEachLazy(e.getElementsByClassName("result"), function(i_e) { - removeClass(i_e, "highlighted"); + if (mouseMovedAfterSearch) { + var el = e.target; + // to retrieve the real "owner" of the event. + while (el.tagName !== "TR") { + el = el.parentNode; + } + clearTimeout(hoverTimeout); + hoverTimeout = setTimeout(function() { + onEachLazy(document.getElementsByClassName("search-results"), function(e) { + onEachLazy(e.getElementsByClassName("result"), function(i_e) { + removeClass(i_e, "highlighted"); + }); }); - }); - addClass(el, "highlighted"); - }, 20); + addClass(el, "highlighted"); + }, 20); + } }; onEachLazy(document.getElementsByClassName("search-results"), function(e) { onEachLazy(e.getElementsByClassName("result"), function(i_e) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 2cb3347135c..9c6dd25394d 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1089,7 +1089,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { border-style: solid; } -.tooltip.compile_fail, .tooltip.ignore { +.tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore { font-weight: bold; font-size: 20px; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index a2986c7b927..41dcb5c2450 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -283,6 +283,14 @@ pre.compile_fail:hover, .information:hover + pre.compile_fail { border-left: 2px solid #f00; } +pre.should_panic { + border-left: 2px solid rgba(255,0,0,.8); +} + +pre.should_panic:hover, .information:hover + pre.should_panic { + border-left: 2px solid #f00; +} + pre.ignore { border-left: 2px solid rgba(255,142,0,.6); } @@ -299,6 +307,14 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #f00; } +.tooltip.should_panic { + color: rgba(255,0,0,.8); +} + +.information > .should_panic:hover { + color: #f00; +} + .tooltip.ignore { color: rgba(255,142,0,.6); } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index be173d8eb46..386fe2398e6 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -278,6 +278,14 @@ pre.compile_fail:hover, .information:hover + pre.compile_fail { border-left: 2px solid #f00; } +pre.should_panic { + border-left: 2px solid rgba(255,0,0,.5); +} + +pre.should_panic:hover, .information:hover + pre.should_panic { + border-left: 2px solid #f00; +} + pre.ignore { border-left: 2px solid rgba(255,142,0,.6); } @@ -294,6 +302,14 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #f00; } +.tooltip.should_panic { + color: rgba(255,0,0,.5); +} + +.information > .should_panic:hover { + color: #f00; +} + .tooltip.ignore { color: rgba(255,142,0,.6); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 82d6cda986a..95d113166e0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -165,9 +165,8 @@ fn opts() -> Vec<RustcOptGroup> { o.optmulti( "", "passes", - "list of passes to also run, you might want \ - to pass it multiple times; a value of `list` \ - will print available passes", + "list of passes to also run, you might want to pass it multiple times; a value of \ + `list` will print available passes", "PASSES", ) }), @@ -248,8 +247,8 @@ fn opts() -> Vec<RustcOptGroup> { "e", "extend-css", "To add some CSS rules with a given file to generate doc with your \ - own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", + own theme. However, your theme might break if the rustdoc's generated HTML \ + changes, so be careful!", "PATH", ) }), @@ -262,7 +261,7 @@ fn opts() -> Vec<RustcOptGroup> { "", "playground-url", "URL to send code snippets to, may be reset by --markdown-playground-url \ - or `#![doc(html_playground_url=...)]`", + or `#![doc(html_playground_url=...)]`", "URL", ) }), @@ -276,8 +275,7 @@ fn opts() -> Vec<RustcOptGroup> { o.optflag( "", "sort-modules-by-appearance", - "sort modules by where they appear in the \ - program, rather than alphabetically", + "sort modules by where they appear in the program, rather than alphabetically", ) }), stable("theme", |o| { @@ -358,7 +356,7 @@ fn opts() -> Vec<RustcOptGroup> { "", "static-root-path", "Path string to force loading static files from in output pages. \ - If not set, uses combinations of '../' to reach the documentation root.", + If not set, uses combinations of '../' to reach the documentation root.", "PATH", ) }), diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 83029a86420..490afb5a043 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -74,3 +74,8 @@ std_detect_dlsym_getauxval = [] threads = 125 # Maximum heap size heap_size = 0x8000000 + +[[bench]] +name = "stdbenches" +path = "benches/lib.rs" +test = true diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index d752ba89a27..b392d6e7226 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -832,11 +832,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f32 { - if self == Self::NEG_INFINITY { - Self::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) - } + (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self) } /// Inverse hyperbolic cosine function. @@ -1413,6 +1409,8 @@ mod tests { 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); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); } #[test] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 9cd60d846a7..72268d2cc2f 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -834,11 +834,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn asinh(self) -> f64 { - if self == Self::NEG_INFINITY { - Self::NEG_INFINITY - } else { - (self + ((self * self) + 1.0).sqrt()).ln().copysign(self) - } + (self.abs() + ((self * self) + 1.0).sqrt()).ln().copysign(self) } /// Inverse hyperbolic cosine function. @@ -1442,6 +1438,8 @@ mod tests { // issue 63271 assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); } #[test] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d6493454db5..ef699ede2a1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -298,6 +298,7 @@ #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] +#![feature(raw_ref_macros)] #![feature(renamed_spin_loop)] #![feature(rustc_attrs)] #![feature(rustc_private)] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 6a120f930ab..d22ac1d5385 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -201,8 +201,7 @@ fn default_hook(info: &PanicInfo<'_>) { if FIRST_PANIC.swap(false, Ordering::SeqCst) { let _ = writeln!( err, - "note: run with `RUST_BACKTRACE=1` \ - environment variable to display a backtrace" + "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" ); } } @@ -454,10 +453,7 @@ fn rust_panic_with_hook( // process real quickly as we don't want to try calling it again as it'll // probably just panic again. if panics > 2 { - util::dumb_print(format_args!( - "thread panicked while processing \ - panic. aborting.\n" - )); + util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n")); intrinsics::abort() } @@ -489,10 +485,7 @@ fn rust_panic_with_hook( // have limited options. Currently our preference is to // just abort. In the future we may consider resuming // unwinding or otherwise exiting the thread cleanly. - util::dumb_print(format_args!( - "thread panicked while panicking. \ - aborting.\n" - )); + util::dumb_print(format_args!("thread panicked while panicking. aborting.\n")); intrinsics::abort() } diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 3085c3d8296..48f7cf16988 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -10,22 +10,6 @@ //! things, particularly traits, which are used in almost every single Rust //! program. //! -//! On a technical level, Rust inserts -//! -//! ``` -//! # #[allow(unused_extern_crates)] -//! extern crate std; -//! ``` -//! -//! into the crate root of every crate, and -//! -//! ``` -//! # #[allow(unused_imports)] -//! use std::prelude::v1::*; -//! ``` -//! -//! into every module. -//! //! # Other preludes //! //! Preludes can be seen as a pattern to make using multiple types more diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs index 9e588c4265a..8a788a9265f 100644 --- a/src/libstd/sys/hermit/net.rs +++ b/src/libstd/sys/hermit/net.rs @@ -147,10 +147,7 @@ impl TcpStream { .map_err(|_| io::Error::new(ErrorKind::Other, "peer_addr failed"))?; let saddr = match ipaddr { - Ipv4(ref addr) => SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(addr.0[0], addr.0[1], addr.0[2], addr.0[3])), - port, - ), + Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port), Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port), _ => { return Err(io::Error::new(ErrorKind::Other, "peer_addr failed")); @@ -227,10 +224,7 @@ impl TcpListener { let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port()) .map_err(|_| io::Error::new(ErrorKind::Other, "accept failed"))?; let saddr = match ipaddr { - Ipv4(ref addr) => SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(addr.0[0], addr.0[1], addr.0[2], addr.0[3])), - port, - ), + Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port), Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port), _ => { return Err(io::Error::new(ErrorKind::Other, "accept failed")); diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 732cd677a18..e4d71493604 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -242,7 +242,8 @@ pub trait PermissionsExt { /// let permissions = metadata.permissions(); /// /// println!("permissions: {:o}", permissions.mode()); - /// Ok(()) } + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -262,7 +263,8 @@ pub trait PermissionsExt { /// /// permissions.set_mode(0o644); // Read/write for owner and read for others. /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 2d7267263de..6e33cdd3c48 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -428,6 +428,7 @@ mod tests { // ignored there. #[cfg_attr(target_arch = "arm", ignore)] #[cfg_attr(target_arch = "aarch64", ignore)] + #[cfg_attr(target_arch = "riscv64", ignore)] fn test_process_mask() { unsafe { // Test to make sure that a signal mask does not get inherited. diff --git a/src/libstd/time.rs b/src/libstd/time.rs index bc3bfde6d75..84fa35e01bb 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -60,6 +60,21 @@ pub use core::time::Duration; /// } /// ``` /// +/// # OS-specific behaviors +/// +/// An `Instant` is a wrapper around system-specific types and it may behave +/// differently depending on the underlying operating system. For example, +/// the following snippet is fine on Linux but panics on macOS: +/// +/// ```no_run +/// use std::time::{Instant, Duration}; +/// +/// let now = Instant::now(); +/// let max_nanoseconds = u64::MAX / 1_000_000_000; +/// let duration = Duration::new(max_nanoseconds, 0); +/// println!("{:?}", now + duration); +/// ``` +/// /// # Underlying System calls /// Currently, the following system calls are being used to get the current time using `now()`: /// @@ -796,11 +811,11 @@ mod tests { // Right now for CI this test is run in an emulator, and apparently the // aarch64 emulator's sense of time is that we're still living in the - // 70s. + // 70s. This is also true for riscv (also qemu) // // Otherwise let's assume that we're all running computers later than // 2000. - if !cfg!(target_arch = "aarch64") { + if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") { assert!(a > thirty_years); } diff --git a/src/llvm-project b/src/llvm-project -Subproject 02e0d7fa5547f2b270b8b57cf4f4f8e177153c8 +Subproject 0ddefeca92b2e1835c80e9b01d9ecc7efc906b1 diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 3d252fe70af..9bc111c26ba 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -424,6 +424,12 @@ extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) { printf("Available features for this target:\n"); for (auto &Feature : FeatTable) printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc); + printf("\nRust-specific features:\n"); + printf(" %-*s - %s.\n", + MaxFeatLen, + "crt-static", + "Enables libraries with C Run-time Libraries(CRT) to be statically linked" + ); printf("\n"); printf("Use +feature to enable a feature, or -feature to disable it.\n" @@ -711,11 +717,12 @@ enum class LLVMRustOptStage { }; struct LLVMRustSanitizerOptions { + bool SanitizeAddress; + bool SanitizeAddressRecover; bool SanitizeMemory; + bool SanitizeMemoryRecover; + int SanitizeMemoryTrackOrigins; bool SanitizeThread; - bool SanitizeAddress; - bool SanitizeRecover; - int SanitizeMemoryTrackOrigins; }; extern "C" void @@ -802,7 +809,7 @@ LLVMRustOptimizeWithNewPassManager( if (SanitizerOptions->SanitizeMemory) { MemorySanitizerOptions Options( SanitizerOptions->SanitizeMemoryTrackOrigins, - SanitizerOptions->SanitizeRecover, + SanitizerOptions->SanitizeMemoryRecover, /*CompileKernel=*/false); #if LLVM_VERSION_GE(10, 0) PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) { @@ -836,14 +843,14 @@ LLVMRustOptimizeWithNewPassManager( OptimizerLastEPCallbacks.push_back( [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { FPM.addPass(AddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover, + /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover, /*UseAfterScope=*/true)); } ); PipelineStartEPCallbacks.push_back( [SanitizerOptions](ModulePassManager &MPM) { MPM.addPass(ModuleAddressSanitizerPass( - /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover)); + /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); } ); } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 4704622922a..cdb3a157eab 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -5,6 +5,7 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Bitcode/BitcodeWriterPass.h" @@ -1364,6 +1365,11 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles)); } +extern "C" LLVMValueRef LLVMRustGetInstrprofIncrementIntrinsic(LLVMModuleRef M) { + return wrap(llvm::Intrinsic::getDeclaration(unwrap(M), + (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment)); +} + extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, LLVMValueRef Src, unsigned SrcAlign, diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs new file mode 100644 index 00000000000..ba2d8a363cd --- /dev/null +++ b/src/test/assembly/asm/hexagon-types.rs @@ -0,0 +1,130 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target hexagon-unknown-linux-musl + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: sym_static: +// CHECK: InlineAsm Start +// CHECK: r0 = #extern_static +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_static() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: InlineAsm Start +// CHECK: r0 = #extern_func +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_fn() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_func); +} + +// This is a test for multi-instruction packets, +// which require the escaped braces. +// +// CHECK-LABEL: packet: +// CHECK: InlineAsm Start +// CHECK: { +// CHECK: r{{[0-9]+}} = r0 +// CHECK: memw(r1) = r{{[0-9]+}} +// CHECK: } +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn packet() { + let val = 1024; + asm!("{{ + {} = r0 + memw(r1) = {} + }}", out(reg) _, in(reg) &val); +} + +// CHECK-LABEL: ptr: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_ptr ptr reg); + +// CHECK-LABEL: reg_f32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_f32 f32 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i8: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i16 i16 reg); diff --git a/src/test/codegen-units/partitioning/compiler-builtins.rs b/src/test/codegen-units/partitioning/compiler-builtins.rs deleted file mode 100644 index 25195743b04..00000000000 --- a/src/test/codegen-units/partitioning/compiler-builtins.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Verifies that during compiler_builtins compilation the codegen units are kept -// unmerged. Even when only a single codegen unit is requested with -Ccodegen-units=1. -// -// compile-flags: -Zprint-mono-items=eager -Ccodegen-units=1 - -#![compiler_builtins] -#![crate_type="lib"] -#![feature(compiler_builtins)] - -mod atomics { - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_1[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_1() {} - - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_2[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_2() {} - - //~ MONO_ITEM fn compiler_builtins::atomics[0]::sync_3[0] @@ compiler_builtins-cgu.0[External] - #[no_mangle] - pub extern "C" fn sync_3() {} -} - -mod x { - //~ MONO_ITEM fn compiler_builtins::x[0]::x[0] @@ compiler_builtins-cgu.1[External] - #[no_mangle] - pub extern "C" fn x() {} -} - -mod y { - //~ MONO_ITEM fn compiler_builtins::y[0]::y[0] @@ compiler_builtins-cgu.2[External] - #[no_mangle] - pub extern "C" fn y() {} -} - -mod z { - //~ MONO_ITEM fn compiler_builtins::z[0]::z[0] @@ compiler_builtins-cgu.3[External] - #[no_mangle] - pub extern "C" fn z() {} -} diff --git a/src/test/codegen/cdylib-external-inline-fns.rs b/src/test/codegen/cdylib-external-inline-fns.rs new file mode 100644 index 00000000000..519be6b6a99 --- /dev/null +++ b/src/test/codegen/cdylib-external-inline-fns.rs @@ -0,0 +1,43 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "cdylib"] + +// CHECK: define void @a() +#[no_mangle] +#[inline] +pub extern "C" fn a() {} + +// CHECK: define void @b() +#[export_name = "b"] +#[inline] +pub extern "C" fn b() {} + +// CHECK: define void @c() +#[no_mangle] +#[inline] +extern "C" fn c() {} + +// CHECK: define void @d() +#[export_name = "d"] +#[inline] +extern "C" fn d() {} + +// CHECK: define void @e() +#[no_mangle] +#[inline(always)] +pub extern "C" fn e() {} + +// CHECK: define void @f() +#[export_name = "f"] +#[inline(always)] +pub extern "C" fn f() {} + +// CHECK: define void @g() +#[no_mangle] +#[inline(always)] +extern "C" fn g() {} + +// CHECK: define void @h() +#[export_name = "h"] +#[inline(always)] +extern "C" fn h() {} diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs index 78d41e4be0a..59e97601c83 100644 --- a/src/test/codegen/export-no-mangle.rs +++ b/src/test/codegen/export-no-mangle.rs @@ -11,11 +11,21 @@ mod private { #[export_name = "BAR"] static BAR: u32 = 3; - // CHECK: void @foo() + // CHECK: void @a() #[no_mangle] - pub extern fn foo() {} + pub extern fn a() {} - // CHECK: void @bar() - #[export_name = "bar"] - extern fn bar() {} + // CHECK: void @b() + #[export_name = "b"] + extern fn b() {} + + // CHECK: void @c() + #[export_name = "c"] + #[inline] + extern fn c() {} + + // CHECK: void @d() + #[export_name = "d"] + #[inline(always)] + extern fn d() {} } diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs index 90288214499..41820b057f1 100644 --- a/src/test/codegen/external-no-mangle-fns.rs +++ b/src/test/codegen/external-no-mangle-fns.rs @@ -53,3 +53,23 @@ fn x() { core::ptr::read_volatile(&42); } } + +// CHECK: define void @i() +#[no_mangle] +#[inline] +fn i() {} + +// CHECK: define void @j() +#[no_mangle] +#[inline] +pub fn j() {} + +// CHECK: define void @k() +#[no_mangle] +#[inline(always)] +fn k() {} + +// CHECK: define void @l() +#[no_mangle] +#[inline(always)] +pub fn l() {} diff --git a/src/test/codegen/issue-69101-bounds-check.rs b/src/test/codegen/issue-69101-bounds-check.rs new file mode 100644 index 00000000000..8ade583b571 --- /dev/null +++ b/src/test/codegen/issue-69101-bounds-check.rs @@ -0,0 +1,44 @@ +// no-system-llvm +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted in the loop when upfront slicing +// ensures that the slices are big enough. +// In particular, bounds checks were not always optimized out if the upfront +// check was for a greater len than the loop requires. +// (i.e. `already_sliced_no_bounds_check` was not always optimized even when +// `already_sliced_no_bounds_check_exact` was) +// CHECK-LABEL: @already_sliced_no_bounds_check +#[no_mangle] +pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..2048], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// CHECK-LABEL: @already_sliced_no_bounds_check_exact +#[no_mangle] +pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK-NOT: panic_bounds_check + let _ = (&a[..1024], &b[..1024], &mut c[..1024]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} + +// Make sure we're checking for the right thing: there can be a panic if the slice is too small. +// CHECK-LABEL: @already_sliced_bounds_check +#[no_mangle] +pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { + // CHECK: slice_index_len_fail + // CHECK: panic_bounds_check + let _ = (&a[..1023], &b[..2048], &mut c[..2048]); + for i in 0..1024 { + c[i] = a[i] ^ b[i]; + } +} diff --git a/src/test/codegen/sanitizer-memory-track-orgins.rs b/src/test/codegen/sanitizer-memory-track-orgins.rs index 8ea41c5d44b..4bd50508d15 100644 --- a/src/test/codegen/sanitizer-memory-track-orgins.rs +++ b/src/test/codegen/sanitizer-memory-track-orgins.rs @@ -1,9 +1,7 @@ // Verifies that MemorySanitizer track-origins level can be controlled // with -Zsanitizer-memory-track-origins option. // -// needs-sanitizer-support -// only-linux -// only-x86_64 +// needs-sanitizer-memory // revisions:MSAN-0 MSAN-1 MSAN-2 MSAN-1-LTO MSAN-2-LTO // //[MSAN-0] compile-flags: -Zsanitizer=memory diff --git a/src/test/codegen/sanitizer-no-sanitize-inlining.rs b/src/test/codegen/sanitizer-no-sanitize-inlining.rs index d96e76618d3..be0547afa4c 100644 --- a/src/test/codegen/sanitizer-no-sanitize-inlining.rs +++ b/src/test/codegen/sanitizer-no-sanitize-inlining.rs @@ -1,11 +1,9 @@ // Verifies that no_sanitize attribute prevents inlining when // given sanitizer is enabled, but has no effect on inlining otherwise. // -// needs-sanitizer-support -// only-x86_64 -// +// needs-sanitizer-address +// needs-sanitizer-leak // revisions: ASAN LSAN -// //[ASAN] compile-flags: -Zsanitizer=address -C opt-level=3 -Z mir-opt-level=3 //[LSAN] compile-flags: -Zsanitizer=leak -C opt-level=3 -Z mir-opt-level=3 @@ -13,7 +11,7 @@ #![feature(no_sanitize)] // ASAN-LABEL: define void @test -// ASAN: tail call fastcc void @random_inline +// ASAN: call {{.*}} @random_inline // ASAN: } // // LSAN-LABEL: define void @test diff --git a/src/test/codegen/sanitizer-no-sanitize.rs b/src/test/codegen/sanitizer-no-sanitize.rs index dfceb28c8dd..1b2b18822e6 100644 --- a/src/test/codegen/sanitizer-no-sanitize.rs +++ b/src/test/codegen/sanitizer-no-sanitize.rs @@ -1,7 +1,7 @@ // Verifies that no_sanitze attribute can be used to // selectively disable sanitizer instrumentation. // -// needs-sanitizer-support +// needs-sanitizer-address // compile-flags: -Zsanitizer=address #![crate_type="lib"] diff --git a/src/test/codegen/sanitizer-recover.rs b/src/test/codegen/sanitizer-recover.rs index 05b4ab5653c..719f219ce4e 100644 --- a/src/test/codegen/sanitizer-recover.rs +++ b/src/test/codegen/sanitizer-recover.rs @@ -1,9 +1,8 @@ // Verifies that AddressSanitizer and MemorySanitizer // recovery mode can be enabled with -Zsanitizer-recover. // -// needs-sanitizer-support -// only-linux -// only-x86_64 +// needs-sanitizer-address +// needs-sanitizer-memory // revisions:ASAN ASAN-RECOVER MSAN MSAN-RECOVER MSAN-RECOVER-LTO // no-prefer-dynamic // diff --git a/src/test/codegen/staticlib-external-inline-fns.rs b/src/test/codegen/staticlib-external-inline-fns.rs new file mode 100644 index 00000000000..8876ab7376a --- /dev/null +++ b/src/test/codegen/staticlib-external-inline-fns.rs @@ -0,0 +1,43 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "staticlib"] + +// CHECK: define void @a() +#[no_mangle] +#[inline] +pub extern "C" fn a() {} + +// CHECK: define void @b() +#[export_name = "b"] +#[inline] +pub extern "C" fn b() {} + +// CHECK: define void @c() +#[no_mangle] +#[inline] +extern "C" fn c() {} + +// CHECK: define void @d() +#[export_name = "d"] +#[inline] +extern "C" fn d() {} + +// CHECK: define void @e() +#[no_mangle] +#[inline(always)] +pub extern "C" fn e() {} + +// CHECK: define void @f() +#[export_name = "f"] +#[inline(always)] +pub extern "C" fn f() {} + +// CHECK: define void @g() +#[no_mangle] +#[inline(always)] +extern "C" fn g() {} + +// CHECK: define void @h() +#[export_name = "h"] +#[inline(always)] +extern "C" fn h() {} diff --git a/src/test/codegen/vec-clear.rs b/src/test/codegen/vec-clear.rs index b9ffce8b0cb..15bfe421e9d 100644 --- a/src/test/codegen/vec-clear.rs +++ b/src/test/codegen/vec-clear.rs @@ -1,4 +1,3 @@ -// ignore-debug: the debug assertions get in the way // compile-flags: -O #![crate_type = "lib"] diff --git a/src/test/codegen/vec-optimizes-away.rs b/src/test/codegen/vec-optimizes-away.rs index ebede0908c6..9143fad2340 100644 --- a/src/test/codegen/vec-optimizes-away.rs +++ b/src/test/codegen/vec-optimizes-away.rs @@ -1,4 +1,3 @@ -// // ignore-debug: the debug assertions get in the way // no-system-llvm // compile-flags: -O diff --git a/src/test/compile-fail/issue-52443.rs b/src/test/compile-fail/issue-52443.rs index 97619593352..00aca1d14ba 100644 --- a/src/test/compile-fail/issue-52443.rs +++ b/src/test/compile-fail/issue-52443.rs @@ -9,7 +9,7 @@ fn main() { [(); { for _ in 0usize.. {}; 0}]; //~^ ERROR `for` is not allowed in a `const` //~| ERROR calls in constants are limited to constant functions - //~| ERROR references in constants may only refer to immutable values + //~| ERROR mutable references are not allowed in constants //~| ERROR calls in constants are limited to constant functions //~| ERROR evaluation of constant value failed } diff --git a/src/test/compile-fail/specialization/issue-50452.rs b/src/test/compile-fail/specialization/issue-50452.rs index d9e5280c7e1..958f0eb2668 100644 --- a/src/test/compile-fail/specialization/issue-50452.rs +++ b/src/test/compile-fail/specialization/issue-50452.rs @@ -1,6 +1,6 @@ // compile-fail - #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete pub trait Foo { fn foo(); diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs index 04541b94ad7..13e8eb3e44e 100644 --- a/src/test/mir-opt/const_prop/discriminant.rs +++ b/src/test/mir-opt/const_prop/discriminant.rs @@ -1,5 +1,10 @@ // compile-flags: -O +// FIXME(wesleywiser): Ideally, we could const-prop away all of this and just be left with +// `let x = 42` but that doesn't work because const-prop doesn't support `Operand::Indirect` +// and `InterpCx::eval_place()` always forces an allocation which creates the `Indirect`. +// Fixing either of those will allow us to const-prop this away. + // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR rustc.main.ConstProp.diff fn main() { diff --git a/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff index 9979ea95498..1c873f53f37 100644 --- a/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/discriminant/32bit/rustc.main.ConstProp.diff @@ -2,100 +2,93 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11 - let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10 - let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64 - let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44 - let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31 + let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11 + let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10 + let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64 + let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44 + let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31 scope 1 { - debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10 + debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10 - StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64 - StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 -- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 -+ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 + StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10 + StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64 + StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 +- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 ++ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 // ty::Const - // + ty: bool + // + ty: std::option::Option<bool> // + val: Value(Scalar(0x01)) // mir::Constant -- // + span: $DIR/discriminant.rs:6:39: 6:43 +- // + span: $DIR/discriminant.rs:11:39: 11:43 - // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31 -- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 -+ // + span: $DIR/discriminant.rs:6:34: 6:44 +- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31 +- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 ++ // + span: $DIR/discriminant.rs:11:34: 11:44 + // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) } -+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 ++ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x00000001)) + // mir::Constant -+ // + span: $DIR/discriminant.rs:6:21: 6:31 ++ // + span: $DIR/discriminant.rs:11:21: 11:31 + // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) } -+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 ++ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x00000001)) + // mir::Constant -+ // + span: $DIR/discriminant.rs:6:21: 6:31 ++ // + span: $DIR/discriminant.rs:11:21: 11:31 + // + literal: Const { ty: isize, val: Value(Scalar(0x00000001)) } } bb1: { - _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61 + _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61 // ty::Const // + ty: i32 // + val: Value(Scalar(0x0000000a)) // mir::Constant - // + span: $DIR/discriminant.rs:6:59: 6:61 + // + span: $DIR/discriminant.rs:11:59: 11:61 // + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) } - goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb2: { -- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30 -+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30 -+ // ty::Const -+ // + ty: bool -+ // + val: Value(Scalar(0x01)) -+ // mir::Constant -+ // + span: $DIR/discriminant.rs:6:26: 6:30 -+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30 } bb3: { - _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49 + _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49 // ty::Const // + ty: i32 // + val: Value(Scalar(0x0000002a)) // mir::Constant - // + span: $DIR/discriminant.rs:6:47: 6:49 + // + span: $DIR/discriminant.rs:11:47: 11:49 // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) } - goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb4: { - _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68 + _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68 // ty::Const // + ty: i32 // + val: Value(Scalar(0x00000000)) // mir::Constant - // + span: $DIR/discriminant.rs:6:67: 6:68 + // + span: $DIR/discriminant.rs:11:67: 11:68 // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) } - StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68 - StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69 - _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2 + StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 + StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 + _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2 // ty::Const // + ty: () // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/discriminant.rs:5:11: 7:2 + // + span: $DIR/discriminant.rs:10:11: 12:2 // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } - StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2 - return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2 + StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 + return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff index ec0341e3de2..75b4b7e5a62 100644 --- a/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/discriminant/64bit/rustc.main.ConstProp.diff @@ -2,100 +2,93 @@ + // MIR for `main` after ConstProp fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:5:11: 5:11 - let _1: i32; // in scope 0 at $DIR/discriminant.rs:6:9: 6:10 - let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:6:13: 6:64 - let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:6:34: 6:44 - let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:6:21: 6:31 + let mut _0: (); // return place in scope 0 at $DIR/discriminant.rs:10:11: 10:11 + let _1: i32; // in scope 0 at $DIR/discriminant.rs:11:9: 11:10 + let mut _2: i32; // in scope 0 at $DIR/discriminant.rs:11:13: 11:64 + let mut _3: std::option::Option<bool>; // in scope 0 at $DIR/discriminant.rs:11:34: 11:44 + let mut _4: isize; // in scope 0 at $DIR/discriminant.rs:11:21: 11:31 scope 1 { - debug x => _1; // in scope 1 at $DIR/discriminant.rs:6:9: 6:10 + debug x => _1; // in scope 1 at $DIR/discriminant.rs:11:9: 11:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/discriminant.rs:6:9: 6:10 - StorageLive(_2); // scope 0 at $DIR/discriminant.rs:6:13: 6:64 - StorageLive(_3); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 -- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 -+ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:6:34: 6:44 + StorageLive(_1); // scope 0 at $DIR/discriminant.rs:11:9: 11:10 + StorageLive(_2); // scope 0 at $DIR/discriminant.rs:11:13: 11:64 + StorageLive(_3); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 +- _3 = std::option::Option::<bool>::Some(const true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 ++ _3 = const std::option::Option::<bool>::Some(true); // scope 0 at $DIR/discriminant.rs:11:34: 11:44 // ty::Const - // + ty: bool + // + ty: std::option::Option<bool> // + val: Value(Scalar(0x01)) // mir::Constant -- // + span: $DIR/discriminant.rs:6:39: 6:43 +- // + span: $DIR/discriminant.rs:11:39: 11:43 - // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } -- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:6:21: 6:31 -- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 -+ // + span: $DIR/discriminant.rs:6:34: 6:44 +- _4 = discriminant(_3); // scope 0 at $DIR/discriminant.rs:11:21: 11:31 +- switchInt(move _4) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 ++ // + span: $DIR/discriminant.rs:11:34: 11:44 + // + literal: Const { ty: std::option::Option<bool>, val: Value(Scalar(0x01)) } -+ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 ++ _4 = const 1isize; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant -+ // + span: $DIR/discriminant.rs:6:21: 6:31 ++ // + span: $DIR/discriminant.rs:11:21: 11:31 + // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) } -+ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:6:21: 6:31 ++ switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1]; // scope 0 at $DIR/discriminant.rs:11:21: 11:31 + // ty::Const + // + ty: isize + // + val: Value(Scalar(0x0000000000000001)) + // mir::Constant -+ // + span: $DIR/discriminant.rs:6:21: 6:31 ++ // + span: $DIR/discriminant.rs:11:21: 11:31 + // + literal: Const { ty: isize, val: Value(Scalar(0x0000000000000001)) } } bb1: { - _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:6:59: 6:61 + _2 = const 10i32; // scope 0 at $DIR/discriminant.rs:11:59: 11:61 // ty::Const // + ty: i32 // + val: Value(Scalar(0x0000000a)) // mir::Constant - // + span: $DIR/discriminant.rs:6:59: 6:61 + // + span: $DIR/discriminant.rs:11:59: 11:61 // + literal: Const { ty: i32, val: Value(Scalar(0x0000000a)) } - goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb2: { -- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30 -+ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:6:26: 6:30 -+ // ty::Const -+ // + ty: bool -+ // + val: Value(Scalar(0x01)) -+ // mir::Constant -+ // + span: $DIR/discriminant.rs:6:26: 6:30 -+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30 } bb3: { - _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:6:47: 6:49 + _2 = const 42i32; // scope 0 at $DIR/discriminant.rs:11:47: 11:49 // ty::Const // + ty: i32 // + val: Value(Scalar(0x0000002a)) // mir::Constant - // + span: $DIR/discriminant.rs:6:47: 6:49 + // + span: $DIR/discriminant.rs:11:47: 11:49 // + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) } - goto -> bb4; // scope 0 at $DIR/discriminant.rs:6:13: 6:64 + goto -> bb4; // scope 0 at $DIR/discriminant.rs:11:13: 11:64 } bb4: { - _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:6:13: 6:68 + _1 = Add(move _2, const 0i32); // scope 0 at $DIR/discriminant.rs:11:13: 11:68 // ty::Const // + ty: i32 // + val: Value(Scalar(0x00000000)) // mir::Constant - // + span: $DIR/discriminant.rs:6:67: 6:68 + // + span: $DIR/discriminant.rs:11:67: 11:68 // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) } - StorageDead(_2); // scope 0 at $DIR/discriminant.rs:6:67: 6:68 - StorageDead(_3); // scope 0 at $DIR/discriminant.rs:6:68: 6:69 - _0 = const (); // scope 0 at $DIR/discriminant.rs:5:11: 7:2 + StorageDead(_2); // scope 0 at $DIR/discriminant.rs:11:67: 11:68 + StorageDead(_3); // scope 0 at $DIR/discriminant.rs:11:68: 11:69 + _0 = const (); // scope 0 at $DIR/discriminant.rs:10:11: 12:2 // ty::Const // + ty: () // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/discriminant.rs:5:11: 7:2 + // + span: $DIR/discriminant.rs:10:11: 12:2 // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } - StorageDead(_1); // scope 0 at $DIR/discriminant.rs:7:1: 7:2 - return; // scope 0 at $DIR/discriminant.rs:7:2: 7:2 + StorageDead(_1); // scope 0 at $DIR/discriminant.rs:12:1: 12:2 + return; // scope 0 at $DIR/discriminant.rs:12:2: 12:2 } } diff --git a/src/test/mir-opt/fn-ptr-shim.rs b/src/test/mir-opt/fn-ptr-shim.rs new file mode 100644 index 00000000000..08413c9f6fc --- /dev/null +++ b/src/test/mir-opt/fn-ptr-shim.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmir-opt-level=0 -Zvalidate-mir + +// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee +// (as only `FnDef` and `FnPtr` callees are allowed in MIR). + +// EMIT_MIR rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir +fn main() { + call(noop as fn()); +} + +fn noop() {} + +fn call<F: Fn()>(f: F) { + f(); +} diff --git a/src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir new file mode 100644 index 00000000000..4ecc331afae --- /dev/null +++ b/src/test/mir-opt/fn-ptr-shim/rustc.ops-function-Fn-call.AddMovesForPackedDrops.before.mir @@ -0,0 +1,13 @@ +// MIR for `std::ops::Fn::call` before AddMovesForPackedDrops + +fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> <Self as std::ops::FnOnce<Args>>::Output { + let mut _0: <Self as std::ops::FnOnce<Args>>::Output; // return place in scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL + + bb0: { + _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL + } + + bb1: { + return; // scope 0 at $SRC_DIR/libcore/ops/function.rs:LL:COL + } +} diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs new file mode 100644 index 00000000000..3fe010ef68f --- /dev/null +++ b/src/test/mir-opt/instrument_coverage.rs @@ -0,0 +1,20 @@ +// Test that the initial version of Rust coverage injects count_code_region() placeholder calls, +// at the top of each function. The placeholders are later converted into LLVM instrprof.increment +// intrinsics, during codegen. + +// needs-profiler-support +// compile-flags: -Zinstrument-coverage +// EMIT_MIR rustc.main.InstrumentCoverage.diff +// EMIT_MIR rustc.bar.InstrumentCoverage.diff +fn main() { + loop { + if bar() { + break; + } + } +} + +#[inline(never)] +fn bar() -> bool { + true +} diff --git a/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff new file mode 100644 index 00000000000..1e64379aa0e --- /dev/null +++ b/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff @@ -0,0 +1,41 @@ +- // MIR for `bar` before InstrumentCoverage ++ // MIR for `bar` after InstrumentCoverage + + fn bar() -> bool { + let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17 ++ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 + + bb0: { ++ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ _1 = const std::intrinsics::count_code_region(const 0u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ // ty::Const ++ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region} ++ // + val: Value(Scalar(<ZST>)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000000)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ } ++ ++ bb2: { ++ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 + _0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 + // ty::Const + // + ty: bool + // + val: Value(Scalar(0x01)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:19:5: 19:9 + // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } + return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2 + } + } + diff --git a/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff new file mode 100644 index 00000000000..82d21467827 --- /dev/null +++ b/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff @@ -0,0 +1,82 @@ +- // MIR for `main` before InstrumentCoverage ++ // MIR for `main` after InstrumentCoverage + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 + let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10 ++ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + + bb0: { +- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 ++ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 ++ _4 = const std::intrinsics::count_code_region(const 0u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 ++ // ty::Const ++ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region} ++ // + val: Value(Scalar(<ZST>)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar(<ZST>)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000000)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } + } + + bb1: { + StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + // ty::Const + // + ty: fn() -> bool {bar} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:11:12: 11:15 + // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) } + } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + } + + bb3: { + FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + } + + bb4: { + falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + } + + bb5: { + _1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:11:9: 13:10 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 + goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 + } + + bb6: { + _0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:12:13: 12:18 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 + return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2 ++ } ++ ++ bb7: { ++ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 ++ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 + } + } + diff --git a/src/test/mir-opt/issue-72181-1.rs b/src/test/mir-opt/issue-72181-1.rs new file mode 100644 index 00000000000..6d65f847a2c --- /dev/null +++ b/src/test/mir-opt/issue-72181-1.rs @@ -0,0 +1,21 @@ +// compile-flags: -Z mir-opt-level=1 +// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags. + +#![feature(never_type)] +#![allow(unused, invalid_value)] + +enum Void {} + +// EMIT_MIR rustc.f.mir_map.0.mir +fn f(v: Void) -> ! { + match v {} +} + +// EMIT_MIR rustc.main.mir_map.0.mir +fn main() { + let v: Void = unsafe { + std::mem::transmute::<(), Void>(()) + }; + + f(v); +} diff --git a/src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir b/src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir new file mode 100644 index 00000000000..1821365898e --- /dev/null +++ b/src/test/mir-opt/issue-72181-1/rustc.f.mir_map.0.mir @@ -0,0 +1,37 @@ +// MIR for `f` 0 mir_map + +fn f(_1: Void) -> ! { + debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:10:6: 10:7 + let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:10:18: 10:19 + let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 + let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 + StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 + FakeRead(ForMatchedPlace, _1); // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:11: 11:12 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181-1.rs:10:1: 12:2 + } + + bb2: { + unreachable; // scope 0 at $DIR/issue-72181-1.rs:11:5: 11:15 + } + + bb3: { + StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:11:14: 11:15 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:10:20: 12:2 + } + + bb4: { + StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:12:1: 12:2 + goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2 + } + + bb5: { + return; // scope 0 at $DIR/issue-72181-1.rs:12:2: 12:2 + } +} diff --git a/src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir new file mode 100644 index 00000000000..b87d0294fb8 --- /dev/null +++ b/src/test/mir-opt/issue-72181-1/rustc.main.mir_map.0.mir @@ -0,0 +1,67 @@ +// MIR for `main` 0 mir_map + +| User Type Annotations +| 0: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16 +| 1: Canonical { max_universe: U0, variables: [], value: Ty(Void) } at $DIR/issue-72181-1.rs:16:12: 16:16 +| +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:15:11: 15:11 + let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2 + let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:17:41: 17:43 + let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:20:5: 20:9 + let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:20:7: 20:8 + scope 1 { + debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:16:9: 16:10 + } + scope 2 { + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 + _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 + _2 = const std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 + // ty::Const + // + ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181-1.rs:17:9: 17:40 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar(<ZST>)) } + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181-1.rs:15:1: 21:2 + } + + bb2: { + StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:17:43: 17:44 + FakeRead(ForLet, _2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 + AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:16:12: 16:16 + StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 + StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 + _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:20:7: 20:8 + const f(move _5) -> bb1; // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9 + // ty::Const + // + ty: fn(Void) -> ! {f} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181-1.rs:20:5: 20:6 + // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) } + } + + bb3: { + StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:20:8: 20:9 + StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:20:9: 20:10 + StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:21:1: 21:2 + unreachable; // scope 0 at $DIR/issue-72181-1.rs:15:11: 21:2 + } + + bb4: { + goto -> bb5; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2 + } + + bb5: { + return; // scope 0 at $DIR/issue-72181-1.rs:21:2: 21:2 + } +} diff --git a/src/test/mir-opt/issue-72181.rs b/src/test/mir-opt/issue-72181.rs new file mode 100644 index 00000000000..9373ce12032 --- /dev/null +++ b/src/test/mir-opt/issue-72181.rs @@ -0,0 +1,28 @@ +// compile-flags: -Z mir-opt-level=1 +// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags. + +use std::mem; + +#[derive(Copy, Clone)] +enum Never {} + +union Foo { + a: u64, + b: Never +} + +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR rustc.foo.mir_map.0.mir +fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } + +// EMIT_MIR rustc.bar.mir_map.0.mir +fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x } + +// EMIT_MIR_FOR_EACH_BIT_WIDTH +// EMIT_MIR rustc.main.mir_map.0.mir +fn main() { + let _ = mem::size_of::<Foo>(); + + let f = [Foo { a: 42 }, Foo { a: 10 }]; + let _ = unsafe { f[0].a }; +} diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir new file mode 100644 index 00000000000..29654c2b1f8 --- /dev/null +++ b/src/test/mir-opt/issue-72181/32bit/rustc.bar.mir_map.0.mir @@ -0,0 +1,25 @@ +// MIR for `bar` 0 mir_map + +fn bar(_1: [(Never, u32); 1]) -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43 + let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + scope 1 { + debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49 + goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49 + } + + bb2: { + return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 + } +} diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir new file mode 100644 index 00000000000..776eb61a526 --- /dev/null +++ b/src/test/mir-opt/issue-72181/32bit/rustc.foo.mir_map.0.mir @@ -0,0 +1,37 @@ +// MIR for `foo` 0 mir_map + +fn foo(_1: [(Never, u32); 1]) -> u32 { + debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37 + let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:16:43: 16:44 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49 + } + + bb2: { + _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49 + goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 + } + + bb3: { + return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 + } +} diff --git a/src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir new file mode 100644 index 00000000000..aa44dcd8eae --- /dev/null +++ b/src/test/mir-opt/issue-72181/32bit/rustc.main.mir_map.0.mir @@ -0,0 +1,93 @@ +// MIR for `main` 0 mir_map + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11 + let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27 + let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42 + let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30 + let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25 + let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + scope 1 { + let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + scope 2 { + debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10 + scope 3 { + } + scope 4 { + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + // ty::Const + // + ty: fn() -> usize {std::mem::size_of::<Foo>} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:24:13: 24:32 + // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) } + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2 + } + + bb2: { + StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35 + StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + _3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000002a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:26:23: 26:25 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) } + StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000000a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:26:38: 26:40 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) } + _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 + StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 + StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:27:24: 27:25 + // + literal: Const { ty: usize, val: Value(Scalar(0x00000000)) } + _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + } + + bb3: { + _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28 + StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:23:11: 28:2 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 + goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 + } + + bb4: { + return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 + } +} diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir new file mode 100644 index 00000000000..29654c2b1f8 --- /dev/null +++ b/src/test/mir-opt/issue-72181/64bit/rustc.bar.mir_map.0.mir @@ -0,0 +1,25 @@ +// MIR for `bar` 0 mir_map + +fn bar(_1: [(Never, u32); 1]) -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:19:40: 19:43 + let _2: u32; // in scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + scope 1 { + debug x => _2; // in scope 1 at $DIR/issue-72181.rs:19:13: 19:14 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:19:13: 19:14 + _0 = _2; // scope 1 at $DIR/issue-72181.rs:19:46: 19:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:19:48: 19:49 + goto -> bb2; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:19:1: 19:49 + } + + bb2: { + return; // scope 0 at $DIR/issue-72181.rs:19:49: 19:49 + } +} diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir new file mode 100644 index 00000000000..639019eaf9c --- /dev/null +++ b/src/test/mir-opt/issue-72181/64bit/rustc.foo.mir_map.0.mir @@ -0,0 +1,37 @@ +// MIR for `foo` 0 mir_map + +fn foo(_1: [(Never, u32); 1]) -> u32 { + debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:16:8: 16:10 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:16:34: 16:37 + let _2: usize; // in scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + _2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:16:43: 16:44 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:16:1: 16:49 + } + + bb2: { + _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:16:40: 16:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:16:48: 16:49 + goto -> bb3; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 + } + + bb3: { + return; // scope 0 at $DIR/issue-72181.rs:16:49: 16:49 + } +} diff --git a/src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir new file mode 100644 index 00000000000..4098e0e295c --- /dev/null +++ b/src/test/mir-opt/issue-72181/64bit/rustc.main.mir_map.0.mir @@ -0,0 +1,93 @@ +// MIR for `main` 0 mir_map + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:23:11: 23:11 + let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:26:14: 26:27 + let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:26:29: 26:42 + let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:27:13: 27:30 + let _6: usize; // in scope 0 at $DIR/issue-72181.rs:27:24: 27:25 + let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:27:22: 27:26 + scope 1 { + let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + scope 2 { + debug f => _2; // in scope 2 at $DIR/issue-72181.rs:26:9: 26:10 + scope 3 { + } + scope 4 { + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34 + // ty::Const + // + ty: fn() -> usize {std::mem::size_of::<Foo>} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:24:13: 24:32 + // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) } + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:23:1: 28:2 + } + + bb2: { + StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:24:34: 24:35 + StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + _3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:26:14: 26:27 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000002a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:26:23: 26:25 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) } + StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + _4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:26:29: 26:42 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000000a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:26:38: 26:40 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) } + _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:26:13: 26:43 + StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:26:42: 26:43 + FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:26:9: 26:10 + StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:27:13: 27:30 + StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + _6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:27:24: 27:25 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + } + + bb3: { + _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:27:22: 27:28 + StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:27:30: 27:31 + _0 = const (); // scope 0 at $DIR/issue-72181.rs:23:11: 28:2 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:23:11: 28:2 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:28:1: 28:2 + goto -> bb4; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 + } + + bb4: { + return; // scope 0 at $DIR/issue-72181.rs:28:2: 28:2 + } +} diff --git a/src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir new file mode 100644 index 00000000000..3b6dc46d055 --- /dev/null +++ b/src/test/mir-opt/issue-72181/rustc.bar.mir_map.0.mir @@ -0,0 +1,25 @@ +// MIR for `bar` 0 mir_map + +fn bar(_1: [(Never, u32); 1]) -> u32 { + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:18:40: 18:43 + let _2: u32; // in scope 0 at $DIR/issue-72181.rs:18:13: 18:14 + scope 1 { + debug x => _2; // in scope 1 at $DIR/issue-72181.rs:18:13: 18:14 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14 + _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:18:13: 18:14 + _0 = _2; // scope 1 at $DIR/issue-72181.rs:18:46: 18:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:18:48: 18:49 + goto -> bb2; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:18:1: 18:49 + } + + bb2: { + return; // scope 0 at $DIR/issue-72181.rs:18:49: 18:49 + } +} diff --git a/src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir new file mode 100644 index 00000000000..2941e282cf4 --- /dev/null +++ b/src/test/mir-opt/issue-72181/rustc.foo.mir_map.0.mir @@ -0,0 +1,37 @@ +// MIR for `foo` 0 mir_map + +fn foo(_1: [(Never, u32); 1]) -> u32 { + debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:15:8: 15:10 + let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:15:34: 15:37 + let _2: usize; // in scope 0 at $DIR/issue-72181.rs:15:43: 15:44 + let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45 + let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:15:40: 15:45 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:15:43: 15:44 + _2 = const 0usize; // scope 0 at $DIR/issue-72181.rs:15:43: 15:44 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:15:43: 15:44 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45 + _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:15:40: 15:45 + assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:15:40: 15:45 + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:15:1: 15:49 + } + + bb2: { + _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:15:40: 15:47 + StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:15:48: 15:49 + goto -> bb3; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49 + } + + bb3: { + return; // scope 0 at $DIR/issue-72181.rs:15:49: 15:49 + } +} diff --git a/src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir b/src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir new file mode 100644 index 00000000000..65f4de0e235 --- /dev/null +++ b/src/test/mir-opt/issue-72181/rustc.main.mir_map.0.mir @@ -0,0 +1,93 @@ +// MIR for `main` 0 mir_map + +fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:21:11: 21:11 + let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:22:13: 22:34 + let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:24:14: 24:27 + let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:24:29: 24:42 + let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:25:13: 25:30 + let _6: usize; // in scope 0 at $DIR/issue-72181.rs:25:24: 25:25 + let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26 + let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:25:22: 25:26 + scope 1 { + let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:24:9: 24:10 + scope 2 { + debug f => _2; // in scope 2 at $DIR/issue-72181.rs:24:9: 24:10 + scope 3 { + } + scope 4 { + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:22:13: 22:34 + _1 = const std::mem::size_of::<Foo>() -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:22:13: 22:34 + // ty::Const + // + ty: fn() -> usize {std::mem::size_of::<Foo>} + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:22:13: 22:32 + // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) } + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/issue-72181.rs:21:1: 26:2 + } + + bb2: { + StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:22:34: 22:35 + StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10 + StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:24:14: 24:27 + _3 = Foo { a: const 42u64 }; // scope 1 at $DIR/issue-72181.rs:24:14: 24:27 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000002a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:24:23: 24:25 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000002a)) } + StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:24:29: 24:42 + _4 = Foo { a: const 10u64 }; // scope 1 at $DIR/issue-72181.rs:24:29: 24:42 + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x000000000000000a)) + // mir::Constant + // + span: $DIR/issue-72181.rs:24:38: 24:40 + // + literal: Const { ty: u64, val: Value(Scalar(0x000000000000000a)) } + _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:24:13: 24:43 + StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43 + StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:24:42: 24:43 + FakeRead(ForLet, _2); // scope 1 at $DIR/issue-72181.rs:24:9: 24:10 + StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:25:13: 25:30 + StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:25:24: 25:25 + _6 = const 0usize; // scope 4 at $DIR/issue-72181.rs:25:24: 25:25 + // ty::Const + // + ty: usize + // + val: Value(Scalar(0x0000000000000000)) + // mir::Constant + // + span: $DIR/issue-72181.rs:25:24: 25:25 + // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000000)) } + _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26 + _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:25:22: 25:26 + assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:25:22: 25:26 + } + + bb3: { + _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:25:22: 25:28 + StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31 + StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:25:30: 25:31 + _0 = const (); // scope 0 at $DIR/issue-72181.rs:21:11: 26:2 + // ty::Const + // + ty: () + // + val: Value(Scalar(<ZST>)) + // mir::Constant + // + span: $DIR/issue-72181.rs:21:11: 26:2 + // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } + StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:26:1: 26:2 + goto -> bb4; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2 + } + + bb4: { + return; // scope 0 at $DIR/issue-72181.rs:26:2: 26:2 + } +} diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp index 4903050e08e..b3d188dd708 100644 --- a/src/test/pretty/asm.pp +++ b/src/test/pretty/asm.pp @@ -22,5 +22,13 @@ pub fn main() { asm!("{0}", inout(reg) b); asm!("{0} {1}", out(reg) _, inlateout(reg) b => _); asm!("", out("al") _, lateout("rbx") _); + asm!("inst1\ninst2"); + asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b); + asm!("inst2 {1}, 24\ninst1 {0}, 42", in(reg) a, out(reg) b); + asm!("inst1 {0}, 42\ninst2 {1}, 24", in(reg) a, out(reg) b); + asm!("inst1\ninst2"); + asm!("inst1\ninst2"); + asm!("inst1\n\tinst2"); + asm!("inst1\ninst2\ninst3\ninst4"); } } diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs index 12c32e6721b..33f25e5216b 100644 --- a/src/test/pretty/asm.rs +++ b/src/test/pretty/asm.rs @@ -16,5 +16,14 @@ pub fn main() { asm!("{name}", name = inout(reg) b); asm!("{} {}", out(reg) _, inlateout(reg) b => _); asm!("", out("al") _, lateout("rbx") _); + asm!("inst1", "inst2"); + asm!("inst1 {}, 42", "inst2 {}, 24", in(reg) a, out(reg) b); + asm!("inst2 {1}, 24", "inst1 {0}, 42", in(reg) a, out(reg) b); + asm!("inst1 {}, 42", "inst2 {name}, 24", in(reg) a, name = out(reg) b); + asm!("inst1 +inst2"); + asm!("inst1\ninst2"); + asm!("inst1\n\tinst2"); + asm!("inst1\ninst2", "inst3\ninst4"); } } diff --git a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile index 5d46be87eac..b11d4c4cab7 100644 --- a/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-cdylib-link/Makefile @@ -1,5 +1,5 @@ # needs-sanitizer-support -# only-x86_64 +# needs-sanitizer-address # only-linux -include ../tools.mk diff --git a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile index f62c3a6654e..c2ebd2a6d8c 100644 --- a/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-dylib-link/Makefile @@ -1,5 +1,5 @@ # needs-sanitizer-support -# only-x86_64 +# needs-sanitizer-address # only-linux -include ../tools.mk diff --git a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile index f56475b441f..5ceff16471c 100644 --- a/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile +++ b/src/test/run-make-fulldeps/sanitizer-staticlib-link/Makefile @@ -1,5 +1,5 @@ # needs-sanitizer-support -# only-x86_64 +# needs-sanitizer-address # only-linux -include ../tools.mk diff --git a/src/test/run-make/static-pie/Makefile b/src/test/run-make/static-pie/Makefile new file mode 100644 index 00000000000..1d3cc821389 --- /dev/null +++ b/src/test/run-make/static-pie/Makefile @@ -0,0 +1,15 @@ +-include ../../run-make-fulldeps/tools.mk + +# only-x86_64-unknown-linux-musl + +# How to manually run this +# $ ./x.py test --target x86_64-unknown-linux-musl src/test/run-make/static-pie + +all: + $(RUSTC) --target $(TARGET) -C target-feature=+crt-static test-aslr.rs + # Check that no dynamic interpreter is set + ! readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) INTERP + # Check that we have a dynamic executable + readelf -l $(call RUN_BINFILE,test-aslr) | $(CGREP) DYNAMIC + # Check for address space layout randomization + $(call RUN,test-aslr) --test-aslr diff --git a/src/test/run-make/static-pie/test-aslr.rs b/src/test/run-make/static-pie/test-aslr.rs new file mode 100644 index 00000000000..f28e00f7f4c --- /dev/null +++ b/src/test/run-make/static-pie/test-aslr.rs @@ -0,0 +1,43 @@ +const NUM_RUNS: usize = 10; + +fn run_self(exe: &str) -> usize { + use std::process::Command; + let mut set = std::collections::HashSet::new(); + + let mut cmd = Command::new(exe); + cmd.arg("--report"); + (0..NUM_RUNS).for_each(|_| { + set.insert(cmd.output().expect("failed to execute process").stdout); + }); + set.len() +} + +fn main() { + let mut args = std::env::args(); + let arg0 = args.next().unwrap(); + match args.next() { + Some(s) if s.eq("--report") => { + println!("main = {:#?}", &main as *const _); + } + Some(s) if s.eq("--test-no-aslr") => { + let cnt = run_self(&arg0); + if cnt != 1 { + eprintln!("FAIL: {} most likely ASLR", arg0); + std::process::exit(1); + } + println!("PASS: {} does no ASLR", arg0); + } + Some(s) if s.eq("--test-aslr") => { + let cnt = run_self(&arg0); + if cnt != NUM_RUNS { + eprintln!("FAIL: {} most likely no ASLR", arg0); + std::process::exit(1); + } + println!("PASS: {} does ASLR", arg0); + } + Some(_) | None => { + println!("Usage: {} --test-no-aslr | --test-aslr", arg0); + std::process::exit(1); + } + } +} diff --git a/src/test/rustdoc/codeblock-title.rs b/src/test/rustdoc/codeblock-title.rs index 2f77929c74e..b59b21111b0 100644 --- a/src/test/rustdoc/codeblock-title.rs +++ b/src/test/rustdoc/codeblock-title.rs @@ -4,6 +4,7 @@ // @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This example deliberately fails to compile" // @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "This example is not tested" +// @has foo/fn.bar.html '//*[@class="tooltip should_panic"]/span' "This example panics" /// foo /// @@ -15,6 +16,10 @@ /// goo(); /// ``` /// +/// ```should_panic +/// hoo(); +/// ``` +/// /// ``` /// let x = 0; /// ``` diff --git a/src/test/rustdoc/sanitizer-option.rs b/src/test/rustdoc/sanitizer-option.rs index 6af9ed3e33f..a79b37ee082 100644 --- a/src/test/rustdoc/sanitizer-option.rs +++ b/src/test/rustdoc/sanitizer-option.rs @@ -1,4 +1,5 @@ // needs-sanitizer-support +// needs-sanitizer-address // compile-flags: --test -Z sanitizer=address // // #43031: Verify that rustdoc passes `-Z` options to rustc. Use an extern diff --git a/src/test/rustdoc/synthetic_auto/overflow.rs b/src/test/rustdoc/synthetic_auto/overflow.rs new file mode 100644 index 00000000000..546b3e07793 --- /dev/null +++ b/src/test/rustdoc/synthetic_auto/overflow.rs @@ -0,0 +1,35 @@ +// Tests that we don't fail with an overflow error for certain +// strange types +// See https://github.com/rust-lang/rust/pull/72936#issuecomment-643676915 + +pub trait Interner { + type InternedType; +} + +struct RustInterner<'tcx> { + foo: &'tcx () +} + +impl<'tcx> Interner for RustInterner<'tcx> { + type InternedType = Box<TyData<Self>>; +} + +enum TyData<I: Interner> { + FnDef(I::InternedType) +} + +struct VariableKind<I: Interner>(I::InternedType); + +// @has overflow/struct.BoundVarsCollector.html +// @has - '//code' "impl<'tcx> Send for BoundVarsCollector<'tcx>" +pub struct BoundVarsCollector<'tcx> { + val: VariableKind<RustInterner<'tcx>> +} + +fn is_send<T: Send>() {} + +struct MyInterner<'tcx> { + val: &'tcx () +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs index 27fe432e96d..973294e985f 100644 --- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -37,7 +37,7 @@ fn main() { TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` - TyKind::Error => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Error(_) => (), //~ ERROR usage of `ty::TyKind::<kind>` } if let ty::Int(int_ty) = kind {} diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 0486c90a5a0..d6e4c85c190 100644 --- a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -169,7 +169,7 @@ LL | TyKind::Infer(..) => (), error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Error => (), +LL | TyKind::Error(_) => (), | ^^^^^^ help: try using ty::<kind> directly: `ty` error: usage of `ty::TyKind::<kind>` diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs index 2b1f018f364..fbf399d8b07 100644 --- a/src/test/ui/asm/parse-error.rs +++ b/src/test/ui/asm/parse-error.rs @@ -13,7 +13,7 @@ fn main() { asm!("{}" foo); //~^ ERROR expected token: `,` asm!("{}", foo); - //~^ ERROR expected one of + //~^ ERROR expected operand, options, or additional template string asm!("{}", in foo); //~^ ERROR expected `(`, found `foo` asm!("{}", in(reg foo)); @@ -52,5 +52,13 @@ fn main() { //~^ ERROR named arguments cannot follow explicit register arguments asm!("{1}", in("eax") foo, const bar); //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + asm!("", options(), ""); + //~^ ERROR expected one of + asm!("{}", in(reg) foo, "{}", out(reg) foo); + //~^ ERROR expected one of + asm!(format!("{{{}}}", 0), in(reg) foo); + //~^ ERROR asm template must be a string literal + asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + //~^ ERROR asm template must be a string literal } } diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index 583a1057036..ba7e8f7a03c 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -16,11 +16,11 @@ error: expected token: `,` LL | asm!("{}" foo); | ^^^ expected `,` -error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo` +error: expected operand, options, or additional template string --> $DIR/parse-error.rs:15:20 | LL | asm!("{}", foo); - | ^^^ expected one of 8 possible tokens + | ^^^ expected operand, options, or additional template string error: expected `(`, found `foo` --> $DIR/parse-error.rs:17:23 @@ -160,5 +160,33 @@ LL | asm!("{1}", in("eax") foo, const bar); | | | explicit register argument -error: aborting due to 24 previous errors +error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:55:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 8 possible tokens + +error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:57:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 8 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:59:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:61:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 28 previous errors diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs index 402adc50d5b..1477e3dd566 100644 --- a/src/test/ui/asm/srcloc.rs +++ b/src/test/ui/asm/srcloc.rs @@ -40,5 +40,85 @@ fn main() { asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); //~^ WARN: scale factor without index register is ignored + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax\n", + "invalid_instruction", + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + "mov eax, eax", + concat!("invalid", "_", "instruction"), + "mov eax, eax", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + asm!( + concat!("mov eax", ", ", "eax"), + concat!("invalid", "_", "instruction"), + concat!("mov eax", ", ", "eax"), + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction' + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1' + //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2' + //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3' + //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4' } } diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/srcloc.stderr index d5d12b00481..b62c8948289 100644 --- a/src/test/ui/asm/srcloc.stderr +++ b/src/test/ui/asm/srcloc.stderr @@ -82,5 +82,209 @@ note: instantiated into assembly here LL | movaps %xmm3, (%esi, 2) | ^ -error: aborting due to 6 previous errors; 1 warning emitted +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:45:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:51:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:58:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:65:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:72:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:79:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:86:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:95:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:99:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:110:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:114:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> <inline asm>:6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 23 previous errors; 1 warning emitted diff --git a/src/test/ui/associated-types/associated-types-eq-1.stderr b/src/test/ui/associated-types/associated-types-eq-1.stderr index 66c5f34644c..53a45cf4e4f 100644 --- a/src/test/ui/associated-types/associated-types-eq-1.stderr +++ b/src/test/ui/associated-types/associated-types-eq-1.stderr @@ -4,7 +4,16 @@ error[E0412]: cannot find type `A` in this scope LL | fn foo2<I: Foo>(x: I) { | - similarly named type parameter `I` defined here LL | let _: A = x.boo(); - | ^ help: a type parameter with a similar name exists: `I` + | ^ + | +help: a type parameter with a similar name exists + | +LL | let _: I = x.boo(); + | ^ +help: you might be missing a type parameter + | +LL | fn foo2<I: Foo, A>(x: I) { + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 137cb83ccd3..0a05fc6bb82 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -1,8 +1,8 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/project-fn-ret-invariant.rs:48:8 + --> $DIR/project-fn-ret-invariant.rs:48:4 | LL | bar(foo, x) - | ^^^ + | ^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 44:8... --> $DIR/project-fn-ret-invariant.rs:44:8 diff --git a/src/test/ui/associated-types/defaults-specialization.rs b/src/test/ui/associated-types/defaults-specialization.rs index d0ed718b839..553705b2a4f 100644 --- a/src/test/ui/associated-types/defaults-specialization.rs +++ b/src/test/ui/associated-types/defaults-specialization.rs @@ -1,6 +1,7 @@ //! Tests the interaction of associated type defaults and specialization. #![feature(associated_type_defaults, specialization)] +//~^ WARN the feature `specialization` is incomplete trait Tr { type Ty = u8; diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 37a4d9b60fd..09a8c8f8a88 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -1,5 +1,14 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/defaults-specialization.rs:3:38 + | +LL | #![feature(associated_type_defaults, specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0053]: method `make` has an incompatible type for trait - --> $DIR/defaults-specialization.rs:18:18 + --> $DIR/defaults-specialization.rs:19:18 | LL | fn make() -> Self::Ty { | -------- type in trait @@ -11,7 +20,7 @@ LL | fn make() -> u8 { 0 } found fn pointer `fn() -> u8` error[E0053]: method `make` has an incompatible type for trait - --> $DIR/defaults-specialization.rs:34:18 + --> $DIR/defaults-specialization.rs:35:18 | LL | fn make() -> Self::Ty { | -------- type in trait @@ -26,7 +35,7 @@ LL | fn make() -> bool { true } found fn pointer `fn() -> bool` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:9:9 + --> $DIR/defaults-specialization.rs:10:9 | LL | type Ty = u8; | ------------- associated type defaults can't be assumed inside the trait defining them @@ -40,7 +49,7 @@ LL | 0u8 found type `u8` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:25:29 + --> $DIR/defaults-specialization.rs:26:29 | LL | fn make() -> Self::Ty { 0u8 } | -------- ^^^ expected associated type, found `u8` @@ -53,7 +62,7 @@ LL | fn make() -> Self::Ty { 0u8 } = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:43:29 + --> $DIR/defaults-specialization.rs:44:29 | LL | default type Ty = bool; | ----------------------- expected this associated type @@ -67,7 +76,7 @@ LL | fn make() -> Self::Ty { true } found type `bool` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:86:32 + --> $DIR/defaults-specialization.rs:87:32 | LL | let _: <B<()> as Tr>::Ty = 0u8; | ----------------- ^^^ expected associated type, found `u8` @@ -77,13 +86,13 @@ LL | let _: <B<()> as Tr>::Ty = 0u8; = note: expected associated type `<B<()> as Tr>::Ty` found type `u8` help: a method is available that returns `<B<()> as Tr>::Ty` - --> $DIR/defaults-specialization.rs:8:5 + --> $DIR/defaults-specialization.rs:9:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:87:32 + --> $DIR/defaults-specialization.rs:88:32 | LL | let _: <B<()> as Tr>::Ty = true; | ----------------- ^^^^ expected associated type, found `bool` @@ -93,13 +102,13 @@ LL | let _: <B<()> as Tr>::Ty = true; = note: expected associated type `<B<()> as Tr>::Ty` found type `bool` help: a method is available that returns `<B<()> as Tr>::Ty` - --> $DIR/defaults-specialization.rs:8:5 + --> $DIR/defaults-specialization.rs:9:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:88:33 + --> $DIR/defaults-specialization.rs:89:33 | LL | let _: <B2<()> as Tr>::Ty = 0u8; | ------------------ ^^^ expected associated type, found `u8` @@ -109,13 +118,13 @@ LL | let _: <B2<()> as Tr>::Ty = 0u8; = note: expected associated type `<B2<()> as Tr>::Ty` found type `u8` help: a method is available that returns `<B2<()> as Tr>::Ty` - --> $DIR/defaults-specialization.rs:8:5 + --> $DIR/defaults-specialization.rs:9:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types - --> $DIR/defaults-specialization.rs:89:33 + --> $DIR/defaults-specialization.rs:90:33 | LL | let _: <B2<()> as Tr>::Ty = true; | ------------------ ^^^^ expected associated type, found `bool` @@ -125,12 +134,12 @@ LL | let _: <B2<()> as Tr>::Ty = true; = note: expected associated type `<B2<()> as Tr>::Ty` found type `bool` help: a method is available that returns `<B2<()> as Tr>::Ty` - --> $DIR/defaults-specialization.rs:8:5 + --> $DIR/defaults-specialization.rs:9:5 | LL | fn make() -> Self::Ty { | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` -error: aborting due to 9 previous errors +error: aborting due to 9 previous errors; 1 warning emitted Some errors have detailed explanations: E0053, E0308. For more information about an error, try `rustc --explain E0053`. diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index af8fc2cd2ab..0f58b158904 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -1,13 +1,14 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { | ^^^^^ | | - | data with this lifetime... + | this data with an anonymous lifetime `'_`... | ...is captured here... LL | foo(|| self.bar()).await; - | --- ...and required to be `'static` by this + | --- ...and is required to live as long as `'static` here error: aborting due to previous error +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/auto-is-contextual.rs b/src/test/ui/auto-traits/auto-is-contextual.rs index a2ddd5374c0..a2ddd5374c0 100644 --- a/src/test/ui/auto-is-contextual.rs +++ b/src/test/ui/auto-traits/auto-is-contextual.rs diff --git a/src/test/ui/auto-traits/auto-trait-projection-recursion.rs b/src/test/ui/auto-traits/auto-trait-projection-recursion.rs new file mode 100644 index 00000000000..a36f26f02e9 --- /dev/null +++ b/src/test/ui/auto-traits/auto-trait-projection-recursion.rs @@ -0,0 +1,34 @@ +// Checking the `Send` bound in `main` requires: +// +// checking <C<'static> as Y>::P: Send +// which normalizes to Box<X<C<'?1>>>: Send +// which needs X<C<'?1>>: Send +// which needs <C<'?1> as Y>::P: Send +// +// At this point we used to normalize the predicate to `Box<X<C<'?2>>>: Send` +// and continue in a loop where we created new region variables to the +// recursion limit. To avoid this we now "canonicalize" region variables to +// lowest unified region vid. This means we instead have to prove +// `Box<X<C<'?1>>>: Send`, which we can because auto traits are coinductive. + +// check-pass + +// Avoid a really long error message if this regresses. +#![recursion_limit="20"] + +trait Y { + type P; +} + +impl<'a> Y for C<'a> { + type P = Box<X<C<'a>>>; +} + +struct C<'a>(&'a ()); +struct X<T: Y>(T::P); + +fn is_send<S: Send>() {} + +fn main() { + is_send::<X<C<'static>>>(); +} diff --git a/src/test/ui/auto-trait-validation.rs b/src/test/ui/auto-traits/auto-trait-validation.rs index 34d6c3da00e..34d6c3da00e 100644 --- a/src/test/ui/auto-trait-validation.rs +++ b/src/test/ui/auto-traits/auto-trait-validation.rs diff --git a/src/test/ui/auto-trait-validation.stderr b/src/test/ui/auto-traits/auto-trait-validation.stderr index 4040e66c6af..4040e66c6af 100644 --- a/src/test/ui/auto-trait-validation.stderr +++ b/src/test/ui/auto-traits/auto-trait-validation.stderr diff --git a/src/test/ui/traits/auto-traits.rs b/src/test/ui/auto-traits/auto-traits.rs index 15fdddc5f3f..15fdddc5f3f 100644 --- a/src/test/ui/traits/auto-traits.rs +++ b/src/test/ui/auto-traits/auto-traits.rs diff --git a/src/test/ui/issues/issue-23080-2.rs b/src/test/ui/auto-traits/issue-23080-2.rs index 7f6b9e3fba7..7f6b9e3fba7 100644 --- a/src/test/ui/issues/issue-23080-2.rs +++ b/src/test/ui/auto-traits/issue-23080-2.rs diff --git a/src/test/ui/issues/issue-23080-2.stderr b/src/test/ui/auto-traits/issue-23080-2.stderr index 48ce09aaa34..48ce09aaa34 100644 --- a/src/test/ui/issues/issue-23080-2.stderr +++ b/src/test/ui/auto-traits/issue-23080-2.stderr diff --git a/src/test/ui/issues/issue-23080.rs b/src/test/ui/auto-traits/issue-23080.rs index 035db82ba5d..035db82ba5d 100644 --- a/src/test/ui/issues/issue-23080.rs +++ b/src/test/ui/auto-traits/issue-23080.rs diff --git a/src/test/ui/issues/issue-23080.stderr b/src/test/ui/auto-traits/issue-23080.stderr index 73ecb1c362e..73ecb1c362e 100644 --- a/src/test/ui/issues/issue-23080.stderr +++ b/src/test/ui/auto-traits/issue-23080.stderr diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.rs b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs index 8824a6d2767..8824a6d2767 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.rs +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr index 63b3300f6db..63b3300f6db 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits-2.stderr +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.rs b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.rs index edbca915124..edbca915124 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.rs +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.rs diff --git a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr index 796638fc54d..796638fc54d 100644 --- a/src/test/ui/typeck/typeck-auto-trait-no-supertraits.stderr +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.rs index 71ac2b466c1..71ac2b466c1 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.rs +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.rs diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr index 53ba9b8a3f6..53ba9b8a3f6 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types-2.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs index 6483b9213dc..6483b9213dc 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.rs diff --git a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr index bc500004984..bc500004984 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-constituent-types.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.rs index 47cab60625d..47cab60625d 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation.rs +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.rs diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr index 76a6994cb00..76a6994cb00 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-negation.stderr diff --git a/src/test/ui/typeck/typeck-default-trait-impl-precedence.rs b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.rs index 614a5ff55b1..614a5ff55b1 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-precedence.rs +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.rs diff --git a/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr index 5962d191292..5962d191292 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-precedence.stderr +++ b/src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr diff --git a/src/test/ui/cast/cast-from-nil.stderr b/src/test/ui/cast/cast-from-nil.stderr index c8e3628a7de..dab133cfb4b 100644 --- a/src/test/ui/cast/cast-from-nil.stderr +++ b/src/test/ui/cast/cast-from-nil.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `u32` --> $DIR/cast-from-nil.rs:2:21 | LL | fn main() { let u = (assert!(true) as u32); } - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/cast/cast-to-bare-fn.stderr b/src/test/ui/cast/cast-to-bare-fn.stderr index 84933dca929..d97b0c5f8aa 100644 --- a/src/test/ui/cast/cast-to-bare-fn.stderr +++ b/src/test/ui/cast/cast-to-bare-fn.stderr @@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `fn(isize) {foo}` as `extern "C" fn() -> isize --> $DIR/cast-to-bare-fn.rs:5:13 | LL | let x = foo as extern "C" fn() -> isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `u64` as `fn(isize) -> (isize, isize)` --> $DIR/cast-to-bare-fn.rs:7:13 | LL | let y = v as extern "Rust" fn(isize) -> (isize, isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error: aborting due to 2 previous errors diff --git a/src/test/ui/cast/cast-to-nil.stderr b/src/test/ui/cast/cast-to-nil.stderr index 478f6b69daf..29a9baffd71 100644 --- a/src/test/ui/cast/cast-to-nil.stderr +++ b/src/test/ui/cast/cast-to-nil.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `u32` as `()` --> $DIR/cast-to-nil.rs:2:21 | LL | fn main() { let u = 0u32 as (); } - | ^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index ffa02533d8b..9b86f8d4def 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -12,7 +12,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::ma LL | Box::new(1) as dyn Send; | ^^^^^^^^^^^^^^^-------- | | - | help: try casting to a `Box` instead: `Box<dyn Send>` + | help: you can cast to a `Box` instead: `Box<dyn Send>` error: aborting due to 2 previous errors diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs new file mode 100644 index 00000000000..96e3d967e2c --- /dev/null +++ b/src/test/ui/cenum_impl_drop_cast.rs @@ -0,0 +1,18 @@ +#![deny(cenum_impl_drop_cast)] + +enum E { + A = 0, +} + +impl Drop for E { + fn drop(&mut self) { + println!("Drop"); + } +} + +fn main() { + let e = E::A; + let i = e as u32; + //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop` + //~| WARN this was previously accepted +} diff --git a/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr new file mode 100644 index 00000000000..8d847a0c80b --- /dev/null +++ b/src/test/ui/cenum_impl_drop_cast.stderr @@ -0,0 +1,16 @@ +error: cannot cast enum `E` into integer `u32` because it implements `Drop` + --> $DIR/cenum_impl_drop_cast.rs:15:13 + | +LL | let i = e as u32; + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/cenum_impl_drop_cast.rs:1:9 + | +LL | #![deny(cenum_impl_drop_cast)] + | ^^^^^^^^^^^^^^^^^^^^ + = 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 #73333 <https://github.com/rust-lang/rust/issues/73333> + +error: aborting due to previous error + diff --git a/src/test/ui/check-static-immutable-mut-slices.rs b/src/test/ui/check-static-immutable-mut-slices.rs index d5e9fb2dede..3be02f6a0f6 100644 --- a/src/test/ui/check-static-immutable-mut-slices.rs +++ b/src/test/ui/check-static-immutable-mut-slices.rs @@ -1,6 +1,6 @@ // Checks that immutable static items can't have mutable slices static TEST: &'static mut [isize] = &mut []; -//~^ ERROR references in statics may only refer to immutable values +//~^ ERROR mutable references are not allowed in statics pub fn main() { } diff --git a/src/test/ui/check-static-immutable-mut-slices.stderr b/src/test/ui/check-static-immutable-mut-slices.stderr index 66fe8646e10..9ffbb483d13 100644 --- a/src/test/ui/check-static-immutable-mut-slices.stderr +++ b/src/test/ui/check-static-immutable-mut-slices.stderr @@ -1,12 +1,9 @@ -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/check-static-immutable-mut-slices.rs:3:37 | LL | static TEST: &'static mut [isize] = &mut []; - | ^^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr index 2005bd4dd5c..0c6d11cd321 100644 --- a/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr +++ b/src/test/ui/closure-expected-type/expect-two-infer-vars-supply-ty-with-bound-region.stderr @@ -1,8 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:27 + --> $DIR/expect-two-infer-vars-supply-ty-with-bound-region.rs:8:5 | LL | with_closure(|x: u32, y| {}); - | ^ consider giving this closure parameter a type + | ^^^^^^^^^^^^ cannot infer type for type parameter `B` declared on the function `with_closure` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr index ab6056b6547..4b3b4be798f 100644 --- a/src/test/ui/closures/closure-no-fn-3.stderr +++ b/src/test/ui/closures/closure-no-fn-3.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b --> $DIR/closure-no-fn-3.rs:6:27 | LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast error: aborting due to previous error diff --git a/src/test/ui/coerce/coerce-overloaded-autoderef.rs b/src/test/ui/coerce/coerce-overloaded-autoderef.rs deleted file mode 100644 index d5484607c8b..00000000000 --- a/src/test/ui/coerce/coerce-overloaded-autoderef.rs +++ /dev/null @@ -1,68 +0,0 @@ -// run-pass -#![allow(unused_braces)] -#![allow(dead_code)] -// pretty-expanded FIXME #23616 - -use std::rc::Rc; - -// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241. - -fn use_ref<T>(_: &T) {} -fn use_mut<T>(_: &mut T) {} - -fn use_rc<T>(t: Rc<T>) { - use_ref(&*t); // what you have to write today - use_ref(&t); // what you'd be able to write - use_ref(&&&&&&t); - use_ref(&mut &&&&&t); - use_ref(&&&mut &&&t); -} - -fn use_mut_box<T>(mut t: &mut Box<T>) { - use_mut(&mut *t); // what you have to write today - use_mut(t); // what you'd be able to write - use_mut(&mut &mut &mut t); - - use_ref(&*t); // what you have to write today - use_ref(t); // what you'd be able to write - use_ref(&&&&&&t); - use_ref(&mut &&&&&t); - use_ref(&&&mut &&&t); -} - -fn use_nested<T>(t: &Box<T>) { - use_ref(&**t); // what you have to write today - use_ref(t); // what you'd be able to write (note: recursive deref) - use_ref(&&&&&&t); - use_ref(&mut &&&&&t); - use_ref(&&&mut &&&t); -} - -fn use_slice(_: &[u8]) {} -fn use_slice_mut(_: &mut [u8]) {} - -fn use_vec(mut v: Vec<u8>) { - use_slice_mut(&mut v[..]); // what you have to write today - use_slice_mut(&mut v); // what you'd be able to write - use_slice_mut(&mut &mut &mut v); - - use_slice(&v[..]); // what you have to write today - use_slice(&v); // what you'd be able to write - use_slice(&&&&&&v); - use_slice(&mut &&&&&v); - use_slice(&&&mut &&&v); -} - -fn use_vec_ref(v: &Vec<u8>) { - use_slice(&v[..]); // what you have to write today - use_slice(v); // what you'd be able to write - use_slice(&&&&&&v); - use_slice(&mut &&&&&v); - use_slice(&&&mut &&&v); -} - -fn use_op_rhs(s: &mut String) { - *s += {&String::from(" ")}; -} - -pub fn main() {} diff --git a/src/test/ui/coerce/coerce-expect-unsized.rs b/src/test/ui/coercion/coerce-expect-unsized.rs index d486fdf73ab..d486fdf73ab 100644 --- a/src/test/ui/coerce/coerce-expect-unsized.rs +++ b/src/test/ui/coercion/coerce-expect-unsized.rs diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs new file mode 100644 index 00000000000..01d9c1e486a --- /dev/null +++ b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.rs @@ -0,0 +1,32 @@ +fn borrow_mut<T>(x: &mut T) -> &mut T { x } +fn borrow<T>(x: &T) -> &T { x } + +fn borrow_mut2<T>(_: &mut T, _: &mut T) {} +fn borrow2<T>(_: &mut T, _: &T) {} + +fn double_mut_borrow<T>(x: &mut Box<T>) { + let y = borrow_mut(x); + let z = borrow_mut(x); + //~^ ERROR cannot borrow `*x` as mutable more than once at a time + drop((y, z)); +} + +fn double_imm_borrow(x: &mut Box<i32>) { + let y = borrow(x); + let z = borrow(x); + **x += 1; + //~^ ERROR cannot assign to `**x` because it is borrowed + drop((y, z)); +} + +fn double_mut_borrow2<T>(x: &mut Box<T>) { + borrow_mut2(x, x); + //~^ ERROR cannot borrow `*x` as mutable more than once at a time +} + +fn double_borrow2<T>(x: &mut Box<T>) { + borrow2(x, x); + //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable +} + +pub fn main() {} diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.stderr b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr index 7cdfcb5f4fc..d067c3b3a18 100644 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.stderr +++ b/src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:9:24 + --> $DIR/coerce-overloaded-autoderef-fail.rs:9:24 | LL | let y = borrow_mut(x); | - first mutable borrow occurs here @@ -10,7 +10,7 @@ LL | drop((y, z)); | - first borrow later used here error[E0506]: cannot assign to `**x` because it is borrowed - --> $DIR/coerce-overloaded-autoderef.rs:17:5 + --> $DIR/coerce-overloaded-autoderef-fail.rs:17:5 | LL | let y = borrow(x); | - borrow of `**x` occurs here @@ -22,7 +22,7 @@ LL | drop((y, z)); | - borrow later used here error[E0499]: cannot borrow `*x` as mutable more than once at a time - --> $DIR/coerce-overloaded-autoderef.rs:23:20 + --> $DIR/coerce-overloaded-autoderef-fail.rs:23:20 | LL | borrow_mut2(x, x); | ----------- - ^ second mutable borrow occurs here @@ -31,7 +31,7 @@ LL | borrow_mut2(x, x); | first borrow later used by call error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable - --> $DIR/coerce-overloaded-autoderef.rs:28:5 + --> $DIR/coerce-overloaded-autoderef-fail.rs:28:5 | LL | borrow2(x, x); | -------^^^^-^ diff --git a/src/test/ui/coercion/coerce-overloaded-autoderef.rs b/src/test/ui/coercion/coerce-overloaded-autoderef.rs index 01d9c1e486a..d5484607c8b 100644 --- a/src/test/ui/coercion/coerce-overloaded-autoderef.rs +++ b/src/test/ui/coercion/coerce-overloaded-autoderef.rs @@ -1,32 +1,68 @@ -fn borrow_mut<T>(x: &mut T) -> &mut T { x } -fn borrow<T>(x: &T) -> &T { x } +// run-pass +#![allow(unused_braces)] +#![allow(dead_code)] +// pretty-expanded FIXME #23616 -fn borrow_mut2<T>(_: &mut T, _: &mut T) {} -fn borrow2<T>(_: &mut T, _: &T) {} +use std::rc::Rc; -fn double_mut_borrow<T>(x: &mut Box<T>) { - let y = borrow_mut(x); - let z = borrow_mut(x); - //~^ ERROR cannot borrow `*x` as mutable more than once at a time - drop((y, z)); +// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241. + +fn use_ref<T>(_: &T) {} +fn use_mut<T>(_: &mut T) {} + +fn use_rc<T>(t: Rc<T>) { + use_ref(&*t); // what you have to write today + use_ref(&t); // what you'd be able to write + use_ref(&&&&&&t); + use_ref(&mut &&&&&t); + use_ref(&&&mut &&&t); +} + +fn use_mut_box<T>(mut t: &mut Box<T>) { + use_mut(&mut *t); // what you have to write today + use_mut(t); // what you'd be able to write + use_mut(&mut &mut &mut t); + + use_ref(&*t); // what you have to write today + use_ref(t); // what you'd be able to write + use_ref(&&&&&&t); + use_ref(&mut &&&&&t); + use_ref(&&&mut &&&t); } -fn double_imm_borrow(x: &mut Box<i32>) { - let y = borrow(x); - let z = borrow(x); - **x += 1; - //~^ ERROR cannot assign to `**x` because it is borrowed - drop((y, z)); +fn use_nested<T>(t: &Box<T>) { + use_ref(&**t); // what you have to write today + use_ref(t); // what you'd be able to write (note: recursive deref) + use_ref(&&&&&&t); + use_ref(&mut &&&&&t); + use_ref(&&&mut &&&t); +} + +fn use_slice(_: &[u8]) {} +fn use_slice_mut(_: &mut [u8]) {} + +fn use_vec(mut v: Vec<u8>) { + use_slice_mut(&mut v[..]); // what you have to write today + use_slice_mut(&mut v); // what you'd be able to write + use_slice_mut(&mut &mut &mut v); + + use_slice(&v[..]); // what you have to write today + use_slice(&v); // what you'd be able to write + use_slice(&&&&&&v); + use_slice(&mut &&&&&v); + use_slice(&&&mut &&&v); } -fn double_mut_borrow2<T>(x: &mut Box<T>) { - borrow_mut2(x, x); - //~^ ERROR cannot borrow `*x` as mutable more than once at a time +fn use_vec_ref(v: &Vec<u8>) { + use_slice(&v[..]); // what you have to write today + use_slice(v); // what you'd be able to write + use_slice(&&&&&&v); + use_slice(&mut &&&&&v); + use_slice(&&&mut &&&v); } -fn double_borrow2<T>(x: &mut Box<T>) { - borrow2(x, x); - //~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable +fn use_op_rhs(s: &mut String) { + *s += {&String::from(" ")}; } pub fn main() {} diff --git a/src/test/ui/coerce/coerce-reborrow-imm-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs index f033e1b5d2b..f033e1b5d2b 100644 --- a/src/test/ui/coerce/coerce-reborrow-imm-ptr-arg.rs +++ b/src/test/ui/coercion/coerce-reborrow-imm-ptr-arg.rs diff --git a/src/test/ui/coerce/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs index 64a365229cb..64a365229cb 100644 --- a/src/test/ui/coerce/coerce-reborrow-imm-ptr-rcvr.rs +++ b/src/test/ui/coercion/coerce-reborrow-imm-ptr-rcvr.rs diff --git a/src/test/ui/coerce/coerce-reborrow-imm-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs index c2aaae1c73e..c2aaae1c73e 100644 --- a/src/test/ui/coerce/coerce-reborrow-imm-vec-arg.rs +++ b/src/test/ui/coercion/coerce-reborrow-imm-vec-arg.rs diff --git a/src/test/ui/coerce/coerce-reborrow-imm-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs index 9a5652acf87..9a5652acf87 100644 --- a/src/test/ui/coerce/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/ui/coercion/coerce-reborrow-imm-vec-rcvr.rs diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs new file mode 100644 index 00000000000..48be2d3146b --- /dev/null +++ b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.rs @@ -0,0 +1,6 @@ +fn test<T>(_a: T, _b: T) {} + +fn main() { + test(&mut 7, &7); + //~^ mismatched types +} diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr new file mode 100644 index 00000000000..59b0ec496f1 --- /dev/null +++ b/src/test/ui/coercion/coerce-reborrow-multi-arg-fail.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18 + | +LL | test(&mut 7, &7); + | ^^ types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/coercion/coerce-reborrow-multi-arg.rs b/src/test/ui/coercion/coerce-reborrow-multi-arg.rs new file mode 100644 index 00000000000..93cd0bb3e27 --- /dev/null +++ b/src/test/ui/coercion/coerce-reborrow-multi-arg.rs @@ -0,0 +1,9 @@ +// build-pass +fn test<T>(_a: T, _b: T) {} + +fn main() { + test(&7, &7); + test(&7, &mut 7); + test::<&i32>(&mut 7, &7); + test::<&i32>(&mut 7, &mut 7); +} diff --git a/src/test/ui/coerce/coerce-reborrow-mut-ptr-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs index 76cd6793b3c..76cd6793b3c 100644 --- a/src/test/ui/coerce/coerce-reborrow-mut-ptr-arg.rs +++ b/src/test/ui/coercion/coerce-reborrow-mut-ptr-arg.rs diff --git a/src/test/ui/coerce/coerce-reborrow-mut-ptr-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs index e6e7c3a51aa..e6e7c3a51aa 100644 --- a/src/test/ui/coerce/coerce-reborrow-mut-ptr-rcvr.rs +++ b/src/test/ui/coercion/coerce-reborrow-mut-ptr-rcvr.rs diff --git a/src/test/ui/coerce/coerce-reborrow-mut-vec-arg.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs index 2635754f14d..2635754f14d 100644 --- a/src/test/ui/coerce/coerce-reborrow-mut-vec-arg.rs +++ b/src/test/ui/coercion/coerce-reborrow-mut-vec-arg.rs diff --git a/src/test/ui/coerce/coerce-reborrow-mut-vec-rcvr.rs b/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs index c03336ea37a..c03336ea37a 100644 --- a/src/test/ui/coerce/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/ui/coercion/coerce-reborrow-mut-vec-rcvr.rs diff --git a/src/test/ui/coercion/coerce-to-bang-cast.rs b/src/test/ui/coercion/coerce-to-bang-cast.rs index 8ef19480846..85598a42ecc 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.rs +++ b/src/test/ui/coercion/coerce-to-bang-cast.rs @@ -1,7 +1,5 @@ #![feature(never_type)] -fn foo(x: usize, y: !, z: usize) { } - fn cast_a() { let y = {return; 22} as !; //~^ ERROR non-primitive cast diff --git a/src/test/ui/coercion/coerce-to-bang-cast.stderr b/src/test/ui/coercion/coerce-to-bang-cast.stderr index ff30ebc09c6..50e009aa25b 100644 --- a/src/test/ui/coercion/coerce-to-bang-cast.stderr +++ b/src/test/ui/coercion/coerce-to-bang-cast.stderr @@ -1,18 +1,14 @@ error[E0605]: non-primitive cast: `i32` as `!` - --> $DIR/coerce-to-bang-cast.rs:6:13 + --> $DIR/coerce-to-bang-cast.rs:4:13 | LL | let y = {return; 22} as !; - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `i32` as `!` - --> $DIR/coerce-to-bang-cast.rs:11:13 + --> $DIR/coerce-to-bang-cast.rs:9:13 | LL | let y = 22 as !; - | ^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/coerce/coerce-unify-return.rs b/src/test/ui/coercion/coerce-unify-return.rs index 95a7ee8fe0f..95a7ee8fe0f 100644 --- a/src/test/ui/coerce/coerce-unify-return.rs +++ b/src/test/ui/coercion/coerce-unify-return.rs diff --git a/src/test/ui/coerce/coerce-unify.rs b/src/test/ui/coercion/coerce-unify.rs index f1818f9bb5a..f1818f9bb5a 100644 --- a/src/test/ui/coerce/coerce-unify.rs +++ b/src/test/ui/coercion/coerce-unify.rs diff --git a/src/test/ui/coerce/coerce-unsize-subtype.rs b/src/test/ui/coercion/coerce-unsize-subtype.rs index 45b53300c5b..45b53300c5b 100644 --- a/src/test/ui/coerce/coerce-unsize-subtype.rs +++ b/src/test/ui/coercion/coerce-unsize-subtype.rs diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs index 7f0e5472c3c..d74d3a2a523 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.rs @@ -4,6 +4,7 @@ // // No we expect to run into a more user-friendly cycle error instead. #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete trait Trait<T> { type Assoc; } //~^ ERROR E0391 diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index 71f997c54c6..7e140480b77 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -1,16 +1,25 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:6:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0391]: cycle detected when building specialization graph of trait `Trait` - --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 + --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 | LL | trait Trait<T> { type Assoc; } | ^^^^^^^^^^^^^^ | = note: ...which again requires building specialization graph of trait `Trait`, completing the cycle note: cycle used when coherence checking all impls of trait `Trait` - --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:8:1 + --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 | LL | trait Trait<T> { type Assoc; } | ^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs new file mode 100644 index 00000000000..fc993d63927 --- /dev/null +++ b/src/test/ui/const-generics/auxiliary/impl-const.rs @@ -0,0 +1,9 @@ +#![feature(const_generics)] + +pub struct Num<const N: usize>; + +// Braces around const expression causes crash +impl Num<{5}> { + pub fn five(&self) { + } +} diff --git a/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs b/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs new file mode 100644 index 00000000000..bda9ce8767d --- /dev/null +++ b/src/test/ui/const-generics/issue-68104-print-stack-overflow.rs @@ -0,0 +1,14 @@ +// aux-build:impl-const.rs +// run-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +extern crate impl_const; + +use impl_const::*; + +pub fn main() { + let n = Num::<5>; + n.five(); +} diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 5b2c4116c4b..e4d256c0ad1 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -16,7 +16,7 @@ error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:25:13 | LL | : [u32; 5i8 as char as usize] - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ invalid cast error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr index 81fa5c0df13..93dd9a53ec9 100644 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ b/src/test/ui/consts/const-eval/double_check2.stderr @@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {( LL | | Union { u8: &BAR }.foo, LL | | Union { u8: &BAR }.bar, LL | | )}; - | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum discriminant + | |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/issue-65394.rs b/src/test/ui/consts/const-eval/issue-65394.rs index b1c058eac9e..2518e4ed40b 100644 --- a/src/test/ui/consts/const-eval/issue-65394.rs +++ b/src/test/ui/consts/const-eval/issue-65394.rs @@ -5,7 +5,7 @@ const _: Vec<i32> = { let mut x = Vec::<i32>::new(); //~ ERROR destructors cannot be evaluated at compile-time - let r = &mut x; //~ ERROR references in constants may only refer to immutable values + let r = &mut x; //~ ERROR mutable references are not allowed in constants let y = x; y }; diff --git a/src/test/ui/consts/const-eval/issue-65394.stderr b/src/test/ui/consts/const-eval/issue-65394.stderr index d85a1a1a3c3..f843a94fabd 100644 --- a/src/test/ui/consts/const-eval/issue-65394.stderr +++ b/src/test/ui/consts/const-eval/issue-65394.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-65394.rs:8:13 | LL | let r = &mut x; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0493]: destructors cannot be evaluated at compile-time --> $DIR/issue-65394.rs:7:9 @@ -15,5 +12,5 @@ LL | let mut x = Vec::<i32>::new(); error: aborting due to 2 previous errors -Some errors have detailed explanations: E0493, E0658. +Some errors have detailed explanations: E0493, E0764. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index e49fd3e0b97..1f7593c6db9 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:24:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum discriminant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:42:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum discriminant + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-multi-ref.rs b/src/test/ui/consts/const-multi-ref.rs index 5e2be0d4f3f..18645efc887 100644 --- a/src/test/ui/consts/const-multi-ref.rs +++ b/src/test/ui/consts/const-multi-ref.rs @@ -3,7 +3,7 @@ const _: i32 = { let mut a = 5; - let p = &mut a; //~ ERROR references in constants may only refer to immutable values + let p = &mut a; //~ ERROR mutable references are not allowed in constants let reborrow = {p}; let pp = &reborrow; diff --git a/src/test/ui/consts/const-multi-ref.stderr b/src/test/ui/consts/const-multi-ref.stderr index e01dd4e5747..9a7914b4588 100644 --- a/src/test/ui/consts/const-multi-ref.stderr +++ b/src/test/ui/consts/const-multi-ref.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/const-multi-ref.rs:6:13 | LL | let p = &mut a; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead --> $DIR/const-multi-ref.rs:16:13 @@ -15,5 +12,5 @@ LL | let p = &a; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0492, E0658. +Some errors have detailed explanations: E0492, E0764. For more information about an error, try `rustc --explain E0492`. diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs index 130ba9283b1..5819daa817a 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_mut_refs)] #![feature(const_fn)] #![feature(raw_ref_op)] @@ -24,7 +22,9 @@ const fn baz(foo: &mut Foo)-> *mut usize { const _: () = { foo().bar(); + //~^ ERROR mutable references are not allowed in constants baz(&mut foo()); + //~^ ERROR mutable references are not allowed in constants }; fn main() {} diff --git a/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr new file mode 100644 index 00000000000..2214ce6ee1c --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_address_of.stderr @@ -0,0 +1,15 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_address_of.rs:24:5 + | +LL | foo().bar(); + | ^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_address_of.rs:26:9 + | +LL | baz(&mut foo()); + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs index 99006a20b1b..9099d5a1b8e 100644 --- a/src/test/ui/consts/const-mut-refs/const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.rs @@ -1,5 +1,3 @@ -// run-pass - #![feature(const_mut_refs)] struct Foo { @@ -31,6 +29,9 @@ const fn bazz(foo: &mut Foo) -> usize { fn main() { let _: [(); foo().bar()] = [(); 1]; + //~^ ERROR mutable references are not allowed in constants let _: [(); baz(&mut foo())] = [(); 2]; + //~^ ERROR mutable references are not allowed in constants let _: [(); bazz(&mut foo())] = [(); 3]; + //~^ ERROR mutable references are not allowed in constants } diff --git a/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr new file mode 100644 index 00000000000..4ca7b128b7c --- /dev/null +++ b/src/test/ui/consts/const-mut-refs/const_mut_refs.stderr @@ -0,0 +1,21 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:31:17 + | +LL | let _: [(); foo().bar()] = [(); 1]; + | ^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:33:21 + | +LL | let _: [(); baz(&mut foo())] = [(); 2]; + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error[E0764]: mutable references are not allowed in constants + --> $DIR/const_mut_refs.rs:35:22 + | +LL | let _: [(); bazz(&mut foo())] = [(); 3]; + | ^^^^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/const_in_pattern/issue-73431.rs b/src/test/ui/consts/const_in_pattern/issue-73431.rs new file mode 100644 index 00000000000..fa18a3af1b0 --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/issue-73431.rs @@ -0,0 +1,29 @@ +// run-pass + +// Regression test for https://github.com/rust-lang/rust/issues/73431. + +pub trait Zero { + const ZERO: Self; +} + +impl Zero for usize { + const ZERO: Self = 0; +} + +impl<T: Zero> Zero for Wrapper<T> { + const ZERO: Self = Wrapper(T::ZERO); +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Wrapper<T>(T); + +fn is_zero(x: Wrapper<usize>) -> bool { + match x { + Zero::ZERO => true, + _ => false, + } +} + +fn main() { + let _ = is_zero(Wrapper(42)); +} diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index cbe73923e9c..f993a427b48 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -13,14 +13,14 @@ impl S { const FOO: S = { let mut s = S { state: 42 }; - s.foo(3); //~ ERROR references in constants may only refer to immutable values + s.foo(3); //~ ERROR mutable references are not allowed in constants s }; type Array = [u32; { let mut x = 2; let y = &mut x; -//~^ ERROR references in constants may only refer to immutable values +//~^ ERROR mutable references are not allowed in constants *y = 42; //~^ ERROR constant contains unimplemented expression type *y diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 62fd04ea522..dd05a4c0bb0 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -6,23 +6,17 @@ LL | self.state = x; | = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:16:5 | LL | s.foo(3); - | ^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^ `&mut` is only allowed in `const fn` -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:22:13 | LL | let y = &mut x; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: constant contains unimplemented expression type --> $DIR/const_let_assign3.rs:24:5 @@ -34,5 +28,5 @@ LL | *y = 42; error: aborting due to 4 previous errors -Some errors have detailed explanations: E0019, E0658. +Some errors have detailed explanations: E0019, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/projection_qualif.mut_refs.stderr b/src/test/ui/consts/projection_qualif.mut_refs.stderr index 0945a23f3b1..fad8f011f75 100644 --- a/src/test/ui/consts/projection_qualif.mut_refs.stderr +++ b/src/test/ui/consts/projection_qualif.mut_refs.stderr @@ -1,3 +1,9 @@ +error[E0764]: mutable references are not allowed in constants + --> $DIR/projection_qualif.rs:10:27 + | +LL | let b: *mut u32 = &mut a; + | ^^^^^^ `&mut` is only allowed in `const fn` + error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/projection_qualif.rs:11:18 | @@ -7,6 +13,7 @@ LL | unsafe { *b = 5; } = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index cfe8e7f03d5..7db970cf137 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -7,7 +7,7 @@ use std::cell::Cell; const FOO: &u32 = { let mut a = 42; { - let b: *mut u32 = &mut a; //[stock]~ ERROR may only refer to immutable values + let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants //[stock]~^ contains unimplemented expression } diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr index cfa48d947c9..212f1228645 100644 --- a/src/test/ui/consts/projection_qualif.stock.stderr +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/projection_qualif.rs:10:27 | LL | let b: *mut u32 = &mut a; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/projection_qualif.rs:11:18 @@ -26,5 +23,5 @@ LL | unsafe { *b = 5; } error: aborting due to 3 previous errors -Some errors have detailed explanations: E0019, E0658. +Some errors have detailed explanations: E0019, E0658, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/read_from_static_mut_ref.rs b/src/test/ui/consts/read_from_static_mut_ref.rs index c18227e0f55..5faa983ab09 100644 --- a/src/test/ui/consts/read_from_static_mut_ref.rs +++ b/src/test/ui/consts/read_from_static_mut_ref.rs @@ -1,10 +1,9 @@ -// run-pass +// We are keeping this test in case we decide to allow mutable references in statics again #![feature(const_mut_refs)] #![allow(const_err)] -static OH_YES: &mut i32 = &mut 42; - +static OH_NO: &mut i32 = &mut 42; +//~^ ERROR mutable references are not allowed in statics fn main() { - // Make sure `OH_YES` can be read. - assert_eq!(*OH_YES, 42); + assert_eq!(*OH_NO, 42); } diff --git a/src/test/ui/consts/read_from_static_mut_ref.stderr b/src/test/ui/consts/read_from_static_mut_ref.stderr new file mode 100644 index 00000000000..c936ac0b7d5 --- /dev/null +++ b/src/test/ui/consts/read_from_static_mut_ref.stderr @@ -0,0 +1,9 @@ +error[E0764]: mutable references are not allowed in statics + --> $DIR/read_from_static_mut_ref.rs:5:26 + | +LL | static OH_NO: &mut i32 = &mut 42; + | ^^^^^^^ `&mut` is only allowed in `const fn` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index 8db75dd63cf..36c280ca5c6 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,9 +1,9 @@ -error[E0080]: could not evaluate static initializer - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 +error[E0764]: mutable references are not allowed in statics + --> $DIR/static_mut_containing_mut_ref2.rs:7:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index 74162fbd54b..a6bbe8d6ec2 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -5,8 +5,7 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; -//[mut_refs]~^ ERROR could not evaluate static initializer -//[stock]~^^ ERROR references in statics may only refer to immutable values +//~^ ERROR mutable references are not allowed in statics //[stock]~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index cc169351bf2..57fb27e642e 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/static_mut_containing_mut_ref2.rs:7:46 | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type --> $DIR/static_mut_containing_mut_ref2.rs:7:45 @@ -17,5 +14,5 @@ LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 4 error: aborting due to 2 previous errors -Some errors have detailed explanations: E0019, E0658. +Some errors have detailed explanations: E0019, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/trait_specialization.rs b/src/test/ui/consts/trait_specialization.rs index 8010d2fe1ae..3adbbb53046 100644 --- a/src/test/ui/consts/trait_specialization.rs +++ b/src/test/ui/consts/trait_specialization.rs @@ -5,7 +5,7 @@ // Tests that specialization does not cause optimizations running on polymorphic MIR to resolve // to a `default` implementation. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Marker {} diff --git a/src/test/ui/consts/trait_specialization.stderr b/src/test/ui/consts/trait_specialization.stderr new file mode 100644 index 00000000000..03da7d512e5 --- /dev/null +++ b/src/test/ui/consts/trait_specialization.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait_specialization.rs:8:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 749d569b9ae..006a334021b 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -9,6 +9,10 @@ LL | impl Foo<[isize]> for usize { } | = help: the trait `std::marker::Sized` is not implemented for `[isize]` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized + | ^^^^^^^^ error[E0277]: the size for values of type `[usize]` cannot be known at compilation time --> $DIR/dst-sized-trait-param.rs:10:6 diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 64be41170d0..818dec1207b 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -2,10 +2,10 @@ static X: i32 = 1; const C: i32 = 2; static mut M: i32 = 3; -const CR: &'static mut i32 = &mut C; //~ ERROR E0658 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 +const CR: &'static mut i32 = &mut C; //~ ERROR E0764 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 //~| ERROR E0019 //~| ERROR cannot borrow -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 -static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0658 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 +static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index f959ad0d008..c1d96de1dca 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type --> $DIR/E0017.rs:6:39 @@ -15,14 +12,11 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; | = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/E0017.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0017.rs:6:39 @@ -30,25 +24,19 @@ error[E0596]: cannot borrow immutable static item `X` as mutable LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/E0017.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/E0017.rs:10:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; - | ^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to 6 previous errors -Some errors have detailed explanations: E0019, E0596, E0658. +Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 5954e3490b0..13131017c2e 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -1,10 +1,10 @@ static X: i32 = 1; const C: i32 = 2; -const CR: &'static mut i32 = &mut C; //~ ERROR E0658 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0658 +const CR: &'static mut i32 = &mut C; //~ ERROR E0764 +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019 //~| ERROR cannot borrow - //~| ERROR E0019 -static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0658 + //~| ERROR E0764 +static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index 8bdfbac3681..f09100bac43 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/E0388.rs:4:30 | LL | const CR: &'static mut i32 = &mut C; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0019]: static contains unimplemented expression type --> $DIR/E0388.rs:5:39 @@ -15,14 +12,11 @@ LL | static STATIC_REF: &'static mut i32 = &mut X; | = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/E0388.rs:5:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable --> $DIR/E0388.rs:5:39 @@ -30,16 +24,13 @@ error[E0596]: cannot borrow immutable static item `X` as mutable LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/E0388.rs:8:38 | LL | static CONST_REF: &'static mut i32 = &mut C; - | ^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to 5 previous errors -Some errors have detailed explanations: E0019, E0596, E0658. +Some errors have detailed explanations: E0019, E0596, E0764. For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/error-codes/E0520.rs b/src/test/ui/error-codes/E0520.rs index b746ca63590..ead78b7ffa2 100644 --- a/src/test/ui/error-codes/E0520.rs +++ b/src/test/ui/error-codes/E0520.rs @@ -1,4 +1,5 @@ #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete trait SpaceLlama { fn fly(&self); diff --git a/src/test/ui/error-codes/E0520.stderr b/src/test/ui/error-codes/E0520.stderr index 72fc85ab1e7..1041ccee937 100644 --- a/src/test/ui/error-codes/E0520.stderr +++ b/src/test/ui/error-codes/E0520.stderr @@ -1,5 +1,14 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/E0520.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/E0520.rs:16:5 + --> $DIR/E0520.rs:17:5 | LL | / impl<T: Clone> SpaceLlama for T { LL | | fn fly(&self) {} @@ -11,6 +20,6 @@ LL | default fn fly(&self) {} | = note: to specialize, `fly` in the parent `impl` must be marked `default` -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0520`. diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr index 5861bdcb7a9..18835310bd5 100644 --- a/src/test/ui/error-codes/E0604.stderr +++ b/src/test/ui/error-codes/E0604.stderr @@ -2,7 +2,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/E0604.rs:2:5 | LL | 1u32 as char; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ invalid cast error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index 95e899db8b7..f23d2008e0b 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -2,17 +2,13 @@ error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>` --> $DIR/E0605.rs:3:5 | LL | x as Vec<u8>; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/E0605.rs:6:5 | LL | v as &u8; - | ^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 7f524230ef0..905195d4ad9 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -42,15 +42,13 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:25:5 | LL | 0u32 as char; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `u8` as `std::vec::Vec<u8>` --> $DIR/error-festival.rs:29:5 | LL | x as Vec<u8>; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0054]: cannot cast as `bool` --> $DIR/error-festival.rs:33:24 diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 9ed52511fa3..0c7995fde32 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -26,6 +26,10 @@ LL | assert_sized::<Foo>(); = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required because it appears within the type `Foo` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() { } + | ^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:28:5 @@ -39,6 +43,10 @@ LL | assert_sized::<Bar<A>>(); = help: within `Bar<A>`, the trait `std::marker::Sized` is not implemented for `A` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required because it appears within the type `Bar<A>` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() { } + | ^^^^^^^^ error[E0277]: the size for values of type `A` cannot be known at compilation time --> $DIR/extern-types-unsized.rs:31:5 @@ -53,6 +61,10 @@ LL | assert_sized::<Bar<Bar<A>>>(); = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required because it appears within the type `Bar<A>` = note: required because it appears within the type `Bar<Bar<A>>` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn assert_sized<T: ?Sized>() { } + | ^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr index 93e1471838f..56d5a26beb0 100644 --- a/src/test/ui/fat-ptr-cast.stderr +++ b/src/test/ui/fat-ptr-cast.stderr @@ -34,9 +34,7 @@ error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize` --> $DIR/fat-ptr-cast.rs:14:5 | LL | b as usize; - | ^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0606]: casting `*const [i32]` as `usize` is invalid --> $DIR/fat-ptr-cast.rs:15:5 diff --git a/src/test/ui/impl-trait/binding-without-value.rs b/src/test/ui/impl-trait/binding-without-value.rs new file mode 100644 index 00000000000..6a97f28ff55 --- /dev/null +++ b/src/test/ui/impl-trait/binding-without-value.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(impl_trait_in_bindings)] + +fn foo() { + let _ : impl Copy; + //~^ ERROR cannot resolve opaque type +} + +fn main() {} diff --git a/src/test/ui/impl-trait/binding-without-value.stderr b/src/test/ui/impl-trait/binding-without-value.stderr new file mode 100644 index 00000000000..0d2faeaf85d --- /dev/null +++ b/src/test/ui/impl-trait/binding-without-value.stderr @@ -0,0 +1,16 @@ +error[E0720]: cannot resolve opaque type + --> $DIR/binding-without-value.rs:5:13 + | +LL | let _ : impl Copy; + | - ^^^^^^^^^ cannot resolve opaque type + | | + | this binding might not have a concrete type + | +help: set the binding to a value for a concrete type to be resolved + | +LL | let _ : impl Copy = /* value */; + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/equality-rpass.rs b/src/test/ui/impl-trait/equality-rpass.rs index 05c9e4173b0..607b4a49661 100644 --- a/src/test/ui/impl-trait/equality-rpass.rs +++ b/src/test/ui/impl-trait/equality-rpass.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo: std::fmt::Debug + Eq {} diff --git a/src/test/ui/impl-trait/equality-rpass.stderr b/src/test/ui/impl-trait/equality-rpass.stderr new file mode 100644 index 00000000000..1abf05dca82 --- /dev/null +++ b/src/test/ui/impl-trait/equality-rpass.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality-rpass.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/impl-trait/equality.rs b/src/test/ui/impl-trait/equality.rs index 14b0eeb739a..828b5aac896 100644 --- a/src/test/ui/impl-trait/equality.rs +++ b/src/test/ui/impl-trait/equality.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo: Copy + ToString {} diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 9178358b60a..628dfb13d4c 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0308]: mismatched types --> $DIR/equality.rs:15:5 | @@ -24,7 +33,7 @@ LL | n + sum_to(n - 1) | = help: the trait `std::ops::Add<impl Foo>` is not implemented for `u32` -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/equality2.rs b/src/test/ui/impl-trait/equality2.rs index abce8c8c204..2e325867da8 100644 --- a/src/test/ui/impl-trait/equality2.rs +++ b/src/test/ui/impl-trait/equality2.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo: Copy + ToString {} diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 2454c218ffc..1780931efc5 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/equality2.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 | @@ -58,6 +67,6 @@ LL | x.0); = note: expected opaque type `impl Foo` (`i32`) found opaque type `impl Foo` (`u32`) -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs index 150a8015cbc..451ddb3cce0 100644 --- a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs +++ b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.rs @@ -5,13 +5,13 @@ trait Quux {} -fn foo() -> impl Quux { //~ opaque type expands to a recursive type +fn foo() -> impl Quux { //~ ERROR cannot resolve opaque type struct Foo<T>(T); impl<T> Quux for Foo<T> {} Foo(bar()) } -fn bar() -> impl Quux { //~ opaque type expands to a recursive type +fn bar() -> impl Quux { //~ ERROR cannot resolve opaque type struct Bar<T>(T); impl<T> Quux for Bar<T> {} Bar(foo()) diff --git a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr index d10001e8a8e..c538b77098a 100644 --- a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr +++ b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -1,18 +1,26 @@ -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/infinite-impl-trait-issue-38064.rs:8:13 | LL | fn foo() -> impl Quux { - | ^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `foo::Foo<bar::Bar<impl Quux>>` + | ^^^^^^^^^ recursive opaque type +... +LL | Foo(bar()) + | ---------- returning here with type `foo::Foo<impl Quux>` +... +LL | fn bar() -> impl Quux { + | --------- returning this opaque type `foo::Foo<impl Quux>` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 | +LL | fn foo() -> impl Quux { + | --------- returning this opaque type `bar::Bar<impl Quux>` +... LL | fn bar() -> impl Quux { - | ^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `bar::Bar<foo::Foo<impl Quux>>` + | ^^^^^^^^^ recursive opaque type +... +LL | Bar(foo()) + | ---------- returning here with type `bar::Bar<impl Quux>` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 1806d2607a3..ca9ca8a9deb 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -26,7 +26,34 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:12:69 + --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | - ^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + | + = help: consider replacing `'1` with `'static` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` + | + = help: consider replacing `'a` with `'static` + = help: consider replacing `'a` with `'static` + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:15:41 + | +LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } + | ---- ^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + +error: lifetime may not live long enough + --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` @@ -35,7 +62,7 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } = help: consider replacing `'a` with `'static` error: lifetime may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:17:61 + --> $DIR/must_outlive_least_region_or_bound.rs:38:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a` @@ -45,13 +72,14 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 = help: consider adding the following bound: `'b: 'a` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:22:51 + --> $DIR/must_outlive_least_region_or_bound.rs:43:51 | LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { | ^^^^^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0310`. +Some errors have detailed explanations: E0310, E0621. +For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs index 00f3490991b..837244b0227 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.rs @@ -6,6 +6,27 @@ fn elided(x: &i32) -> impl Copy { x } fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~^ ERROR cannot infer an appropriate lifetime +fn elided2(x: &i32) -> impl Copy + 'static { x } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } +//~^ ERROR cannot infer an appropriate lifetime + +fn foo<'a>(x: &i32) -> impl Copy + 'a { x } +//~^ ERROR explicit lifetime required in the type of `x` + +fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + +fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + +fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } +//~^ ERROR cannot infer an appropriate lifetime + trait LifetimeTrait<'a> {} impl<'a> LifetimeTrait<'a> for &'a i32 {} diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index d7dae6a08a7..e1fa4f02b6f 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -1,47 +1,113 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } - | ---- --------- ^ ...and is captured here - | | | - | | ...is required to be `'static` by this... - | data with this lifetime... + | ---- ^ ...is captured here... + | | + | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:3:23 + | +LL | fn elided(x: &i32) -> impl Copy { x } + | ^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided(x: &i32) -> impl Copy + '_ { x } | ^^^^ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } - | ------- --------- ^ ...and is captured here - | | | - | | ...is required to be `'static` by this... - | data with this lifetime... + | ------- ^ ...is captured here... + | | + | this data with lifetime `'a`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 6:13 +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:6:32 + | +LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } + | ^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } | ^^^^ -error: cannot infer an appropriate lifetime - --> $DIR/must_outlive_least_region_or_bound.rs:12:69 +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:9:46 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | ---- ^ ...is captured here... + | | + | this data with an anonymous lifetime `'_`... + | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:9:24 + | +LL | fn elided2(x: &i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^^^^^^^^ +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` + | +LL | fn elided2(x: &i32) -> impl Copy + '_ { x } + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:12:55 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | ------- ^ ...is captured here... + | | + | this data with lifetime `'a`... + | +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:12:33 + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^^^^^^^^ +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` + | +LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn explicit2<'a>(x: &'static i32) -> impl Copy + 'static { x } + | ^^^^^^^^^^^^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/must_outlive_least_region_or_bound.rs:15:24 + | +LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } + | ---- ^^^^^^^^^^^^^^ lifetime `'a` required + | | + | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:33:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | ------- -------------------------------- ^ ...and is captured here - | | | - | | ...is required to be `'static` by this... - | data with this lifetime... + | ------- this data with lifetime `'a`... ^ ...is captured here... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the function body at 12:15 +note: ...and is required to live as long as `'static` here + --> $DIR/must_outlive_least_region_or_bound.rs:33:34 + | +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider changing the `impl Trait`'s explicit `'static` bound to the lifetime of argument `x` | -LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static + 'a { x } - | ^^^^ +LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'a { x } + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn with_bound<'a>(x: &'static i32) -> impl LifetimeTrait<'a> + 'static { x } + | ^^^^^^^^^^^^ error[E0623]: lifetime mismatch - --> $DIR/must_outlive_least_region_or_bound.rs:17:61 + --> $DIR/must_outlive_least_region_or_bound.rs:38:61 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { | ------- ^^^^^^^^^^^^^^^^ @@ -50,14 +116,72 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 | this parameter and the return type are declared with different lifetimes... error[E0310]: the parameter type `T` may not live long enough - --> $DIR/must_outlive_least_region_or_bound.rs:22:51 + --> $DIR/must_outlive_least_region_or_bound.rs:43:51 | LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static { | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `T: 'static +` -error: aborting due to 5 previous errors +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:18:50 + | +LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } + | ---- ^ ...is captured here, requiring it to live as long as `'static` + | | + | this data with an anonymous lifetime `'_`... + | +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound + | +LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) } + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:21:59 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } + | ------- ^ ...is captured here, requiring it to live as long as `'static` + | | + | this data with lifetime `'a`... + | +help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound + | +LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) } + | ^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:24:60 + | +LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } + | ---- ^ ...is captured here, requiring it to live as long as `'static` + | | + | this data with an anonymous lifetime `'_`... + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` + | +LL | fn elided4(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) } + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) } + | ^^^^^^^^^^^^ + +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/must_outlive_least_region_or_bound.rs:27:69 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } + | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` + | +LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) } + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn explicit4<'a>(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) } + | ^^^^^^^^^^^^ + +error: aborting due to 12 previous errors -Some errors have detailed explanations: E0310, E0623. +Some errors have detailed explanations: E0310, E0621, E0623, E0759. For more information about an error, try `rustc --explain E0310`. 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 b5135b53e18..3cd4d0dd391 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -49,14 +49,6 @@ LL | use foo::Bar; error[E0599]: no method named `method` found for struct `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<std::rc::Rc<&mut std::boxed::Box<&char>>>` here - | the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&char>>>` here - | the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here - | the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&char>>>` here -... LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` | @@ -83,16 +75,6 @@ error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::b | LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` - | - ::: $DIR/auxiliary/no_method_suggested_traits.rs:8:12 - | -LL | fn method(&self) {} - | ------ - | | - | the method is available for `std::boxed::Box<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here - | the method is available for `std::pin::Pin<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here - | the method is available for `std::sync::Arc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here - | the method is available for `std::rc::Rc<std::rc::Rc<&mut std::boxed::Box<&i32>>>` here | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr index 5a95e2969d1..5a3027ec751 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-direct.stderr @@ -1,10 +1,11 @@ -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-direct.rs:5:14 | LL | fn test() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: type resolves to itself + | ^^^^^^^^^^ recursive opaque type +LL | +LL | test() + | ------ returning here with type `impl Sized` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 6573b00870c..75ff9e078cc 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -1,114 +1,147 @@ -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:7:22 | LL | fn option(i: i32) -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `std::option::Option<(impl Sized, i32)>` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | if i < 0 { None } else { Some((option(i - 1), i)) } + | ---- ------------------------ returning here with type `std::option::Option<(impl Sized, i32)>` + | | + | returning here with type `std::option::Option<(impl Sized, i32)>` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 | LL | fn tuple() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `(impl Sized,)` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (tuple(),) + | ---------- returning here with type `(impl Sized,)` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:17:15 | LL | fn array() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[impl Sized; 1]` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | [array()] + | --------- returning here with type `[impl Sized; 1]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:22:13 | LL | fn ptr() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `*const impl Sized` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | &ptr() as *const _ + | ------------------ returning here with type `*const impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:27:16 | LL | fn fn_ptr() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `fn() -> impl Sized` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | fn_ptr as fn() -> _ + | ------------------- returning here with type `fn() -> impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:32:25 | -LL | fn closure_capture() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` +LL | fn closure_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | x; +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 | -LL | fn closure_ref_capture() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` +LL | fn closure_ref_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | &x; +LL | | } + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 | LL | fn closure_sig() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || closure_sig() + | ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:53:23 | LL | fn generator_sig() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | || generator_sig() + | ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:58:27 | -LL | fn generator_capture() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` +LL | fn generator_capture() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +... +LL | / move || { +LL | | yield; +LL | | x; +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 | LL | fn substs_change<T: 'static>() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `(impl Sized,)` + | ^^^^^^^^^^ recursive opaque type +LL | +LL | (substs_change::<&T>(),) + | ------------------------ returning here with type `(impl Sized,)` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:72:24 | -LL | fn generator_hold() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]` +LL | fn generator_hold() -> impl Sized { + | ^^^^^^^^^^ recursive opaque type +LL | +LL | / move || { +LL | | let x = generator_hold(); +LL | | yield; +LL | | x; +LL | | } + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:86:26 | LL | fn mutual_recursion() -> impl Sync { - | ^^^^^^^^^ expands to a recursive type - | - = note: type resolves to itself + | ^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion_b() + | -------------------- returning here with type `impl Sized` +... +LL | fn mutual_recursion_b() -> impl Sized { + | ---------- returning this opaque type `impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | +LL | fn mutual_recursion() -> impl Sync { + | --------- returning this opaque type `impl std::marker::Sync` +... LL | fn mutual_recursion_b() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: type resolves to itself + | ^^^^^^^^^^ recursive opaque type +LL | +LL | mutual_recursion() + | ------------------ returning here with type `impl std::marker::Sync` error: aborting due to 14 previous errors diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs index cfd9c0ec5b4..818e4036539 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.rs @@ -4,21 +4,21 @@ fn id<T>(t: T) -> impl Sized { t } -fn recursive_id() -> impl Sized { //~ ERROR opaque type expands to a recursive type +fn recursive_id() -> impl Sized { //~ ERROR cannot resolve opaque type id(recursive_id2()) } -fn recursive_id2() -> impl Sized { //~ ERROR opaque type expands to a recursive type +fn recursive_id2() -> impl Sized { //~ ERROR cannot resolve opaque type id(recursive_id()) } fn wrap<T>(t: T) -> impl Sized { (t,) } -fn recursive_wrap() -> impl Sized { //~ ERROR opaque type expands to a recursive type +fn recursive_wrap() -> impl Sized { //~ ERROR cannot resolve opaque type wrap(recursive_wrap2()) } -fn recursive_wrap2() -> impl Sized { //~ ERROR opaque type expands to a recursive type +fn recursive_wrap2() -> impl Sized { //~ ERROR cannot resolve opaque type wrap(recursive_wrap()) } diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr index 73c12f6137d..fbc58837a8e 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-through-non-recursive.stderr @@ -1,34 +1,46 @@ -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:7:22 | +LL | fn id<T>(t: T) -> impl Sized { t } + | ---------- returning this opaque type `impl Sized` +LL | LL | fn recursive_id() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: type resolves to itself + | ^^^^^^^^^^ recursive opaque type +LL | id(recursive_id2()) + | ------------------- returning here with type `impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:11:23 | +LL | fn id<T>(t: T) -> impl Sized { t } + | ---------- returning this opaque type `impl Sized` +... LL | fn recursive_id2() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: type resolves to itself + | ^^^^^^^^^^ recursive opaque type +LL | id(recursive_id()) + | ------------------ returning here with type `impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:17:24 | +LL | fn wrap<T>(t: T) -> impl Sized { (t,) } + | ---------- returning this opaque type `impl Sized` +LL | LL | fn recursive_wrap() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `((impl Sized,),)` + | ^^^^^^^^^^ recursive opaque type +LL | wrap(recursive_wrap2()) + | ----------------------- returning here with type `impl Sized` -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-through-non-recursive.rs:21:25 | +LL | fn wrap<T>(t: T) -> impl Sized { (t,) } + | ---------- returning this opaque type `impl Sized` +... LL | fn recursive_wrap2() -> impl Sized { - | ^^^^^^^^^^ expands to a recursive type - | - = note: expanded type is `((impl Sized,),)` + | ^^^^^^^^^^ recursive opaque type +LL | wrap(recursive_wrap()) + | ---------------------- returning here with type `impl Sized` error: aborting due to 4 previous errors diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr index 1c3a5979ee5..df0db6e4fc6 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr @@ -1,36 +1,43 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:7:16 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { - | ----- ----------------------- ...is required to be `'static` by this... - | | - | data with this lifetime... + | ----- this data with an anonymous lifetime `'_`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...and is captured here + | ...is captured here... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 +note: ...and is required to live as long as `'static` here + --> $DIR/static-return-lifetime-infered.rs:6:35 + | +LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { | ^^^^ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:11:16 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { - | -------- ----------------------- ...is required to be `'static` by this... - | | - | data with this lifetime... + | -------- this data with lifetime `'a`... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | - | ...and is captured here + | ...is captured here... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the lifetime `'a` as defined on the method body at 10:20 +note: ...and is required to live as long as `'static` here + --> $DIR/static-return-lifetime-infered.rs:10:37 + | +LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'a` lifetime bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a { | ^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/impl-trait/where-allowed-2.rs b/src/test/ui/impl-trait/where-allowed-2.rs index f7744ef1b3e..462508f306e 100644 --- a/src/test/ui/impl-trait/where-allowed-2.rs +++ b/src/test/ui/impl-trait/where-allowed-2.rs @@ -3,7 +3,6 @@ use std::fmt::Debug; // Disallowed -fn in_adt_in_return() -> Vec<impl Debug> { panic!() } -//~^ ERROR opaque type expands to a recursive type +fn in_adt_in_return() -> Vec<impl Debug> { panic!() } //~ ERROR cannot resolve opaque type fn main() {} diff --git a/src/test/ui/impl-trait/where-allowed-2.stderr b/src/test/ui/impl-trait/where-allowed-2.stderr index 1de15014c1f..b8e06725cbc 100644 --- a/src/test/ui/impl-trait/where-allowed-2.stderr +++ b/src/test/ui/impl-trait/where-allowed-2.stderr @@ -1,10 +1,12 @@ -error[E0720]: opaque type expands to a recursive type +error[E0720]: cannot resolve opaque type --> $DIR/where-allowed-2.rs:6:30 | LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() } - | ^^^^^^^^^^ expands to a recursive type + | ^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type | - = note: type resolves to itself + = help: this error will resolve once the item's body returns a concrete type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index 888576c4336..d7a4bf4f21f 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -57,6 +57,10 @@ LL | impl<'self> Serializable<str> for &'self str { | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider relaxing the implicit `Sized` restriction + | +LL | trait Serializable<'self, T: ?Sized> { + | ^^^^^^^^ error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-10991.stderr b/src/test/ui/issues/issue-10991.stderr index f12539b47cf..5b8a1823386 100644 --- a/src/test/ui/issues/issue-10991.stderr +++ b/src/test/ui/issues/issue-10991.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `()` as `usize` --> $DIR/issue-10991.rs:3:14 | LL | let _t = nil as usize; - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16048.rs b/src/test/ui/issues/issue-16048.rs index 7d24f3a40a7..eaf6acff26b 100644 --- a/src/test/ui/issues/issue-16048.rs +++ b/src/test/ui/issues/issue-16048.rs @@ -18,12 +18,12 @@ impl<'a> Test<'a> for Foo<'a> { } impl<'a> NoLifetime for Foo<'a> { - fn get<'p, T : Test<'a>>(&self) -> T { + fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T { //~^ ERROR E0195 //~| NOTE lifetimes do not match method in trait return *self as T; //~^ ERROR non-primitive cast: `Foo<'a>` as `T` - //~| NOTE an `as` expression can only be used to convert between primitive types. + //~| NOTE an `as` expression can only be used to convert between primitive types } } diff --git a/src/test/ui/issues/issue-16048.stderr b/src/test/ui/issues/issue-16048.stderr index a137bcdf191..73610942d7a 100644 --- a/src/test/ui/issues/issue-16048.stderr +++ b/src/test/ui/issues/issue-16048.stderr @@ -4,16 +4,16 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the tra LL | fn get<'p, T : Test<'p>>(&self) -> T; | ------------------ lifetimes in impl do not match this method in trait ... -LL | fn get<'p, T : Test<'a>>(&self) -> T { - | ^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait +LL | fn get<'p, T: Test<'a> + From<Foo<'a>>>(&self) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait error[E0605]: non-primitive cast: `Foo<'a>` as `T` --> $DIR/issue-16048.rs:24:16 | LL | return *self as T; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: consider using the `From` trait instead: `T::from(*self)` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 02d33aae023..919594fc9af 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -1,18 +1,16 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/issue-16922.rs:4:14 | LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> { - | -- data with this lifetime... + | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box<dyn Any> - | ---------^^^^^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^^^^^ ...is captured here, requiring it to live as long as `'static` | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 3:1 +help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | LL | fn foo<T: Any>(value: &T) -> Box<dyn Any + '_> { | ^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr index 0ab035515a0..b63a3995d25 100644 --- a/src/test/ui/issues/issue-17441.stderr +++ b/src/test/ui/issues/issue-17441.stderr @@ -16,7 +16,7 @@ error[E0620]: cast to unsized type: `std::boxed::Box<usize>` as `dyn std::fmt::D LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^------------------- | | - | help: try casting to a `Box` instead: `Box<dyn std::fmt::Debug>` + | help: you can cast to a `Box` instead: `Box<dyn std::fmt::Debug>` error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug` --> $DIR/issue-17441.rs:8:16 diff --git a/src/test/ui/issues/issue-17718-const-bad-values.rs b/src/test/ui/issues/issue-17718-const-bad-values.rs index 9355c8ab152..49023f18ddb 100644 --- a/src/test/ui/issues/issue-17718-const-bad-values.rs +++ b/src/test/ui/issues/issue-17718-const-bad-values.rs @@ -1,10 +1,10 @@ const C1: &'static mut [usize] = &mut []; -//~^ ERROR: references in constants may only refer to immutable values +//~^ ERROR: mutable references are not allowed in constants static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: constants cannot refer to statics //~| ERROR: constants cannot refer to statics -//~| ERROR: references in constants may only refer to immutable values +//~| ERROR: mutable references are not allowed in constants fn main() {} diff --git a/src/test/ui/issues/issue-17718-const-bad-values.stderr b/src/test/ui/issues/issue-17718-const-bad-values.stderr index 688efcdd022..7c50978d4eb 100644 --- a/src/test/ui/issues/issue-17718-const-bad-values.stderr +++ b/src/test/ui/issues/issue-17718-const-bad-values.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-17718-const-bad-values.rs:1:34 | LL | const C1: &'static mut [usize] = &mut []; - | ^^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^ `&mut` is only allowed in `const fn` error[E0013]: constants cannot refer to statics --> $DIR/issue-17718-const-bad-values.rs:5:46 @@ -23,16 +20,13 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; | = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0658]: references in constants may only refer to immutable values +error[E0764]: mutable references are not allowed in constants --> $DIR/issue-17718-const-bad-values.rs:5:41 | LL | const C2: &'static mut usize = unsafe { &mut S }; - | ^^^^^^ constants require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^ `&mut` is only allowed in `const fn` error: aborting due to 4 previous errors -Some errors have detailed explanations: E0013, E0658. +Some errors have detailed explanations: E0013, E0764. For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 1ea40d0728e..383cdd4979a 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -9,6 +9,13 @@ LL | enum Option<T> { | = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/issue-18919.rs:7:13 + | +LL | enum Option<T> { + | ^ this could be changed to `T: ?Sized`... +LL | Some(T), + | - ...if indirection was used here: `Box<T>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index cc7ace30cab..4c35deb1fbe 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)` --> $DIR/issue-22289.rs:2:5 | LL | 0 as &dyn std::any::Any; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait +help: borrow the value for the cast to be valid + | +LL | &0 as &dyn std::any::Any; + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22312.rs b/src/test/ui/issues/issue-22312.rs index 250fec25887..4e359b3412a 100644 --- a/src/test/ui/issues/issue-22312.rs +++ b/src/test/ui/issues/issue-22312.rs @@ -1,6 +1,6 @@ use std::ops::Index; -pub trait Array2D: Index<usize> { +pub trait Array2D: Index<usize> + Sized { fn rows(&self) -> usize; fn columns(&self) -> usize; fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a <Self as Index<usize>>::Output> { diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index fc32fd376b7..28564b07463 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -2,9 +2,12 @@ error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index<usize, Output --> $DIR/issue-22312.rs:11:24 | LL | let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait +help: borrow the value for the cast to be valid + | +LL | let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>); + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23046.rs b/src/test/ui/issues/issue-23046.rs index a68369616d8..75be4a11efd 100644 --- a/src/test/ui/issues/issue-23046.rs +++ b/src/test/ui/issues/issue-23046.rs @@ -14,7 +14,7 @@ pub fn let_<'var, VAR, F: for<'v> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>> } fn main() { - let ex = |x| { //~ ERROR type annotations needed - let_(add(x,x), |y| { + let ex = |x| { + let_(add(x,x), |y| { //~ ERROR type annotations needed let_(add(x, x), |x|x)})}; } diff --git a/src/test/ui/issues/issue-23046.stderr b/src/test/ui/issues/issue-23046.stderr index 12b2eb48e7e..77555fce7c4 100644 --- a/src/test/ui/issues/issue-23046.stderr +++ b/src/test/ui/issues/issue-23046.stderr @@ -1,8 +1,13 @@ -error[E0282]: type annotations needed for `Expr<'_, VAR>` - --> $DIR/issue-23046.rs:17:15 +error[E0282]: type annotations needed for the closure `fn(Expr<'_, _>) -> Expr<'_, _>` + --> $DIR/issue-23046.rs:18:9 | -LL | let ex = |x| { - | ^ consider giving this closure parameter the explicit type `Expr<'_, VAR>`, where the type parameter `VAR` is specified +LL | let_(add(x,x), |y| { + | ^^^^ cannot infer type for type parameter `VAR` declared on the function `let_` + | +help: give this closure an explicit return type without `_` placeholders + | +LL | let_(add(x, x), |x|-> Expr<'_, _> { x })})}; + | ^^^^^^^^^^^^^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index 3b4b8997a70..cffa5236169 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -9,6 +9,13 @@ LL | struct Vec<T> { | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/issue-23281.rs:8:12 + | +LL | struct Vec<T> { + | ^ this could be changed to `T: ?Sized`... +LL | t: T, + | - ...if indirection was used here: `Box<T>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index c316780d5f6..9f5968399a3 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` --> $DIR/issue-2995.rs:2:22 | LL | let _q: &isize = p as &isize; - | ^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35376.rs b/src/test/ui/issues/issue-35376.rs index eb139ec4d7f..cc35213b93d 100644 --- a/src/test/ui/issues/issue-35376.rs +++ b/src/test/ui/issues/issue-35376.rs @@ -1,5 +1,6 @@ // check-pass #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete fn main() {} diff --git a/src/test/ui/issues/issue-35376.stderr b/src/test/ui/issues/issue-35376.stderr new file mode 100644 index 00000000000..06c31f3bae0 --- /dev/null +++ b/src/test/ui/issues/issue-35376.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-35376.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/issues/issue-38091.rs b/src/test/ui/issues/issue-38091.rs index 00aa810f830..c1262430502 100644 --- a/src/test/ui/issues/issue-38091.rs +++ b/src/test/ui/issues/issue-38091.rs @@ -1,5 +1,6 @@ // run-pass #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete trait Iterate<'a> { type Ty: Valid; diff --git a/src/test/ui/issues/issue-38091.stderr b/src/test/ui/issues/issue-38091.stderr new file mode 100644 index 00000000000..a9855445f66 --- /dev/null +++ b/src/test/ui/issues/issue-38091.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-38091.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/issues/issue-45730.stderr b/src/test/ui/issues/issue-45730.stderr index d4ddba52df1..d00f3d91b49 100644 --- a/src/test/ui/issues/issue-45730.stderr +++ b/src/test/ui/issues/issue-45730.stderr @@ -1,30 +1,24 @@ error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:3:23 + --> $DIR/issue-45730.rs:3:28 | LL | let x: *const _ = 0 as _; - | ^^^^^- - | | - | help: consider giving more type information + | ^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:5:23 + --> $DIR/issue-45730.rs:5:28 | LL | let x: *const _ = 0 as *const _; - | ^^^^^-------- - | | - | help: consider giving more type information + | ^^^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:8:13 + --> $DIR/issue-45730.rs:8:44 | LL | let x = 0 as *const i32 as *const _ as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ - | | - | help: consider giving more type information + | ^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid diff --git a/src/test/ui/issues/issue-46604.rs b/src/test/ui/issues/issue-46604.rs index e1967eb7655..273187a5a13 100644 --- a/src/test/ui/issues/issue-46604.rs +++ b/src/test/ui/issues/issue-46604.rs @@ -1,4 +1,4 @@ -static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0658 +static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; //~ ERROR E0764 fn write<T: AsRef<[u8]>>(buffer: T) { } fn main() { diff --git a/src/test/ui/issues/issue-46604.stderr b/src/test/ui/issues/issue-46604.stderr index 771e368a35d..5421721dec2 100644 --- a/src/test/ui/issues/issue-46604.stderr +++ b/src/test/ui/issues/issue-46604.stderr @@ -1,11 +1,8 @@ -error[E0658]: references in statics may only refer to immutable values +error[E0764]: mutable references are not allowed in statics --> $DIR/issue-46604.rs:1:25 | LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7]; - | ^^^^^^^^^^^^^^^^^^^^ statics require immutable values - | - = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item --> $DIR/issue-46604.rs:6:5 @@ -15,5 +12,5 @@ LL | buf[0]=2; error: aborting due to 2 previous errors -Some errors have detailed explanations: E0594, E0658. +Some errors have detailed explanations: E0594, E0764. For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/issues/issue-48508.rs b/src/test/ui/issues/issue-48508.rs index 87965c204ad..8dc9351260e 100644 --- a/src/test/ui/issues/issue-48508.rs +++ b/src/test/ui/issues/issue-48508.rs @@ -11,7 +11,7 @@ // ignore-asmjs wasm2js does not support source maps yet #![feature(non_ascii_idents)] -#[allow(uncommon_codepoints)] +#![allow(uncommon_codepoints)] #[path = "issue-48508-aux.rs"] mod other_file; diff --git a/src/test/ui/issues/issue-55380.rs b/src/test/ui/issues/issue-55380.rs index 862218e2192..f7cb296d3b8 100644 --- a/src/test/ui/issues/issue-55380.rs +++ b/src/test/ui/issues/issue-55380.rs @@ -1,6 +1,6 @@ // run-pass - #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete pub trait Foo { fn abc() -> u32; diff --git a/src/test/ui/issues/issue-55380.stderr b/src/test/ui/issues/issue-55380.stderr new file mode 100644 index 00000000000..451beebd106 --- /dev/null +++ b/src/test/ui/issues/issue-55380.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-55380.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/issues/issue-72690.rs b/src/test/ui/issues/issue-72690.rs new file mode 100644 index 00000000000..4edbd9ca15d --- /dev/null +++ b/src/test/ui/issues/issue-72690.rs @@ -0,0 +1,62 @@ +fn no_err() { + |x: String| x; + let _ = String::from("x"); +} + +fn err() { + String::from("x".as_ref()); //~ ERROR type annotations needed +} + +fn arg_pat_closure_err() { + |x| String::from("x".as_ref()); //~ ERROR type annotations needed +} + +fn local_pat_closure_err() { + let _ = "x".as_ref(); //~ ERROR type annotations needed +} + +fn err_first_arg_pat() { + String::from("x".as_ref()); //~ ERROR type annotations needed + |x: String| x; +} + +fn err_second_arg_pat() { + |x: String| x; + String::from("x".as_ref()); //~ ERROR type annotations needed +} + +fn err_mid_arg_pat() { + |x: String| x; + |x: String| x; + |x: String| x; + |x: String| x; + String::from("x".as_ref()); //~ ERROR type annotations needed + |x: String| x; + |x: String| x; + |x: String| x; + |x: String| x; +} + +fn err_first_local_pat() { + String::from("x".as_ref()); //~ ERROR type annotations needed + let _ = String::from("x"); +} + +fn err_second_local_pat() { + let _ = String::from("x"); + String::from("x".as_ref()); //~ ERROR type annotations needed +} + +fn err_mid_local_pat() { + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + String::from("x".as_ref()); //~ ERROR type annotations needed + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); + let _ = String::from("x"); +} + +fn main() {} diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr new file mode 100644 index 00000000000..64e78ddf604 --- /dev/null +++ b/src/test/ui/issues/issue-72690.stderr @@ -0,0 +1,88 @@ +error[E0283]: type annotations needed + --> $DIR/issue-72690.rs:7:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0282]: type annotations needed + --> $DIR/issue-72690.rs:11:6 + | +LL | |x| String::from("x".as_ref()); + | ^ consider giving this closure parameter a type + +error[E0283]: type annotations needed + --> $DIR/issue-72690.rs:15:17 + | +LL | let _ = "x".as_ref(); + | ^^^^^^ cannot infer type for type `str` + | + = note: cannot satisfy `str: std::convert::AsRef<_>` + +error[E0283]: type annotations needed + --> $DIR/issue-72690.rs:19:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0283]: type annotations needed + --> $DIR/issue-72690.rs:25:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0283]: type annotations needed + --> $DIR/issue-72690.rs:33:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0283]: type annotations needed for `std::string::String` + --> $DIR/issue-72690.rs:41:5 + | +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` +LL | let _ = String::from("x"); + | - consider giving this pattern a type + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0283]: type annotations needed for `std::string::String` + --> $DIR/issue-72690.rs:47:5 + | +LL | let _ = String::from("x"); + | - consider giving this pattern a type +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error[E0283]: type annotations needed for `std::string::String` + --> $DIR/issue-72690.rs:55:5 + | +LL | let _ = String::from("x"); + | - consider giving this pattern a type +... +LL | String::from("x".as_ref()); + | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | + = note: cannot satisfy `std::string::String: std::convert::From<&_>` + = note: required by `std::convert::From::from` + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/layout/debug.stderr b/src/test/ui/layout/debug.stderr index cd8ebdffb73..1a371c6b170 100644 --- a/src/test/ui/layout/debug.stderr +++ b/src/test/ui/layout/debug.stderr @@ -10,15 +10,15 @@ error: layout_of(E) = Layout { ], }, variants: Multiple { - discr: Scalar { + tag: Scalar { value: Int( I32, false, ), valid_range: 0..=0, }, - discr_kind: Tag, - discr_index: 0, + tag_encoding: Direct, + tag_field: 0, variants: [ Layout { fields: Arbitrary { @@ -202,15 +202,15 @@ error: layout_of(std::result::Result<i32, i32>) = Layout { ], }, variants: Multiple { - discr: Scalar { + tag: Scalar { value: Int( I32, false, ), valid_range: 0..=1, }, - discr_kind: Tag, - discr_index: 0, + tag_encoding: Direct, + tag_field: 0, variants: [ Layout { fields: Arbitrary { diff --git a/src/test/ui/lint/crate_level_only_lint.rs b/src/test/ui/lint/crate_level_only_lint.rs new file mode 100644 index 00000000000..d9673faa214 --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.rs @@ -0,0 +1,22 @@ +#![deny(uncommon_codepoints, unused_attributes)] + +mod foo { +#![allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +const BAR: f64 = 0.000001; + +} + +#[allow(uncommon_codepoints)] +//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes] +fn main() { +} diff --git a/src/test/ui/lint/crate_level_only_lint.stderr b/src/test/ui/lint/crate_level_only_lint.stderr new file mode 100644 index 00000000000..8fb06df2a48 --- /dev/null +++ b/src/test/ui/lint/crate_level_only_lint.stderr @@ -0,0 +1,62 @@ +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/crate_level_only_lint.rs:1:30 + | +LL | #![deny(uncommon_codepoints, unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:4:10 + | +LL | #![allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:9:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: allow(uncommon_codepoints) is ignored unless specified at crate level + --> $DIR/crate_level_only_lint.rs:17:9 + | +LL | #[allow(uncommon_codepoints)] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/lint/lint-ctypes-73249-1.rs b/src/test/ui/lint/lint-ctypes-73249-1.rs new file mode 100644 index 00000000000..cf416c3fe8b --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-1.rs @@ -0,0 +1,21 @@ +// check-pass +#![deny(improper_ctypes)] + +pub trait Foo { + type Assoc: 'static; +} + +impl Foo for () { + type Assoc = u32; +} + +extern "C" { + pub fn lint_me(x: Bar<()>); +} + +#[repr(transparent)] +pub struct Bar<T: Foo> { + value: &'static <T as Foo>::Assoc, +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73249-2.rs b/src/test/ui/lint/lint-ctypes-73249-2.rs new file mode 100644 index 00000000000..86cc5e2c31e --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-2.rs @@ -0,0 +1,29 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for () { } + +type Qux = impl Baz; + +fn assign() -> Qux {} + +pub trait Foo { + type Assoc: 'static; +} + +impl Foo for () { + type Assoc = Qux; +} + +#[repr(transparent)] +pub struct A<T: Foo> { + x: &'static <T as Foo>::Assoc, +} + +extern "C" { + pub fn lint_me() -> A<()>; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73249-2.stderr b/src/test/ui/lint/lint-ctypes-73249-2.stderr new file mode 100644 index 00000000000..36dbe3217d7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-2.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73249-2.rs:26:25 + | +LL | pub fn lint_me() -> A<()>; + | ^^^^^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73249-2.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73249-3.rs b/src/test/ui/lint/lint-ctypes-73249-3.rs new file mode 100644 index 00000000000..25c4e7c92a8 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-3.rs @@ -0,0 +1,21 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for u32 { } + +type Qux = impl Baz; + +fn assign() -> Qux { 3 } + +#[repr(C)] +pub struct A { + x: Qux, +} + +extern "C" { + pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73249-3.stderr b/src/test/ui/lint/lint-ctypes-73249-3.stderr new file mode 100644 index 00000000000..7d133287bd7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-3.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73249-3.rs:18:25 + | +LL | pub fn lint_me() -> A; + | ^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73249-3.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73249-4.rs b/src/test/ui/lint/lint-ctypes-73249-4.rs new file mode 100644 index 00000000000..6c72bd691b1 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-4.rs @@ -0,0 +1,24 @@ +// check-pass +#![deny(improper_ctypes)] + +use std::marker::PhantomData; + +trait Foo { + type Assoc; +} + +impl Foo for () { + type Assoc = PhantomData<()>; +} + +#[repr(transparent)] +struct Wow<T> where T: Foo<Assoc = PhantomData<T>> { + x: <T as Foo>::Assoc, + v: u32, +} + +extern "C" { + fn test(v: Wow<()>); +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73249-5.rs b/src/test/ui/lint/lint-ctypes-73249-5.rs new file mode 100644 index 00000000000..61e46983ede --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-5.rs @@ -0,0 +1,21 @@ +#![feature(type_alias_impl_trait)] +#![deny(improper_ctypes)] + +pub trait Baz { } + +impl Baz for u32 { } + +type Qux = impl Baz; + +fn assign() -> Qux { 3 } + +#[repr(transparent)] +pub struct A { + x: Qux, +} + +extern "C" { + pub fn lint_me() -> A; //~ ERROR: uses type `impl Baz` +} + +fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-73249-5.stderr b/src/test/ui/lint/lint-ctypes-73249-5.stderr new file mode 100644 index 00000000000..d2780cb60e7 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249-5.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `impl Baz`, which is not FFI-safe + --> $DIR/lint-ctypes-73249-5.rs:18:25 + | +LL | pub fn lint_me() -> A; + | ^ not FFI-safe + | +note: the lint level is defined here + --> $DIR/lint-ctypes-73249-5.rs:2:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-ctypes-73249.rs b/src/test/ui/lint/lint-ctypes-73249.rs new file mode 100644 index 00000000000..5b48fa9b737 --- /dev/null +++ b/src/test/ui/lint/lint-ctypes-73249.rs @@ -0,0 +1,21 @@ +// check-pass +#![deny(improper_ctypes)] + +pub trait Foo { + type Assoc; +} + +impl Foo for () { + type Assoc = u32; +} + +extern "C" { + pub fn lint_me(x: Bar<()>); +} + +#[repr(transparent)] +pub struct Bar<T: Foo> { + value: <T as Foo>::Assoc, +} + +fn main() {} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index f94dfd100a6..95936de218b 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -24,41 +24,31 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:29:13 | LL | let _ = v as &u8; - | ^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 | LL | let _ = v as E; - | ^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `fn()` --> $DIR/cast-rfc0401.rs:31:13 | LL | let _ = v as fn(); - | ^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `*const u8` as `(u32,)` --> $DIR/cast-rfc0401.rs:32:13 | LL | let _ = v as (u32,); - | ^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:33:13 | LL | let _ = Some(&v) as *const u8; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0606]: casting `*const u8` as `f32` is invalid --> $DIR/cast-rfc0401.rs:35:13 @@ -102,7 +92,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:41:13 | LL | let _ = 0x61u32 as char; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ invalid cast error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13 diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 69a9d03e474..d39b0a32077 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -17,12 +17,11 @@ error[E0605]: non-primitive cast: `{integer}` as `()` --> $DIR/issue-26480.rs:22:19 | LL | ($x:expr) => ($x as ()) - | ^^^^^^^^ + | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object ... LL | cast!(2); | --------- in this macro invocation | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/nonscalar-cast.fixed b/src/test/ui/nonscalar-cast.fixed new file mode 100644 index 00000000000..0a4b98469b2 --- /dev/null +++ b/src/test/ui/nonscalar-cast.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#[derive(Debug)] +struct Foo { + x: isize +} + +impl From<Foo> for isize { + fn from(val: Foo) -> isize { + val.x + } +} + +fn main() { + println!("{}", isize::from(Foo { x: 1 })); //~ non-primitive cast: `Foo` as `isize` [E0605] +} diff --git a/src/test/ui/nonscalar-cast.rs b/src/test/ui/nonscalar-cast.rs index 7e6f1fd038f..59fcf09666b 100644 --- a/src/test/ui/nonscalar-cast.rs +++ b/src/test/ui/nonscalar-cast.rs @@ -1,8 +1,16 @@ +// run-rustfix + #[derive(Debug)] struct Foo { x: isize } +impl From<Foo> for isize { + fn from(val: Foo) -> isize { + val.x + } +} + fn main() { println!("{}", Foo { x: 1 } as isize); //~ non-primitive cast: `Foo` as `isize` [E0605] } diff --git a/src/test/ui/nonscalar-cast.stderr b/src/test/ui/nonscalar-cast.stderr index 9338688b037..2a703712187 100644 --- a/src/test/ui/nonscalar-cast.stderr +++ b/src/test/ui/nonscalar-cast.stderr @@ -1,10 +1,10 @@ error[E0605]: non-primitive cast: `Foo` as `isize` - --> $DIR/nonscalar-cast.rs:7:20 + --> $DIR/nonscalar-cast.rs:15:20 | LL | println!("{}", Foo { x: 1 } as isize); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(Foo { x: 1 })` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/numeric/numeric-cast-no-fix.rs b/src/test/ui/numeric/numeric-cast-no-fix.rs new file mode 100644 index 00000000000..63e5f098a25 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-no-fix.rs @@ -0,0 +1,87 @@ +#[allow(unused_must_use)] +fn main() { + let x_usize: usize = 1; + let x_u128: u128 = 2; + let x_u64: u64 = 3; + let x_u32: u32 = 4; + let x_u16: u16 = 5; + let x_u8: u8 = 6; + + x_usize > -1_isize; + //~^ ERROR mismatched types + x_u128 > -1_isize; + //~^ ERROR mismatched types + x_u64 > -1_isize; + //~^ ERROR mismatched types + x_u32 > -1_isize; + //~^ ERROR mismatched types + x_u16 > -1_isize; + //~^ ERROR mismatched types + x_u8 > -1_isize; + //~^ ERROR mismatched types + + x_usize > -1_i128; + //~^ ERROR mismatched types + x_u128 > -1_i128; + //~^ ERROR mismatched types + x_u64 > -1_i128; + //~^ ERROR mismatched types + x_u32 > -1_i128; + //~^ ERROR mismatched types + x_u16 > -1_i128; + //~^ ERROR mismatched types + x_u8 > -1_i128; + //~^ ERROR mismatched types + + x_usize > -1_i64; + //~^ ERROR mismatched types + x_u128 > -1_i64; + //~^ ERROR mismatched types + x_u64 > -1_i64; + //~^ ERROR mismatched types + x_u32 > -1_i64; + //~^ ERROR mismatched types + x_u16 > -1_i64; + //~^ ERROR mismatched types + x_u8 > -1_i64; + //~^ ERROR mismatched types + + x_usize > -1_i32; + //~^ ERROR mismatched types + x_u128 > -1_i32; + //~^ ERROR mismatched types + x_u64 > -1_i32; + //~^ ERROR mismatched types + x_u32 > -1_i32; + //~^ ERROR mismatched types + x_u16 > -1_i32; + //~^ ERROR mismatched types + x_u8 > -1_i32; + //~^ ERROR mismatched types + + x_usize > -1_i16; + //~^ ERROR mismatched types + x_u128 > -1_i16; + //~^ ERROR mismatched types + x_u64 > -1_i16; + //~^ ERROR mismatched types + x_u32 > -1_i16; + //~^ ERROR mismatched types + x_u16 > -1_i16; + //~^ ERROR mismatched types + x_u8 > -1_i16; + //~^ ERROR mismatched types + + x_usize > -1_i8; + //~^ ERROR mismatched types + x_u128 > -1_i8; + //~^ ERROR mismatched types + x_u64 > -1_i8; + //~^ ERROR mismatched types + x_u32 > -1_i8; + //~^ ERROR mismatched types + x_u16 > -1_i8; + //~^ ERROR mismatched types + x_u8 > -1_i8; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/numeric/numeric-cast-no-fix.stderr b/src/test/ui/numeric/numeric-cast-no-fix.stderr new file mode 100644 index 00000000000..4852e7047b4 --- /dev/null +++ b/src/test/ui/numeric/numeric-cast-no-fix.stderr @@ -0,0 +1,324 @@ +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:10:15 + | +LL | x_usize > -1_isize; + | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-1_isize` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:12:14 + | +LL | x_u128 > -1_isize; + | ^^^^^^^^ expected `u128`, found `isize` + | + = note: `-1_isize` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:14:13 + | +LL | x_u64 > -1_isize; + | ^^^^^^^^ expected `u64`, found `isize` + | + = note: `-1_isize` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:16:13 + | +LL | x_u32 > -1_isize; + | ^^^^^^^^ expected `u32`, found `isize` + | + = note: `-1_isize` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:18:13 + | +LL | x_u16 > -1_isize; + | ^^^^^^^^ expected `u16`, found `isize` + | + = note: `-1_isize` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:20:12 + | +LL | x_u8 > -1_isize; + | ^^^^^^^^ expected `u8`, found `isize` + | +help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize` + | +LL | isize::from(x_u8) > -1_isize; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:23:15 + | +LL | x_usize > -1_i128; + | ^^^^^^^ expected `usize`, found `i128` + | + = note: `-1_i128` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:25:14 + | +LL | x_u128 > -1_i128; + | ^^^^^^^ expected `u128`, found `i128` + | + = note: `-1_i128` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:27:13 + | +LL | x_u64 > -1_i128; + | ^^^^^^^ expected `u64`, found `i128` + | +help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u64) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:29:13 + | +LL | x_u32 > -1_i128; + | ^^^^^^^ expected `u32`, found `i128` + | +help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u32) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:31:13 + | +LL | x_u16 > -1_i128; + | ^^^^^^^ expected `u16`, found `i128` + | +help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u16) > -1_i128; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:33:12 + | +LL | x_u8 > -1_i128; + | ^^^^^^^ expected `u8`, found `i128` + | +help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128` + | +LL | i128::from(x_u8) > -1_i128; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:36:15 + | +LL | x_usize > -1_i64; + | ^^^^^^ expected `usize`, found `i64` + | + = note: `-1_i64` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:38:14 + | +LL | x_u128 > -1_i64; + | ^^^^^^ expected `u128`, found `i64` + | + = note: `-1_i64` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:40:13 + | +LL | x_u64 > -1_i64; + | ^^^^^^ expected `u64`, found `i64` + | + = note: `-1_i64` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:42:13 + | +LL | x_u32 > -1_i64; + | ^^^^^^ expected `u32`, found `i64` + | +help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u32) > -1_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:44:13 + | +LL | x_u16 > -1_i64; + | ^^^^^^ expected `u16`, found `i64` + | +help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u16) > -1_i64; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:46:12 + | +LL | x_u8 > -1_i64; + | ^^^^^^ expected `u8`, found `i64` + | +help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64` + | +LL | i64::from(x_u8) > -1_i64; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:49:15 + | +LL | x_usize > -1_i32; + | ^^^^^^ expected `usize`, found `i32` + | + = note: `-1_i32` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:51:14 + | +LL | x_u128 > -1_i32; + | ^^^^^^ expected `u128`, found `i32` + | + = note: `-1_i32` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:53:13 + | +LL | x_u64 > -1_i32; + | ^^^^^^ expected `u64`, found `i32` + | + = note: `-1_i32` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:55:13 + | +LL | x_u32 > -1_i32; + | ^^^^^^ expected `u32`, found `i32` + | + = note: `-1_i32` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:57:13 + | +LL | x_u16 > -1_i32; + | ^^^^^^ expected `u16`, found `i32` + | +help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32` + | +LL | i32::from(x_u16) > -1_i32; + | ^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:59:12 + | +LL | x_u8 > -1_i32; + | ^^^^^^ expected `u8`, found `i32` + | +help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32` + | +LL | i32::from(x_u8) > -1_i32; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:62:15 + | +LL | x_usize > -1_i16; + | ^^^^^^ expected `usize`, found `i16` + | + = note: `-1_i16` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:64:14 + | +LL | x_u128 > -1_i16; + | ^^^^^^ expected `u128`, found `i16` + | + = note: `-1_i16` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:66:13 + | +LL | x_u64 > -1_i16; + | ^^^^^^ expected `u64`, found `i16` + | + = note: `-1_i16` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:68:13 + | +LL | x_u32 > -1_i16; + | ^^^^^^ expected `u32`, found `i16` + | + = note: `-1_i16` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:70:13 + | +LL | x_u16 > -1_i16; + | ^^^^^^ expected `u16`, found `i16` + | + = note: `-1_i16` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:72:12 + | +LL | x_u8 > -1_i16; + | ^^^^^^ expected `u8`, found `i16` + | +help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16` + | +LL | i16::from(x_u8) > -1_i16; + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:75:15 + | +LL | x_usize > -1_i8; + | ^^^^^ expected `usize`, found `i8` + | + = note: `-1_i8` cannot fit into type `usize` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:77:14 + | +LL | x_u128 > -1_i8; + | ^^^^^ expected `u128`, found `i8` + | + = note: `-1_i8` cannot fit into type `u128` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:79:13 + | +LL | x_u64 > -1_i8; + | ^^^^^ expected `u64`, found `i8` + | + = note: `-1_i8` cannot fit into type `u64` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:81:13 + | +LL | x_u32 > -1_i8; + | ^^^^^ expected `u32`, found `i8` + | + = note: `-1_i8` cannot fit into type `u32` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:83:13 + | +LL | x_u16 > -1_i8; + | ^^^^^ expected `u16`, found `i8` + | + = note: `-1_i8` cannot fit into type `u16` + +error[E0308]: mismatched types + --> $DIR/numeric-cast-no-fix.rs:85:12 + | +LL | x_u8 > -1_i8; + | ^^^^^ expected `u8`, found `i8` + | + = note: `-1_i8` cannot fit into type `u8` + +error: aborting due to 36 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 70a9bf22b8d..1b1e0d96107 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -1,13 +1,13 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> { - | --------------- data with this lifetime... + | --------------- this data with an anonymous lifetime `'_`... ... LL | ss.r - | ^^^^ ...is captured and required to be `'static` here + | ^^^^ ...is captured and required to live as long as `'static` here | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #2 defined on the function body at 14:1 +help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound | LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait + '_> { | ^^^^ @@ -23,4 +23,5 @@ LL | ss.r = b; error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0621`. +Some errors have detailed explanations: E0621, E0759. +For more information about an error, try `rustc --explain E0621`. diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr index ad50b415869..9f4ac0fea36 100644 --- a/src/test/ui/order-dependent-cast-inference.stderr +++ b/src/test/ui/order-dependent-cast-inference.stderr @@ -1,10 +1,8 @@ error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/order-dependent-cast-inference.rs:5:17 + --> $DIR/order-dependent-cast-inference.rs:5:22 | LL | let mut y = 0 as *const _; - | ^^^^^-------- - | | - | help: consider giving more type information + | ^^^^^^^^ needs more type information | = note: the type information given here is insufficient to check whether the pointer cast is valid diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.rs b/src/test/ui/overlap-doesnt-conflict-with-specialization.rs index dd09d68367e..1e413120a37 100644 --- a/src/test/ui/overlap-doesnt-conflict-with-specialization.rs +++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.rs @@ -1,7 +1,7 @@ // run-pass #![feature(marker_trait_attr)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete #[marker] trait MyMarker {} diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr new file mode 100644 index 00000000000..16df31ba2a8 --- /dev/null +++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/parser/assoc-static-semantic-fail.rs b/src/test/ui/parser/assoc-static-semantic-fail.rs index 215a2921315..a8759d2090d 100644 --- a/src/test/ui/parser/assoc-static-semantic-fail.rs +++ b/src/test/ui/parser/assoc-static-semantic-fail.rs @@ -1,6 +1,7 @@ // Semantically, we do not allow e.g., `static X: u8 = 0;` as an associated item. #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete fn main() {} diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr index 612297c9cd8..bc3054c3e30 100644 --- a/src/test/ui/parser/assoc-static-semantic-fail.stderr +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -1,17 +1,17 @@ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:9:5 + --> $DIR/assoc-static-semantic-fail.rs:10:5 | LL | static IA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:11:5 + --> $DIR/assoc-static-semantic-fail.rs:12:5 | LL | static IB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:14:5 + --> $DIR/assoc-static-semantic-fail.rs:15:5 | LL | default static IC: u8 = 0; | ^^^^^^^ `default` because of this @@ -19,13 +19,13 @@ LL | default static IC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:14:5 + --> $DIR/assoc-static-semantic-fail.rs:15:5 | LL | default static IC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:17:16 + --> $DIR/assoc-static-semantic-fail.rs:18:16 | LL | pub(crate) default static ID: u8; | ^^^^^^^ `default` because of this @@ -33,25 +33,25 @@ LL | pub(crate) default static ID: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:17:5 + --> $DIR/assoc-static-semantic-fail.rs:18:5 | LL | pub(crate) default static ID: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:24:5 + --> $DIR/assoc-static-semantic-fail.rs:25:5 | LL | static TA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:26:5 + --> $DIR/assoc-static-semantic-fail.rs:27:5 | LL | static TB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:28:5 + --> $DIR/assoc-static-semantic-fail.rs:29:5 | LL | default static TC: u8 = 0; | ^^^^^^^ `default` because of this @@ -59,13 +59,13 @@ LL | default static TC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:28:5 + --> $DIR/assoc-static-semantic-fail.rs:29:5 | LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:31:16 + --> $DIR/assoc-static-semantic-fail.rs:32:16 | LL | pub(crate) default static TD: u8; | ^^^^^^^ `default` because of this @@ -73,25 +73,25 @@ LL | pub(crate) default static TD: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:31:5 + --> $DIR/assoc-static-semantic-fail.rs:32:5 | LL | pub(crate) default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:38:5 + --> $DIR/assoc-static-semantic-fail.rs:39:5 | LL | static TA: u8 = 0; | ^^^^^^^^^^^^^^^^^^ error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:40:5 + --> $DIR/assoc-static-semantic-fail.rs:41:5 | LL | static TB: u8; | ^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:43:5 + --> $DIR/assoc-static-semantic-fail.rs:44:5 | LL | default static TC: u8 = 0; | ^^^^^^^ `default` because of this @@ -99,13 +99,13 @@ LL | default static TC: u8 = 0; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:43:5 + --> $DIR/assoc-static-semantic-fail.rs:44:5 | LL | default static TC: u8 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a static item cannot be `default` - --> $DIR/assoc-static-semantic-fail.rs:46:9 + --> $DIR/assoc-static-semantic-fail.rs:47:9 | LL | pub default static TD: u8; | ^^^^^^^ `default` because of this @@ -113,13 +113,13 @@ LL | pub default static TD: u8; = note: only associated `fn`, `const`, and `type` items can be `default` error: associated `static` items are not allowed - --> $DIR/assoc-static-semantic-fail.rs:46:5 + --> $DIR/assoc-static-semantic-fail.rs:47:5 | LL | pub default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:11:5 + --> $DIR/assoc-static-semantic-fail.rs:12:5 | LL | static IB: u8; | ^^^^^^^^^^^^^- @@ -127,7 +127,7 @@ LL | static IB: u8; | help: provide a definition for the constant: `= <expr>;` error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:17:5 + --> $DIR/assoc-static-semantic-fail.rs:18:5 | LL | pub(crate) default static ID: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -135,13 +135,13 @@ LL | pub(crate) default static ID: u8; | help: provide a definition for the constant: `= <expr>;` error[E0449]: unnecessary visibility qualifier - --> $DIR/assoc-static-semantic-fail.rs:31:5 + --> $DIR/assoc-static-semantic-fail.rs:32:5 | LL | pub(crate) default static TD: u8; | ^^^^^^^^^^ error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:40:5 + --> $DIR/assoc-static-semantic-fail.rs:41:5 | LL | static TB: u8; | ^^^^^^^^^^^^^- @@ -149,7 +149,7 @@ LL | static TB: u8; | help: provide a definition for the constant: `= <expr>;` error: associated constant in `impl` without body - --> $DIR/assoc-static-semantic-fail.rs:46:5 + --> $DIR/assoc-static-semantic-fail.rs:47:5 | LL | pub default static TD: u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -157,11 +157,20 @@ LL | pub default static TD: u8; | help: provide a definition for the constant: `= <expr>;` error[E0449]: unnecessary visibility qualifier - --> $DIR/assoc-static-semantic-fail.rs:46:5 + --> $DIR/assoc-static-semantic-fail.rs:47:5 | LL | pub default static TD: u8; | ^^^ `pub` not permitted here because it's implied -error: aborting due to 24 previous errors +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-static-semantic-fail.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +error: aborting due to 24 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0449`. diff --git a/src/test/ui/parser/byte-literals.rs b/src/test/ui/parser/byte-literals.rs index dadf3971220..9683a83e720 100644 --- a/src/test/ui/parser/byte-literals.rs +++ b/src/test/ui/parser/byte-literals.rs @@ -8,5 +8,5 @@ pub fn main() { b' '; //~ ERROR byte constant must be escaped b'''; //~ ERROR byte constant must be escaped b'é'; //~ ERROR byte constant must be ASCII - b'a //~ ERROR unterminated byte constant + b'a //~ ERROR unterminated byte constant [E0763] } diff --git a/src/test/ui/parser/byte-literals.stderr b/src/test/ui/parser/byte-literals.stderr index 53d50af88d3..7bbdc07cd83 100644 --- a/src/test/ui/parser/byte-literals.stderr +++ b/src/test/ui/parser/byte-literals.stderr @@ -34,7 +34,7 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte LL | b'é'; | ^ -error: unterminated byte constant +error[E0763]: unterminated byte constant --> $DIR/byte-literals.rs:11:6 | LL | b'a @@ -42,3 +42,4 @@ LL | b'a error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0763`. diff --git a/src/test/ui/parser/default.rs b/src/test/ui/parser/default.rs index 64ba4b55311..52338c1f13a 100644 --- a/src/test/ui/parser/default.rs +++ b/src/test/ui/parser/default.rs @@ -1,6 +1,7 @@ // Test successful and unsuccessful parsing of the `default` contextual keyword #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete trait Foo { fn foo<T: Default>() -> T; diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index 15c49e8b627..dea35666f37 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -1,5 +1,5 @@ error: `default` is not followed by an item - --> $DIR/default.rs:22:5 + --> $DIR/default.rs:23:5 | LL | default pub fn foo<T: Default>() -> T { T::default() } | ^^^^^^^ the `default` qualifier @@ -7,7 +7,7 @@ LL | default pub fn foo<T: Default>() -> T { T::default() } = note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` error: non-item in item list - --> $DIR/default.rs:22:13 + --> $DIR/default.rs:23:13 | LL | impl Foo for u32 { | - item list starts here @@ -18,13 +18,22 @@ LL | } | - item list ends here error[E0449]: unnecessary visibility qualifier - --> $DIR/default.rs:16:5 + --> $DIR/default.rs:17:5 | LL | pub default fn foo<T: Default>() -> T { | ^^^ `pub` not permitted here because it's implied +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/default.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/default.rs:21:1 + --> $DIR/default.rs:22:1 | LL | fn foo<T: Default>() -> T; | -------------------------- `foo` from trait @@ -32,7 +41,7 @@ LL | fn foo<T: Default>() -> T; LL | impl Foo for u32 { | ^^^^^^^^^^^^^^^^ missing `foo` in implementation -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0046, E0449. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/parser/let-binop.rs b/src/test/ui/parser/let-binop.rs new file mode 100644 index 00000000000..7f58f5df2d4 --- /dev/null +++ b/src/test/ui/parser/let-binop.rs @@ -0,0 +1,8 @@ +fn main() { + let a: i8 *= 1; //~ ERROR can't reassign to an uninitialized variable + let _ = a; + let b += 1; //~ ERROR can't reassign to an uninitialized variable + let _ = b; + let c *= 1; //~ ERROR can't reassign to an uninitialized variable + let _ = c; +} diff --git a/src/test/ui/parser/let-binop.stderr b/src/test/ui/parser/let-binop.stderr new file mode 100644 index 00000000000..71431499ac7 --- /dev/null +++ b/src/test/ui/parser/let-binop.stderr @@ -0,0 +1,20 @@ +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:2:15 + | +LL | let a: i8 *= 1; + | ^^ help: initialize the variable + +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:4:11 + | +LL | let b += 1; + | ^^ help: initialize the variable + +error: can't reassign to an uninitialized variable + --> $DIR/let-binop.rs:6:11 + | +LL | let c *= 1; + | ^^ help: initialize the variable + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs index 09f967f161e..34aee7f6935 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete fn main() {} diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index 6bb946d5b64..e8ff93f6323 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -46,5 +46,14 @@ LL | default fn f2() {} | | | `default` because of this -error: aborting due to 6 previous errors +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/trait-item-with-defaultness-fail-semantic.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr index bf02ba8eb91..7e8f78067e0 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr @@ -1,21 +1,21 @@ -error[E0621]: explicit lifetime required in the type of `v` +error: lifetime may not live long enough --> $DIR/region-object-lifetime-in-coercion.rs:8:12 | LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | - let's call the lifetime of this reference `'1` LL | let x: Box<dyn Foo + 'static> = Box::new(v); - | ^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required + | ^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'1` must outlive `'static` -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:14:5 +error: lifetime may not live long enough + --> $DIR/region-object-lifetime-in-coercion.rs:13:5 | LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | - let's call the lifetime of this reference `'1` LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/region-object-lifetime-in-coercion.rs:20:5 + --> $DIR/region-object-lifetime-in-coercion.rs:19:5 | LL | fn c(v: &[u8]) -> Box<dyn Foo> { | - let's call the lifetime of this reference `'1` @@ -24,7 +24,7 @@ LL | Box::new(v) | ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/region-object-lifetime-in-coercion.rs:24:5 + --> $DIR/region-object-lifetime-in-coercion.rs:23:5 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { | -- -- lifetime `'b` defined here @@ -37,4 +37,3 @@ LL | Box::new(v) error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.rs b/src/test/ui/regions/region-object-lifetime-in-coercion.rs index d56eaf77b66..5d199149c39 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.rs +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.rs @@ -5,13 +5,12 @@ trait Foo {} impl<'a> Foo for &'a [u8] {} fn a(v: &[u8]) -> Box<dyn Foo + 'static> { - let x: Box<dyn Foo + 'static> = Box::new(v); - //~^ ERROR explicit lifetime required in the type of `v` [E0621] + let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime x } fn b(v: &[u8]) -> Box<dyn Foo + 'static> { - Box::new(v) //~ ERROR explicit lifetime required in the type of `v` [E0621] + Box::new(v) //~ ERROR cannot infer an appropriate lifetime } fn c(v: &[u8]) -> Box<dyn Foo> { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 1462af44cb1..7f5a3a47976 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -1,61 +1,76 @@ -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:8:37 +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:8:46 | LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | ----- this data with an anonymous lifetime `'_`... LL | let x: Box<dyn Foo + 'static> = Box::new(v); - | ^^^^^^^^^^^ lifetime `'static` required + | ^ ...is captured here, requiring it to live as long as `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn a(v: &[u8]) -> Box<dyn Foo + '_> { + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> { + | ^^^^^^^^^^^^^ -error[E0621]: explicit lifetime required in the type of `v` - --> $DIR/region-object-lifetime-in-coercion.rs:14:5 +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:13:14 | LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> { - | ----- help: add explicit lifetime `'static` to the type of `v`: `&'static [u8]` + | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^^^^^^^^^^^ lifetime `'static` required + | ^ ...is captured here, requiring it to live as long as `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` + | +LL | fn b(v: &[u8]) -> Box<dyn Foo + '_> { + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> { + | ^^^^^^^^^^^^^ -error: cannot infer an appropriate lifetime - --> $DIR/region-object-lifetime-in-coercion.rs:20:14 +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/region-object-lifetime-in-coercion.rs:19:14 | LL | fn c(v: &[u8]) -> Box<dyn Foo> { - | ----- data with this lifetime... + | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ---------^- - | | | - | | ...and is captured here - | ...is required to be `'static` by this... + | ^ ...is captured here, requiring it to live as long as `'static` | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 17:1 +help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound | LL | fn c(v: &[u8]) -> Box<dyn Foo + '_> { | ^^^^ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/region-object-lifetime-in-coercion.rs:24:14 + --> $DIR/region-object-lifetime-in-coercion.rs:23:14 | LL | Box::new(v) | ^ | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 23:6... - --> $DIR/region-object-lifetime-in-coercion.rs:23:6 +note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:6... + --> $DIR/region-object-lifetime-in-coercion.rs:22:6 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:24:14 + --> $DIR/region-object-lifetime-in-coercion.rs:23:14 | LL | Box::new(v) | ^ = note: expected `&[u8]` found `&'a [u8]` -note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 23:9... - --> $DIR/region-object-lifetime-in-coercion.rs:23:9 +note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 22:9... + --> $DIR/region-object-lifetime-in-coercion.rs:22:9 | LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> { | ^^ note: ...so that the expression is assignable - --> $DIR/region-object-lifetime-in-coercion.rs:24:5 + --> $DIR/region-object-lifetime-in-coercion.rs:23:5 | LL | Box::new(v) | ^^^^^^^^^^^ @@ -64,5 +79,5 @@ LL | Box::new(v) error: aborting due to 4 previous errors -Some errors have detailed explanations: E0495, E0621. +Some errors have detailed explanations: E0495, E0759. For more information about an error, try `rustc --explain E0495`. diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 147f7f35418..114e4052aae 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,28 +1,20 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-2.rs:10:11 | +LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { + | ------------------ this data with lifetime `'a`... LL | box B(&*v) as Box<dyn X> - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6... - --> $DIR/regions-close-object-into-object-2.rs:9:6 + | ^^^ ...is captured here, requiring it to live as long as `'static` | -LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> { - | ^^ -note: ...so that the type `(dyn A<T> + 'a)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-2.rs:10:11 +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | -LL | box B(&*v) as Box<dyn X> - | ^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/regions-close-object-into-object-2.rs:10:5 +LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'a> { + | ^^ +help: alternatively, add an explicit `'static` bound to this reference | -LL | box B(&*v) as Box<dyn X> - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box<dyn X>` +LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A<T> + 'static)>) -> Box<dyn X + 'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 6e7d6152cd0..850d8194079 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,28 +1,20 @@ -error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements +error[E0759]: cannot infer an appropriate lifetime --> $DIR/regions-close-object-into-object-4.rs:10:11 | +LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { + | ---------------- this data with lifetime `'a`... LL | box B(&*v) as Box<dyn X> - | ^^^ - | -note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 9:6... - --> $DIR/regions-close-object-into-object-4.rs:9:6 + | ^^^ ...is captured here, requiring it to live as long as `'static` | -LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> { - | ^^ -note: ...so that the type `(dyn A<U> + 'a)` is not borrowed for too long - --> $DIR/regions-close-object-into-object-4.rs:10:11 +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | -LL | box B(&*v) as Box<dyn X> - | ^^^ - = note: but, the lifetime must be valid for the static lifetime... -note: ...so that the expression is assignable - --> $DIR/regions-close-object-into-object-4.rs:10:5 +LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'a> { + | ^^ +help: alternatively, add an explicit `'static` bound to this reference | -LL | box B(&*v) as Box<dyn X> - | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn X + 'static)>` - found `std::boxed::Box<dyn X>` +LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A<U> + 'static)>) -> Box<dyn X + 'static> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0495`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/regions/regions-proc-bound-capture.nll.stderr b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr new file mode 100644 index 00000000000..75890b85815 --- /dev/null +++ b/src/test/ui/regions/regions-proc-bound-capture.nll.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/regions-proc-bound-capture.rs:9:5 + | +LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { + | - let's call the lifetime of this reference `'1` +LL | // This is illegal, because the region bound on `proc` is 'static. +LL | Box::new(move || { *x }) + | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/regions/regions-proc-bound-capture.rs b/src/test/ui/regions/regions-proc-bound-capture.rs index 0c903b73849..8617c0e9da8 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.rs +++ b/src/test/ui/regions/regions-proc-bound-capture.rs @@ -4,9 +4,9 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box<dyn FnMut()->(isize) + 'a> { Box::new(move|| { *x }) } -fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> { +fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR explicit lifetime required in the type of `x` [E0621] + Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index c53af34456e..67eee3bb6e2 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -1,12 +1,21 @@ -error[E0621]: explicit lifetime required in the type of `x` - --> $DIR/regions-proc-bound-capture.rs:9:5 +error[E0759]: cannot infer an appropriate lifetime + --> $DIR/regions-proc-bound-capture.rs:9:14 | -LL | fn static_proc(x: &isize) -> Box<dyn FnMut()->(isize) + 'static> { - | ------ help: add explicit lifetime `'static` to the type of `x`: `&'static isize` +LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> { + | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. -LL | Box::new(move|| { *x }) - | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'static` required +LL | Box::new(move || { *x }) + | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` + | +help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` + | +LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + '_> { + | ^^ +help: alternatively, add an explicit `'static` bound to this reference + | +LL | fn static_proc(x: &'static isize) -> Box<dyn FnMut() -> (isize) + 'static> { + | ^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0621`. +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 6a081e23d9d..2eab3ebc768 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -39,12 +39,16 @@ error[E0308]: mismatched types | LL | let f = [0; -4_isize]; | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-4_isize` cannot fit into type `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:22:23 | LL | let f = [0_usize; -1_isize]; | ^^^^^^^^ expected `usize`, found `isize` + | + = note: `-1_isize` cannot fit into type `usize` error[E0308]: mismatched types --> $DIR/repeat_count.rs:25:17 diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs new file mode 100644 index 00000000000..3fb1cf9f557 --- /dev/null +++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.rs @@ -0,0 +1,6 @@ +#![feature(non_ascii_idents)] + +extern crate ьаг; //~ ERROR cannot load a crate with a non-ascii name `ьаг` +//~| ERROR can't find crate for `ьаг` + +fn main() {} diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr new file mode 100644 index 00000000000..1e424237fd2 --- /dev/null +++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-1.stderr @@ -0,0 +1,15 @@ +error: cannot load a crate with a non-ascii name `ьаг` + --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1 + | +LL | extern crate ьаг; + | ^^^^^^^^^^^^^^^^^ + +error[E0463]: can't find crate for `ьаг` + --> $DIR/crate_name_nonascii_forbidden-1.rs:3:1 + | +LL | extern crate ьаг; + | ^^^^^^^^^^^^^^^^^ can't find crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs new file mode 100644 index 00000000000..e1acdbff061 --- /dev/null +++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.rs @@ -0,0 +1,9 @@ +// compile-flags:--extern му_сгате +// edition:2018 +#![feature(non_ascii_idents)] + +use му_сгате::baz; //~ ERROR cannot load a crate with a non-ascii name `му_сгате` + //~| can't find crate for `му_сгате` + + +fn main() {} diff --git a/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr new file mode 100644 index 00000000000..c06405ebb37 --- /dev/null +++ b/src/test/ui/rfc-2457/crate_name_nonascii_forbidden-2.stderr @@ -0,0 +1,15 @@ +error: cannot load a crate with a non-ascii name `му_сгате` + --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5 + | +LL | use му_сгате::baz; + | ^^^^^^^^ + +error[E0463]: can't find crate for `му_сгате` + --> $DIR/crate_name_nonascii_forbidden-2.rs:5:5 + | +LL | use му_сгате::baz; + | ^^^^^^^^ can't find crate + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/sanitize/address.rs b/src/test/ui/sanitize/address.rs index f8650cd86d5..cee73b0425a 100644 --- a/src/test/ui/sanitize/address.rs +++ b/src/test/ui/sanitize/address.rs @@ -1,5 +1,5 @@ // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-address // // compile-flags: -Z sanitizer=address -O -g // diff --git a/src/test/ui/sanitize/badfree.rs b/src/test/ui/sanitize/badfree.rs index 1ca082c8b47..095a6f4697b 100644 --- a/src/test/ui/sanitize/badfree.rs +++ b/src/test/ui/sanitize/badfree.rs @@ -1,5 +1,5 @@ // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-address // // compile-flags: -Z sanitizer=address -O // diff --git a/src/test/ui/sanitize/cfg.rs b/src/test/ui/sanitize/cfg.rs index 9c198543a86..79dfe58f04d 100644 --- a/src/test/ui/sanitize/cfg.rs +++ b/src/test/ui/sanitize/cfg.rs @@ -2,8 +2,10 @@ // the `#[cfg(sanitize = "option")]` attribute is configured. // needs-sanitizer-support -// only-linux -// only-x86_64 +// needs-sanitizer-address +// needs-sanitizer-leak +// needs-sanitizer-memory +// needs-sanitizer-thread // check-pass // revisions: address leak memory thread //[address]compile-flags: -Zsanitizer=address --cfg address diff --git a/src/test/ui/sanitize/incompatible.rs b/src/test/ui/sanitize/incompatible.rs new file mode 100644 index 00000000000..4947f3b3d8b --- /dev/null +++ b/src/test/ui/sanitize/incompatible.rs @@ -0,0 +1,6 @@ +// compile-flags: -Z sanitizer=address -Z sanitizer=memory --target x86_64-unknown-linux-gnu +// error-pattern: error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory` + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/src/test/ui/sanitize/incompatible.stderr b/src/test/ui/sanitize/incompatible.stderr new file mode 100644 index 00000000000..f86db41bac7 --- /dev/null +++ b/src/test/ui/sanitize/incompatible.stderr @@ -0,0 +1,4 @@ +error: `-Zsanitizer=address` is incompatible with `-Zsanitizer=memory` + +error: aborting due to previous error + diff --git a/src/test/ui/sanitize/issue-72154-lifetime-markers.rs b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs index 458f99143b6..b2e182238ce 100644 --- a/src/test/ui/sanitize/issue-72154-lifetime-markers.rs +++ b/src/test/ui/sanitize/issue-72154-lifetime-markers.rs @@ -4,7 +4,7 @@ // miscompilation which was subsequently detected by AddressSanitizer as UB. // // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-address // // compile-flags: -Copt-level=0 -Zsanitizer=address // run-pass diff --git a/src/test/ui/sanitize/leak.rs b/src/test/ui/sanitize/leak.rs index 5c2f2cb4e86..c9f10fe4f46 100644 --- a/src/test/ui/sanitize/leak.rs +++ b/src/test/ui/sanitize/leak.rs @@ -1,5 +1,5 @@ // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-leak // // compile-flags: -Z sanitizer=leak -O // diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs index 3e1cf4509a3..a26649a5800 100644 --- a/src/test/ui/sanitize/memory.rs +++ b/src/test/ui/sanitize/memory.rs @@ -1,6 +1,5 @@ // needs-sanitizer-support -// only-linux -// only-x86_64 +// needs-sanitizer-memory // // compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O // diff --git a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs index d0984bbe65f..64d6ccf3409 100644 --- a/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs +++ b/src/test/ui/sanitize/new-llvm-pass-manager-thin-lto.rs @@ -4,7 +4,7 @@ // // min-llvm-version 9.0 // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-address // // no-prefer-dynamic // revisions: opt0 opt1 diff --git a/src/test/ui/sanitize/thread.rs b/src/test/ui/sanitize/thread.rs index 26590be8b18..c70cf5accc0 100644 --- a/src/test/ui/sanitize/thread.rs +++ b/src/test/ui/sanitize/thread.rs @@ -11,7 +11,7 @@ // would occasionally fail, making test flaky. // // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-thread // // compile-flags: -Z sanitizer=thread -O // diff --git a/src/test/ui/sanitize/unsupported-target.rs b/src/test/ui/sanitize/unsupported-target.rs index 444333c3f01..6ccc9988cde 100644 --- a/src/test/ui/sanitize/unsupported-target.rs +++ b/src/test/ui/sanitize/unsupported-target.rs @@ -1,6 +1,5 @@ -// ignore-tidy-linelength // compile-flags: -Z sanitizer=leak --target i686-unknown-linux-gnu -// error-pattern: error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target +// error-pattern: error: `-Zsanitizer=leak` only works with targets: #![feature(no_core)] #![no_core] diff --git a/src/test/ui/sanitize/unsupported-target.stderr b/src/test/ui/sanitize/unsupported-target.stderr index 38be58dd4b3..f5961a11b1f 100644 --- a/src/test/ui/sanitize/unsupported-target.stderr +++ b/src/test/ui/sanitize/unsupported-target.stderr @@ -1,4 +1,4 @@ -error: LeakSanitizer only works with the `x86_64-unknown-linux-gnu` or `x86_64-apple-darwin` target +error: `-Zsanitizer=leak` only works with targets: aarch64-unknown-linux-gnu, x86_64-apple-darwin, x86_64-unknown-linux-gnu error: aborting due to previous error diff --git a/src/test/ui/sanitize/use-after-scope.rs b/src/test/ui/sanitize/use-after-scope.rs index 6a2067e157a..30be2ae6f09 100644 --- a/src/test/ui/sanitize/use-after-scope.rs +++ b/src/test/ui/sanitize/use-after-scope.rs @@ -1,5 +1,5 @@ // needs-sanitizer-support -// only-x86_64 +// needs-sanitizer-address // // compile-flags: -Zsanitizer=address // run-fail diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index 1aeabce5e8a..88bd990b1e8 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -1,11 +1,12 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ^^^^ ---------- ---------- ...and required to be `'static` by this + | ^^^^ ---------- ---------- ...and is required to live as long as `'static` here | | | - | | data with this lifetime... + | | this data with an anonymous lifetime `'_`... | ...is captured here... error: aborting due to previous error +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 04c475be787..2e10ab3d3f9 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -1,16 +1,21 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } - | ---------- ---------- ^^^^ ...and is captured here - | | | - | | ...is required to be `'static` by this... - | data with this lifetime... + | ---------- ^^^^ ...is captured here... + | | + | this data with an anonymous lifetime `'_`... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the method body at 6:5 +note: ...and is required to live as long as `'static` here + --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:31 + | +LL | fn f(self: Pin<&Self>) -> impl Clone { self } + | ^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `self`, you can add an explicit `'_` lifetime bound | LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self } | ^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.rs b/src/test/ui/specialization/assoc-ty-graph-cycle.rs index 54d51492ab3..fc39b553a61 100644 --- a/src/test/ui/specialization/assoc-ty-graph-cycle.rs +++ b/src/test/ui/specialization/assoc-ty-graph-cycle.rs @@ -2,7 +2,7 @@ // Make sure we don't crash with a cycle error during coherence. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Trait<T> { type Assoc; diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr new file mode 100644 index 00000000000..250f48f8e59 --- /dev/null +++ b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/assoc-ty-graph-cycle.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/cross-crate-defaults.rs b/src/test/ui/specialization/cross-crate-defaults.rs index 79cb6594397..fc28d0c815e 100644 --- a/src/test/ui/specialization/cross-crate-defaults.rs +++ b/src/test/ui/specialization/cross-crate-defaults.rs @@ -2,7 +2,7 @@ // aux-build:cross_crates_defaults.rs -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete extern crate cross_crates_defaults; diff --git a/src/test/ui/specialization/cross-crate-defaults.stderr b/src/test/ui/specialization/cross-crate-defaults.stderr new file mode 100644 index 00000000000..f18bc99d739 --- /dev/null +++ b/src/test/ui/specialization/cross-crate-defaults.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/cross-crate-defaults.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs index 15550bcce2a..5d67160eb96 100644 --- a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs +++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.rs @@ -5,7 +5,7 @@ // aux-build:go_trait.rs -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete extern crate go_trait; diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr new file mode 100644 index 00000000000..1b50329719d --- /dev/null +++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/allowed-cross-crate.rs:8:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.rs b/src/test/ui/specialization/defaultimpl/out-of-order.rs index f9c73a19cfa..13258ac8c9f 100644 --- a/src/test/ui/specialization/defaultimpl/out-of-order.rs +++ b/src/test/ui/specialization/defaultimpl/out-of-order.rs @@ -2,7 +2,7 @@ // Test that you can list the more specific impl before the more general one. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { type Out; diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.stderr b/src/test/ui/specialization/defaultimpl/out-of-order.stderr new file mode 100644 index 00000000000..deae021a891 --- /dev/null +++ b/src/test/ui/specialization/defaultimpl/out-of-order.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/out-of-order.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.rs b/src/test/ui/specialization/defaultimpl/overlap-projection.rs index ed38bb3fc3a..0add4d5516c 100644 --- a/src/test/ui/specialization/defaultimpl/overlap-projection.rs +++ b/src/test/ui/specialization/defaultimpl/overlap-projection.rs @@ -4,7 +4,7 @@ // projections involve specialization, so long as the associated type is // provided by the most specialized impl. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Assoc { type Output; diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr new file mode 100644 index 00000000000..46899ca9954 --- /dev/null +++ b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/overlap-projection.rs:7:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/projection.rs b/src/test/ui/specialization/defaultimpl/projection.rs index 897a7aade2f..4a914096932 100644 --- a/src/test/ui/specialization/defaultimpl/projection.rs +++ b/src/test/ui/specialization/defaultimpl/projection.rs @@ -1,7 +1,7 @@ // run-pass #![allow(dead_code)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Make sure we *can* project non-defaulted associated types // cf compile-fail/specialization-default-projection.rs diff --git a/src/test/ui/specialization/defaultimpl/projection.stderr b/src/test/ui/specialization/defaultimpl/projection.stderr new file mode 100644 index 00000000000..8629c6c52d4 --- /dev/null +++ b/src/test/ui/specialization/defaultimpl/projection.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/projection.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.rs b/src/test/ui/specialization/defaultimpl/specialization-no-default.rs index 37005f839d4..661724eef8a 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Check a number of scenarios in which one impl tries to override another, // without correctly using `default`. diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr index 13636b28b12..7958eddbeba 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-no-default.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | @@ -65,6 +74,6 @@ LL | fn redundant(&self) {} | = note: to specialize, `redundant` in the parent `impl` must be marked `default` -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0520`. diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs index 2b8ca6bb1dd..89fef5b5ef9 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.rs @@ -3,7 +3,7 @@ // Tests that we can combine a default impl that supplies one method with a // full impl that supplies the other, and they can invoke one another. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn foo_one(&self) -> &'static str; diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr new file mode 100644 index 00000000000..dc377dd10c8 --- /dev/null +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-trait-item-not-implemented-rpass.rs:6:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs index 2a121e61aaa..3c5414469fa 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.rs @@ -1,6 +1,6 @@ // Tests that default impls do not have to supply all items but regular impls do. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn foo_one(&self) -> &'static str; diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr index b862a937066..9d1eca1d6af 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-trait-item-not-implemented.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0046]: not all trait items implemented, missing: `foo_two` --> $DIR/specialization-trait-item-not-implemented.rs:18:1 | @@ -7,6 +16,6 @@ LL | fn foo_two(&self) -> &'static str; LL | impl Foo for MyStruct {} | ^^^^^^^^^^^^^^^^^^^^^ missing `foo_two` in implementation -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0046`. diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs index 5c104449fe9..35e3b8725a8 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.rs @@ -2,7 +2,7 @@ // - default impls do not have to supply all items and // - a default impl does not count as an impl (in this case, an incomplete default impl). -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn foo_one(&self) -> &'static str; diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index a55d79ee035..6b8e559bc36 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-trait-not-implemented.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope --> $DIR/specialization-trait-not-implemented.rs:22:29 | @@ -19,6 +28,6 @@ note: `Foo` defines an item `foo_one`, perhaps you need to implement it LL | trait Foo { | ^^^^^^^^^ -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs index 232338d9d4d..afd634725e3 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs @@ -1,6 +1,6 @@ // Tests that a default impl still has to have a WF trait ref. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo<'a, T: Eq + 'a> { } diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index f499c1f5698..d45825651a8 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-wfcheck.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 | @@ -12,6 +21,6 @@ help: consider restricting type parameter `U` LL | default impl<U: std::cmp::Eq> Foo<'static, U> for () {} | ^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/specialization/defaultimpl/validation.rs b/src/test/ui/specialization/defaultimpl/validation.rs index 8134333c58f..8558a1efb82 100644 --- a/src/test/ui/specialization/defaultimpl/validation.rs +++ b/src/test/ui/specialization/defaultimpl/validation.rs @@ -1,5 +1,5 @@ #![feature(negative_impls)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete struct S; struct Z; diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 254eaf51a64..2449849725f 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -8,6 +8,15 @@ LL | default impl S {} | = note: only trait implementations may be annotated with `default` +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/validation.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error: impls of auto traits cannot be default --> $DIR/validation.rs:9:21 | @@ -36,6 +45,6 @@ error[E0750]: negative impls cannot be default impls LL | default impl !Tr for S {} | ^^^^^^^ ^ -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0750`. diff --git a/src/test/ui/specialization/issue-36804.rs b/src/test/ui/specialization/issue-36804.rs index 9546a5dd5f5..89350602f36 100644 --- a/src/test/ui/specialization/issue-36804.rs +++ b/src/test/ui/specialization/issue-36804.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete pub struct Cloned<I>(I); diff --git a/src/test/ui/specialization/issue-36804.stderr b/src/test/ui/specialization/issue-36804.stderr new file mode 100644 index 00000000000..744d8820424 --- /dev/null +++ b/src/test/ui/specialization/issue-36804.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-36804.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/issue-39448.rs b/src/test/ui/specialization/issue-39448.rs index 8ac6d8e9311..9dd47a4a17e 100644 --- a/src/test/ui/specialization/issue-39448.rs +++ b/src/test/ui/specialization/issue-39448.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Regression test for a specialization-related ICE (#39448). diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr index 861a1d9e8fc..f3bb69b8f71 100644 --- a/src/test/ui/specialization/issue-39448.stderr +++ b/src/test/ui/specialization/issue-39448.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-39448.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0275]: overflow evaluating the requirement `T: FromA<U>` --> $DIR/issue-39448.rs:45:13 | @@ -7,6 +16,6 @@ LL | x.foo(y.to()).to() = note: required because of the requirements on the impl of `FromA<U>` for `T` = note: required because of the requirements on the impl of `ToA<T>` for `U` -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/specialization/issue-39618.rs b/src/test/ui/specialization/issue-39618.rs index 20e81e4359b..72630ee9c70 100644 --- a/src/test/ui/specialization/issue-39618.rs +++ b/src/test/ui/specialization/issue-39618.rs @@ -4,7 +4,7 @@ // check-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn foo(&self); diff --git a/src/test/ui/specialization/issue-39618.stderr b/src/test/ui/specialization/issue-39618.stderr new file mode 100644 index 00000000000..d40d17d8f71 --- /dev/null +++ b/src/test/ui/specialization/issue-39618.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-39618.rs:7:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/issue-50452.rs b/src/test/ui/specialization/issue-50452.rs index 93f081d9558..29fc12066e8 100644 --- a/src/test/ui/specialization/issue-50452.rs +++ b/src/test/ui/specialization/issue-50452.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete pub trait Foo { fn foo(); diff --git a/src/test/ui/specialization/issue-50452.stderr b/src/test/ui/specialization/issue-50452.stderr new file mode 100644 index 00000000000..c01817e0b27 --- /dev/null +++ b/src/test/ui/specialization/issue-50452.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-50452.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/issue-52050.rs b/src/test/ui/specialization/issue-52050.rs index 1e1bfe9cf07..80465870206 100644 --- a/src/test/ui/specialization/issue-52050.rs +++ b/src/test/ui/specialization/issue-52050.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Regression test for #52050: when inserting the blanket impl `I` // into the tree, we had to replace the child node for `Foo`, which diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index 36f96b01198..a7564ced055 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-52050.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`: --> $DIR/issue-52050.rs:28:1 | @@ -13,6 +22,6 @@ LL | impl IntoPyDictPointer for () | = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/specialization/issue-63716-parse-async.rs b/src/test/ui/specialization/issue-63716-parse-async.rs index c3764ffaab8..10f185c3351 100644 --- a/src/test/ui/specialization/issue-63716-parse-async.rs +++ b/src/test/ui/specialization/issue-63716-parse-async.rs @@ -4,7 +4,7 @@ // check-pass // edition:2018 -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete fn main() {} diff --git a/src/test/ui/specialization/issue-63716-parse-async.stderr b/src/test/ui/specialization/issue-63716-parse-async.stderr new file mode 100644 index 00000000000..43620e1ba51 --- /dev/null +++ b/src/test/ui/specialization/issue-63716-parse-async.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-63716-parse-async.rs:7:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/issue-70442.rs b/src/test/ui/specialization/issue-70442.rs index 4371dd2e167..d41b5355c2c 100644 --- a/src/test/ui/specialization/issue-70442.rs +++ b/src/test/ui/specialization/issue-70442.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // check-pass diff --git a/src/test/ui/specialization/issue-70442.stderr b/src/test/ui/specialization/issue-70442.stderr new file mode 100644 index 00000000000..f71e4c7dd1c --- /dev/null +++ b/src/test/ui/specialization/issue-70442.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-70442.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/non-defaulted-item-fail.rs b/src/test/ui/specialization/non-defaulted-item-fail.rs index 403f718d7dd..b7d6ac829dd 100644 --- a/src/test/ui/specialization/non-defaulted-item-fail.rs +++ b/src/test/ui/specialization/non-defaulted-item-fail.rs @@ -1,4 +1,5 @@ #![feature(specialization, associated_type_defaults)] +//~^ WARN the feature `specialization` is incomplete // Test that attempting to override a non-default method or one not in the // parent impl causes an error. diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr index e6c5fc1441b..eae045b92c0 100644 --- a/src/test/ui/specialization/non-defaulted-item-fail.stderr +++ b/src/test/ui/specialization/non-defaulted-item-fail.stderr @@ -1,5 +1,14 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/non-defaulted-item-fail.rs:1:12 + | +LL | #![feature(specialization, associated_type_defaults)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:29:5 + --> $DIR/non-defaulted-item-fail.rs:30:5 | LL | / impl<T> Foo for Box<T> { LL | | type Ty = bool; @@ -14,7 +23,7 @@ LL | type Ty = Vec<()>; = note: to specialize, `Ty` in the parent `impl` must be marked `default` error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:31:5 + --> $DIR/non-defaulted-item-fail.rs:32:5 | LL | / impl<T> Foo for Box<T> { LL | | type Ty = bool; @@ -29,7 +38,7 @@ LL | const CONST: u8 = 42; = note: to specialize, `CONST` in the parent `impl` must be marked `default` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:33:5 + --> $DIR/non-defaulted-item-fail.rs:34:5 | LL | / impl<T> Foo for Box<T> { LL | | type Ty = bool; @@ -44,7 +53,7 @@ LL | fn foo(&self) -> bool { true } = note: to specialize, `foo` in the parent `impl` must be marked `default` error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:45:5 + --> $DIR/non-defaulted-item-fail.rs:46:5 | LL | impl<T> Foo for Vec<T> {} | ------------------------- parent `impl` is here @@ -55,7 +64,7 @@ LL | type Ty = Vec<()>; = note: to specialize, `Ty` in the parent `impl` must be marked `default` error[E0520]: `CONST` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:47:5 + --> $DIR/non-defaulted-item-fail.rs:48:5 | LL | impl<T> Foo for Vec<T> {} | ------------------------- parent `impl` is here @@ -66,7 +75,7 @@ LL | const CONST: u8 = 42; = note: to specialize, `CONST` in the parent `impl` must be marked `default` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/non-defaulted-item-fail.rs:49:5 + --> $DIR/non-defaulted-item-fail.rs:50:5 | LL | impl<T> Foo for Vec<T> {} | ------------------------- parent `impl` is here @@ -76,6 +85,6 @@ LL | fn foo(&self) -> bool { true } | = note: to specialize, `foo` in the parent `impl` must be marked `default` -error: aborting due to 6 previous errors +error: aborting due to 6 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0520`. diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.rs b/src/test/ui/specialization/specialization-allowed-cross-crate.rs index 15550bcce2a..5d67160eb96 100644 --- a/src/test/ui/specialization/specialization-allowed-cross-crate.rs +++ b/src/test/ui/specialization/specialization-allowed-cross-crate.rs @@ -5,7 +5,7 @@ // aux-build:go_trait.rs -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete extern crate go_trait; diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr new file mode 100644 index 00000000000..7d087545725 --- /dev/null +++ b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-allowed-cross-crate.rs:8:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-assoc-fns.rs b/src/test/ui/specialization/specialization-assoc-fns.rs index b6a7a48972a..cbfcb4719f6 100644 --- a/src/test/ui/specialization/specialization-assoc-fns.rs +++ b/src/test/ui/specialization/specialization-assoc-fns.rs @@ -2,7 +2,7 @@ // Test that non-method associated functions can be specialized -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn mk() -> Self; diff --git a/src/test/ui/specialization/specialization-assoc-fns.stderr b/src/test/ui/specialization/specialization-assoc-fns.stderr new file mode 100644 index 00000000000..b12738604ea --- /dev/null +++ b/src/test/ui/specialization/specialization-assoc-fns.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-assoc-fns.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-basics.rs b/src/test/ui/specialization/specialization-basics.rs index 6c359e51bc2..721c934dbfa 100644 --- a/src/test/ui/specialization/specialization-basics.rs +++ b/src/test/ui/specialization/specialization-basics.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Tests a variety of basic specialization scenarios and method // dispatch for them. diff --git a/src/test/ui/specialization/specialization-basics.stderr b/src/test/ui/specialization/specialization-basics.stderr new file mode 100644 index 00000000000..ad00cd81df1 --- /dev/null +++ b/src/test/ui/specialization/specialization-basics.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-basics.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-cross-crate.rs b/src/test/ui/specialization/specialization-cross-crate.rs index fa63c866329..4171505aa37 100644 --- a/src/test/ui/specialization/specialization-cross-crate.rs +++ b/src/test/ui/specialization/specialization-cross-crate.rs @@ -2,7 +2,7 @@ // aux-build:specialization_cross_crate.rs -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete extern crate specialization_cross_crate; diff --git a/src/test/ui/specialization/specialization-cross-crate.stderr b/src/test/ui/specialization/specialization-cross-crate.stderr new file mode 100644 index 00000000000..7481eed796d --- /dev/null +++ b/src/test/ui/specialization/specialization-cross-crate.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-cross-crate.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-default-methods.rs b/src/test/ui/specialization/specialization-default-methods.rs index 9ae3d1e9f39..dcf68afa945 100644 --- a/src/test/ui/specialization/specialization-default-methods.rs +++ b/src/test/ui/specialization/specialization-default-methods.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Test that default methods are cascaded correctly diff --git a/src/test/ui/specialization/specialization-default-methods.stderr b/src/test/ui/specialization/specialization-default-methods.stderr new file mode 100644 index 00000000000..4fa19adad06 --- /dev/null +++ b/src/test/ui/specialization/specialization-default-methods.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-default-methods.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-default-projection.rs b/src/test/ui/specialization/specialization-default-projection.rs index e9343f23601..7f3ae951287 100644 --- a/src/test/ui/specialization/specialization-default-projection.rs +++ b/src/test/ui/specialization/specialization-default-projection.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Make sure we can't project defaulted associated types diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index ac15ab0681a..456eb6d5ca5 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-default-projection.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:21:5 | @@ -28,6 +37,6 @@ LL | generic::<()>() = help: consider constraining the associated type `<() as Foo>::Assoc` to `()` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/specialization/specialization-default-types.rs b/src/test/ui/specialization/specialization-default-types.rs index acb86d889d4..346471f11e4 100644 --- a/src/test/ui/specialization/specialization-default-types.rs +++ b/src/test/ui/specialization/specialization-default-types.rs @@ -2,7 +2,7 @@ // associated type in the impl defining it -- otherwise, what happens // if it's overridden? -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Example { type Output; diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 7233387eba1..5e0221f0788 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-default-types.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:15:9 | @@ -24,6 +33,6 @@ LL | Example::generate(t) = help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/specialization/specialization-no-default.rs b/src/test/ui/specialization/specialization-no-default.rs index 57346b26d24..ae739b2358d 100644 --- a/src/test/ui/specialization/specialization-no-default.rs +++ b/src/test/ui/specialization/specialization-no-default.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Check a number of scenarios in which one impl tries to override another, // without correctly using `default`. diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr index 992e9abbd4c..bb8b2a6c98e 100644 --- a/src/test/ui/specialization/specialization-no-default.stderr +++ b/src/test/ui/specialization/specialization-no-default.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-no-default.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 | @@ -65,6 +74,6 @@ LL | default fn redundant(&self) {} | = note: to specialize, `redundant` in the parent `impl` must be marked `default` -error: aborting due to 5 previous errors +error: aborting due to 5 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0520`. diff --git a/src/test/ui/specialization/specialization-on-projection.rs b/src/test/ui/specialization/specialization-on-projection.rs index 5606eaea307..be8dcc4232e 100644 --- a/src/test/ui/specialization/specialization-on-projection.rs +++ b/src/test/ui/specialization/specialization-on-projection.rs @@ -1,7 +1,7 @@ // run-pass #![allow(dead_code)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Ensure that specialization works for impls defined directly on a projection diff --git a/src/test/ui/specialization/specialization-on-projection.stderr b/src/test/ui/specialization/specialization-on-projection.stderr new file mode 100644 index 00000000000..d91668d10c5 --- /dev/null +++ b/src/test/ui/specialization/specialization-on-projection.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-on-projection.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-out-of-order.rs b/src/test/ui/specialization/specialization-out-of-order.rs index 94e764f7636..cb7563e2760 100644 --- a/src/test/ui/specialization/specialization-out-of-order.rs +++ b/src/test/ui/specialization/specialization-out-of-order.rs @@ -2,7 +2,7 @@ // Test that you can list the more specific impl before the more general one. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { type Out; diff --git a/src/test/ui/specialization/specialization-out-of-order.stderr b/src/test/ui/specialization/specialization-out-of-order.stderr new file mode 100644 index 00000000000..a17f9f11a3f --- /dev/null +++ b/src/test/ui/specialization/specialization-out-of-order.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-out-of-order.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-overlap-negative.rs b/src/test/ui/specialization/specialization-overlap-negative.rs index 90dbef3075b..550d3708295 100644 --- a/src/test/ui/specialization/specialization-overlap-negative.rs +++ b/src/test/ui/specialization/specialization-overlap-negative.rs @@ -1,5 +1,5 @@ #![feature(negative_impls)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait MyTrait {} diff --git a/src/test/ui/specialization/specialization-overlap-negative.stderr b/src/test/ui/specialization/specialization-overlap-negative.stderr index e2616534d20..6141174ba8c 100644 --- a/src/test/ui/specialization/specialization-overlap-negative.stderr +++ b/src/test/ui/specialization/specialization-overlap-negative.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-overlap-negative.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`: --> $DIR/specialization-overlap-negative.rs:9:1 | @@ -6,6 +15,6 @@ LL | unsafe impl<T: Clone> Send for TestType<T> {} LL | impl<T: MyTrait> !Send for TestType<T> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0751`. diff --git a/src/test/ui/specialization/specialization-overlap-projection.rs b/src/test/ui/specialization/specialization-overlap-projection.rs index 00b83c7e7a1..b07efb2a5c1 100644 --- a/src/test/ui/specialization/specialization-overlap-projection.rs +++ b/src/test/ui/specialization/specialization-overlap-projection.rs @@ -4,7 +4,7 @@ // projections involve specialization, so long as the associated type is // provided by the most specialized impl. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Assoc { type Output; diff --git a/src/test/ui/specialization/specialization-overlap-projection.stderr b/src/test/ui/specialization/specialization-overlap-projection.stderr new file mode 100644 index 00000000000..6f1a594bacb --- /dev/null +++ b/src/test/ui/specialization/specialization-overlap-projection.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-overlap-projection.rs:7:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-overlap.rs b/src/test/ui/specialization/specialization-overlap.rs index c8ef8d61c1e..6bee22ceb8b 100644 --- a/src/test/ui/specialization/specialization-overlap.rs +++ b/src/test/ui/specialization/specialization-overlap.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Foo { fn foo() {} } impl<T: Clone> Foo for T {} diff --git a/src/test/ui/specialization/specialization-overlap.stderr b/src/test/ui/specialization/specialization-overlap.stderr index 4275e7bdd85..cf0f186a183 100644 --- a/src/test/ui/specialization/specialization-overlap.stderr +++ b/src/test/ui/specialization/specialization-overlap.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-overlap.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`: --> $DIR/specialization-overlap.rs:5:1 | @@ -30,6 +39,6 @@ LL | impl<T: Clone> Qux for T {} LL | impl<T: Eq> Qux for T {} | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error: aborting due to 4 previous errors +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/specialization/specialization-polarity.rs b/src/test/ui/specialization/specialization-polarity.rs index e78035f1710..17897d8b803 100644 --- a/src/test/ui/specialization/specialization-polarity.rs +++ b/src/test/ui/specialization/specialization-polarity.rs @@ -2,7 +2,7 @@ #![feature(optin_builtin_traits)] #![feature(negative_impls)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete auto trait Foo {} diff --git a/src/test/ui/specialization/specialization-polarity.stderr b/src/test/ui/specialization/specialization-polarity.stderr index 44e60cad67a..c44af22b8e6 100644 --- a/src/test/ui/specialization/specialization-polarity.stderr +++ b/src/test/ui/specialization/specialization-polarity.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-polarity.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`: --> $DIR/specialization-polarity.rs:10:1 | @@ -14,6 +23,6 @@ LL | impl<T> !Bar for T {} LL | impl Bar for u8 {} | ^^^^^^^^^^^^^^^ positive implementation here -error: aborting due to 2 previous errors +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0751`. diff --git a/src/test/ui/specialization/specialization-projection-alias.rs b/src/test/ui/specialization/specialization-projection-alias.rs index 0081ed455c9..f1f0b47bb65 100644 --- a/src/test/ui/specialization/specialization-projection-alias.rs +++ b/src/test/ui/specialization/specialization-projection-alias.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Regression test for ICE when combining specialized associated types and type // aliases diff --git a/src/test/ui/specialization/specialization-projection-alias.stderr b/src/test/ui/specialization/specialization-projection-alias.stderr new file mode 100644 index 00000000000..0c3659a8f7a --- /dev/null +++ b/src/test/ui/specialization/specialization-projection-alias.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-projection-alias.rs:5:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-projection.rs b/src/test/ui/specialization/specialization-projection.rs index 86cdccf131e..700975e3b82 100644 --- a/src/test/ui/specialization/specialization-projection.rs +++ b/src/test/ui/specialization/specialization-projection.rs @@ -1,7 +1,7 @@ // run-pass #![allow(dead_code)] -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Make sure we *can* project non-defaulted associated types // cf compile-fail/specialization-default-projection.rs diff --git a/src/test/ui/specialization/specialization-projection.stderr b/src/test/ui/specialization/specialization-projection.stderr new file mode 100644 index 00000000000..c5c86f5108e --- /dev/null +++ b/src/test/ui/specialization/specialization-projection.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-projection.rs:4:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-super-traits.rs b/src/test/ui/specialization/specialization-super-traits.rs index a0f71d87693..fb85d801921 100644 --- a/src/test/ui/specialization/specialization-super-traits.rs +++ b/src/test/ui/specialization/specialization-super-traits.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete // Test that you can specialize via an explicit trait hierarchy diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-super-traits.stderr new file mode 100644 index 00000000000..05bdfd40136 --- /dev/null +++ b/src/test/ui/specialization/specialization-super-traits.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-super-traits.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs index 2e32e3ff02d..5c2781a9c63 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs +++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Iterator { fn next(&self); diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr new file mode 100644 index 00000000000..6284dd8f3f7 --- /dev/null +++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-translate-projections-with-lifetimes.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.rs b/src/test/ui/specialization/specialization-translate-projections-with-params.rs index bdc6501df44..62d63590a66 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-params.rs +++ b/src/test/ui/specialization/specialization-translate-projections-with-params.rs @@ -4,7 +4,7 @@ // type parameters *and* rely on projections, and the type parameters are input // types on the trait. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Trait<T> { fn convert(&self) -> T; diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr new file mode 100644 index 00000000000..b17794173c5 --- /dev/null +++ b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-translate-projections-with-params.rs:7:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/specialization/specialization-translate-projections.rs b/src/test/ui/specialization/specialization-translate-projections.rs index fcccb67902e..92ea9e2b85d 100644 --- a/src/test/ui/specialization/specialization-translate-projections.rs +++ b/src/test/ui/specialization/specialization-translate-projections.rs @@ -3,7 +3,7 @@ // Ensure that provided items are inherited properly even when impls vary in // type parameters *and* rely on projections. -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete use std::convert::Into; diff --git a/src/test/ui/specialization/specialization-translate-projections.stderr b/src/test/ui/specialization/specialization-translate-projections.stderr new file mode 100644 index 00000000000..fbb28e60640 --- /dev/null +++ b/src/test/ui/specialization/specialization-translate-projections.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/specialization-translate-projections.rs:6:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs new file mode 100644 index 00000000000..ef64d799b65 --- /dev/null +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.rs @@ -0,0 +1,28 @@ +trait Trait { + fn func1() -> Struct1<Self>; //~ ERROR E0277 + fn func2<'a>() -> Struct2<'a, Self>; //~ ERROR E0277 + fn func3() -> Struct3<Self>; //~ ERROR E0277 + fn func4() -> Struct4<Self>; //~ ERROR E0277 +} + +struct Struct1<T>{ + _t: std::marker::PhantomData<*const T>, +} +struct Struct2<'a, T>{ + _t: &'a T, +} +struct Struct3<T>{ + _t: T, +} + +struct X<T>(T); + +struct Struct4<T>{ + _t: X<T>, +} + +struct Struct5<T: ?Sized>{ + _t: X<T>, //~ ERROR E0277 +} + +fn main() {} diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr new file mode 100644 index 00000000000..ee08f51f802 --- /dev/null +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -0,0 +1,107 @@ +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:25:5 + | +LL | struct X<T>(T); + | - required by this bound in `X` +... +LL | struct Struct5<T: ?Sized>{ + | - this type parameter needs to be `std::marker::Sized` +LL | _t: X<T>, + | ^^^^^^^^ 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 <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 + | +LL | struct X<T>(T); + | ^ - ...if indirection was used here: `Box<T>` + | | + | this could be changed to `T: ?Sized`... + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:2:19 + | +LL | fn func1() -> Struct1<Self>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct1<T>{ + | - required by this bound in `Struct1` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider further restricting `Self` + | +LL | fn func1() -> Struct1<Self> where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct1<T: ?Sized>{ + | ^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:3:23 + | +LL | fn func2<'a>() -> Struct2<'a, Self>; + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct2<'a, T>{ + | - required by this bound in `Struct2` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider further restricting `Self` + | +LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct2<'a, T: ?Sized>{ + | ^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:4:19 + | +LL | fn func3() -> Struct3<Self>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct3<T>{ + | - required by this bound in `Struct3` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 + | +LL | struct Struct3<T>{ + | ^ this could be changed to `T: ?Sized`... +LL | _t: T, + | - ...if indirection was used here: `Box<T>` +help: consider further restricting `Self` + | +LL | fn func3() -> Struct3<Self> where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19 + | +LL | fn func4() -> Struct4<Self>; + | ^^^^^^^^^^^^^ doesn't have a size known at compile-time +... +LL | struct Struct4<T>{ + | - required by this bound in `Struct4` + | + = help: the trait `std::marker::Sized` is not implemented for `Self` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider further restricting `Self` + | +LL | fn func4() -> Struct4<Self> where Self: std::marker::Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Struct4<T: ?Sized>{ + | ^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 5cf170d566c..9ab06032853 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -6,20 +6,23 @@ LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | | | help: consider introducing lifetime `'a` here: `'a,` -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | ------ ------------- ...is required to be `'static` by this... - | | - | data with this lifetime... + | ------ this data with an anonymous lifetime `'_`... ... LL | / move || { LL | | *dest = g.get(); LL | | } - | |_____^ ...and is captured here + | |_____^ ...is captured here... | -help: to permit non-static references in an `impl Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 15:1 +note: ...and is required to live as long as `'static` here + --> $DIR/missing-lifetimes-in-signature.rs:15:37 + | +LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + | ^^^^^^^^^^^^^ +help: to declare that the `impl Trait` captures data from argument `dest`, you can add an explicit `'_` lifetime bound | LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^ @@ -122,5 +125,5 @@ LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a error: aborting due to 7 previous errors -Some errors have detailed explanations: E0261, E0309, E0621. +Some errors have detailed explanations: E0261, E0309, E0621, E0759. For more information about an error, try `rustc --explain E0261`. diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.rs b/src/test/ui/suggestions/type-not-found-in-adt-field.rs new file mode 100644 index 00000000000..4cbfe58d357 --- /dev/null +++ b/src/test/ui/suggestions/type-not-found-in-adt-field.rs @@ -0,0 +1,9 @@ +struct Struct { + m: Vec<Someunknownname<String, ()>>, //~ ERROR cannot find type `Someunknownname` in this scope + //~^ NOTE not found in this scope +} +struct OtherStruct { //~ HELP you might be missing a type parameter + m: K, //~ ERROR cannot find type `K` in this scope + //~^ NOTE not found in this scope +} +fn main() {} diff --git a/src/test/ui/suggestions/type-not-found-in-adt-field.stderr b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr new file mode 100644 index 00000000000..e990fb5ba12 --- /dev/null +++ b/src/test/ui/suggestions/type-not-found-in-adt-field.stderr @@ -0,0 +1,17 @@ +error[E0412]: cannot find type `Someunknownname` in this scope + --> $DIR/type-not-found-in-adt-field.rs:2:12 + | +LL | m: Vec<Someunknownname<String, ()>>, + | ^^^^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `K` in this scope + --> $DIR/type-not-found-in-adt-field.rs:6:8 + | +LL | struct OtherStruct { + | - help: you might be missing a type parameter: `<K>` +LL | m: K, + | ^ not found in this scope + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/tag-variant-cast-non-nullary.fixed b/src/test/ui/tag-variant-cast-non-nullary.fixed new file mode 100644 index 00000000000..53e68c2ac6a --- /dev/null +++ b/src/test/ui/tag-variant-cast-non-nullary.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] +enum NonNullary { + Nullary, + Other(isize), +} + +impl From<NonNullary> for isize { + fn from(val: NonNullary) -> isize { + match val { + NonNullary::Nullary => 0, + NonNullary::Other(i) => i, + } + } +} + +fn main() { + let v = NonNullary::Nullary; + let val = isize::from(v); //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605] +} diff --git a/src/test/ui/tag-variant-cast-non-nullary.rs b/src/test/ui/tag-variant-cast-non-nullary.rs index bb34e82cdca..0d0c6188ad1 100644 --- a/src/test/ui/tag-variant-cast-non-nullary.rs +++ b/src/test/ui/tag-variant-cast-non-nullary.rs @@ -1,8 +1,19 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] enum NonNullary { Nullary, Other(isize), } +impl From<NonNullary> for isize { + fn from(val: NonNullary) -> isize { + match val { + NonNullary::Nullary => 0, + NonNullary::Other(i) => i, + } + } +} + fn main() { let v = NonNullary::Nullary; let val = v as isize; //~ ERROR non-primitive cast: `NonNullary` as `isize` [E0605] diff --git a/src/test/ui/tag-variant-cast-non-nullary.stderr b/src/test/ui/tag-variant-cast-non-nullary.stderr index 87ec20f20d7..ae2f5a7aead 100644 --- a/src/test/ui/tag-variant-cast-non-nullary.stderr +++ b/src/test/ui/tag-variant-cast-non-nullary.stderr @@ -1,10 +1,10 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize` - --> $DIR/tag-variant-cast-non-nullary.rs:8:15 + --> $DIR/tag-variant-cast-non-nullary.rs:19:15 | LL | let val = v as isize; - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)` | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to previous error diff --git a/src/test/ui/tls.rs b/src/test/ui/tls.rs new file mode 100644 index 00000000000..fbd3413885f --- /dev/null +++ b/src/test/ui/tls.rs @@ -0,0 +1,14 @@ +// run-pass +// ignore-emscripten no threads support +// compile-flags: -O + +#![feature(thread_local)] + +#[thread_local] +static S: u32 = 222; + +fn main() { + let local = &S as *const u32 as usize; + let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap(); + assert_ne!(local, foreign); +} diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.rs b/src/test/ui/traits/negative-impls/negative-default-impls.rs index 2d50bc83ec3..c68bca432fa 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.rs +++ b/src/test/ui/traits/negative-impls/negative-default-impls.rs @@ -1,5 +1,6 @@ #![feature(negative_impls)] #![feature(specialization)] +//~^ WARN the feature `specialization` is incomplete trait MyTrait { type Foo; diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr index a70bbe6b948..50e74373b53 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -1,9 +1,18 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-default-impls.rs:2:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0750]: negative impls cannot be default impls - --> $DIR/negative-default-impls.rs:8:1 + --> $DIR/negative-default-impls.rs:9:1 | LL | default impl !MyTrait for u32 {} | ^^^^^^^ ^ -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0750`. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.rs b/src/test/ui/traits/negative-impls/negative-specializes-negative.rs index 877c3e8af4f..35297ab124e 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-negative.rs +++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete #![feature(negative_impls)] // Test a negative impl that "specializes" another negative impl. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr new file mode 100644 index 00000000000..8b536de3786 --- /dev/null +++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-negative.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs index da22e43377f..4281eedaf63 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete #![feature(negative_impls)] // Negative impl for u32 cannot "specialize" the base impl. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr index 079546a7df4..89ef15e89ac 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-positive-item.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive-item.rs:11:1 | @@ -7,6 +16,6 @@ LL | impl<T> MyTrait for T { LL | impl !MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0751`. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.rs b/src/test/ui/traits/negative-impls/negative-specializes-positive.rs index 1939a098b50..0e227691e04 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive.rs +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete #![feature(negative_impls)] // Negative impl for u32 cannot "specialize" the base impl. diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr index ea005c1cbe0..e45d5a251ab 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/negative-specializes-positive.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive.rs:7:1 | @@ -6,6 +15,6 @@ LL | impl<T> MyTrait for T {} LL | impl !MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^^ negative implementation here -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0751`. diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.rs b/src/test/ui/traits/negative-impls/positive-specializes-negative.rs index f2c5f507a4e..a06b3576540 100644 --- a/src/test/ui/traits/negative-impls/positive-specializes-negative.rs +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.rs @@ -1,4 +1,4 @@ -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete #![feature(negative_impls)] trait MyTrait {} diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr index a24d7aa442f..49c16d47404 100644 --- a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -1,3 +1,12 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/positive-specializes-negative.rs:1:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/positive-specializes-negative.rs:7:1 | @@ -6,6 +15,6 @@ LL | impl<T> !MyTrait for T {} LL | impl MyTrait for u32 {} | ^^^^^^^^^^^^^^^^^^^^ positive implementation here -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0751`. diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index 7fd5c11fcf0..3be4f110973 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -20,13 +20,6 @@ error[E0599]: no method named `b` found for struct `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<S>` here - | the method is available for `std::sync::Arc<S>` here - | the method is available for `std::rc::Rc<S>` here -... LL | S.b(); | ^ method not found in `S` | diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.rs b/src/test/ui/traits/traits-inductive-overflow-lifetime.rs new file mode 100644 index 00000000000..205d50a2ed9 --- /dev/null +++ b/src/test/ui/traits/traits-inductive-overflow-lifetime.rs @@ -0,0 +1,30 @@ +// Test that we don't hit the recursion limit for short cycles involving lifetimes. + +// Shouldn't hit this, we should realize that we're in a cycle sooner. +#![recursion_limit="20"] + +trait NotAuto {} +trait Y { + type P; +} + +impl<'a> Y for C<'a> { + type P = Box<X<C<'a>>>; +} + +struct C<'a>(&'a ()); +struct X<T: Y>(T::P); + +impl<T: NotAuto> NotAuto for Box<T> {} +impl<T: Y> NotAuto for X<T> where T::P: NotAuto {} +impl<'a> NotAuto for C<'a> {} + +fn is_send<S: NotAuto>() {} +//~^ NOTE: required + +fn main() { + // Should only be a few notes. + is_send::<X<C<'static>>>(); + //~^ ERROR overflow evaluating + //~| NOTE: required +} diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr new file mode 100644 index 00000000000..9a227229ea4 --- /dev/null +++ b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr @@ -0,0 +1,14 @@ +error[E0275]: overflow evaluating the requirement `std::boxed::Box<X<C<'_>>>: NotAuto` + --> $DIR/traits-inductive-overflow-lifetime.rs:27:5 + | +LL | fn is_send<S: NotAuto>() {} + | ------- required by this bound in `is_send` +... +LL | is_send::<X<C<'static>>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/transmute-specialization.rs b/src/test/ui/transmute-specialization.rs index 002fba9ce81..499334d983b 100644 --- a/src/test/ui/transmute-specialization.rs +++ b/src/test/ui/transmute-specialization.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(specialization)] +#![feature(specialization)] //~ WARN the feature `specialization` is incomplete trait Specializable { type Output; } diff --git a/src/test/ui/transmute-specialization.stderr b/src/test/ui/transmute-specialization.stderr new file mode 100644 index 00000000000..02315051d30 --- /dev/null +++ b/src/test/ui/transmute-specialization.stderr @@ -0,0 +1,11 @@ +warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/transmute-specialization.rs:3:12 + | +LL | #![feature(specialization)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index 4fbbf347528..a6b7e35b488 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -16,9 +16,7 @@ error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | LL | let _ = x as &'static str; - | ^^^^^^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs b/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs new file mode 100644 index 00000000000..e4436260e70 --- /dev/null +++ b/src/test/ui/typeck/issue-68590-reborrow-through-derefmut.rs @@ -0,0 +1,25 @@ +// check-pass + +// rust-lang/rust#68590: confusing diagnostics when reborrowing through DerefMut. + +use std::cell::RefCell; + +struct A; + +struct S<'a> { + a: &'a mut A, +} + +fn take_a(_: &mut A) {} + +fn test<'a>(s: &RefCell<S<'a>>) { + let mut guard = s.borrow_mut(); + take_a(guard.a); + let _s2 = S { a: guard.a }; +} + +fn main() { + let a = &mut A; + let s = RefCell::new(S { a }); + test(&s); +} diff --git a/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs b/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs new file mode 100644 index 00000000000..3ea05389f04 --- /dev/null +++ b/src/test/ui/typeck/issue-72225-call-fnmut-through-derefmut.rs @@ -0,0 +1,21 @@ +// check-pass + +// rust-lang/rust#72225: confusing diagnostics when calling FnMut through DerefMut. + +use std::cell::RefCell; + +struct S { + f: Box<dyn FnMut()> +} + +fn test(s: &RefCell<S>) { + let mut guard = s.borrow_mut(); + (guard.f)(); +} + +fn main() { + let s = RefCell::new(S { + f: Box::new(|| ()) + }); + test(&s); +} diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index 3577dd59289..dda5de431d3 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,16 +1,17 @@ -error: cannot infer an appropriate lifetime +error[E0759]: cannot infer an appropriate lifetime --> $DIR/dyn-trait-underscore.rs:8:20 | LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { - | ---- data with this lifetime... + | ---- this data with an anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- ...is captured and required to be `'static` here + | ---------------^^^^--- ...is captured and required to live as long as `'static` here | -help: to permit non-static references in a `dyn Trait` value, you can add an explicit bound for the anonymous lifetime #1 defined on the function body at 6:1 +help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> { | ^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr index a39af7832f8..a9f10dfec99 100644 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr +++ b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr @@ -2,9 +2,7 @@ error[E0605]: non-primitive cast: `E` as `isize` --> $DIR/uninhabited-enum-cast.rs:4:20 | LL | println!("{}", (e as isize).to_string()); - | ^^^^^^^^^^^^ - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object 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 f43d00f9739..1908aee25ea 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() } | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box<U>` + --> $DIR/unsized-enum.rs:4:10 + | +LL | enum Foo<U> { FooSome(U), FooNone } + | ^ - ...if indirection was used here: `Box<U>` + | | + | this could be changed to `U: ?Sized`... 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 808c9c583d4..e0f077d66f9 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -11,6 +11,13 @@ LL | impl<X: ?Sized> S5<X> { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>` + --> $DIR/unsized-inherent-impl-self-type.rs:5:11 + | +LL | struct S5<Y>(Y); + | ^ - ...if indirection was used here: `Box<Y>` + | | + | this could be changed to `Y: ?Sized`... 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 42fc5569ece..d92d1d9113e 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -11,6 +11,13 @@ LL | fn foo2<T: ?Sized>() { not_sized::<Foo<T>>() } | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/unsized-struct.rs:4:12 + | +LL | struct Foo<T> { data: T } + | ^ - ...if indirection was used here: `Box<T>` + | | + | this could be changed to `T: ?Sized`... error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unsized-struct.rs:13:24 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 c2b2fe40ce6..73c5439da53 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -11,6 +11,13 @@ LL | impl<X: ?Sized> T3<X> for S5<X> { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box<Y>` + --> $DIR/unsized-trait-impl-self-type.rs:8:11 + | +LL | struct S5<Y>(Y); + | ^ - ...if indirection was used here: `Box<Y>` + | | + | this could be changed to `Y: ?Sized`... error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index 4cf054d177f..e423a9bdeab 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -11,6 +11,10 @@ LL | impl<X: ?Sized> T2<X> for S4<X> { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider relaxing the implicit `Sized` restriction + | +LL | trait T2<Z: ?Sized> { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index 828e8bc9f4a..e0a0389dc46 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -48,6 +48,10 @@ LL | f5(x1); = help: within `S<X>`, the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required because it appears within the type `S<X>` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5<Y: ?Sized>(x: &Y) {} + | ^^^^^^^^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized3.rs:40:8 @@ -91,6 +95,10 @@ LL | f5(&(32, *x1)); = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> = note: required because it appears within the type `S<X>` = note: required because it appears within the type `({integer}, S<X>)` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn f5<Y: ?Sized>(x: &Y) {} + | ^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index d18644f005a..e616a5cf0f9 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -11,6 +11,10 @@ LL | impl<X: ?Sized + T> T1<X> for S3<X> { | = help: the trait `std::marker::Sized` is not implemented for `X` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider relaxing the implicit `Sized` restriction + | +LL | trait T1<Z: T + ?Sized> { + | ^^^^^^^^ 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 59a4f9bad9d..731d31ac34f 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -23,6 +23,13 @@ LL | struct Vec<T> { | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` + --> $DIR/wf-fn-where-clause.rs:16:12 + | +LL | struct Vec<T> { + | ^ this could be changed to `T: ?Sized`... +LL | t: T, + | - ...if indirection was used here: `Box<T>` error[E0038]: the trait `std::marker::Copy` cannot be made into an object --> $DIR/wf-fn-where-clause.rs:12:16 diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 7227683aa5a..59af475af17 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_target::abi::LayoutOf; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; use crate::utils::span_lint; @@ -112,9 +112,9 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool { } impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { - fn consume(&mut self, cmt: &Place<'tcx>, mode: ConsumeMode) { - if cmt.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.base { + fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, mode: ConsumeMode) { + if cmt.place.projections.is_empty() { + if let PlaceBase::Local(lid) = cmt.place.base { if let ConsumeMode::Move = mode { // moved out or in. clearly can't be localized self.set.remove(&lid); @@ -132,16 +132,16 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { } } - fn borrow(&mut self, cmt: &Place<'tcx>, _: ty::BorrowKind) { - if cmt.projections.is_empty() { - if let PlaceBase::Local(lid) = cmt.base { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: ty::BorrowKind) { + if cmt.place.projections.is_empty() { + if let PlaceBase::Local(lid) = cmt.place.base { self.set.remove(&lid); } } } - fn mutate(&mut self, cmt: &Place<'tcx>) { - if cmt.projections.is_empty() { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { + if cmt.place.projections.is_empty() { let map = &self.cx.tcx.hir(); if is_argument(*map, cmt.hir_id) { // Skip closure arguments @@ -150,7 +150,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { return; } - if is_non_trait_box(cmt.ty) && !self.is_large_box(cmt.ty) { + if is_non_trait_box(cmt.place.ty) && !self.is_large_box(cmt.place.ty) { self.set.insert(cmt.hir_id); } return; diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 771bc8d0558..83093ec51bd 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -28,7 +28,7 @@ use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; use std::iter::{once, Iterator}; use std::mem; @@ -1489,42 +1489,43 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } -struct MutatePairDelegate { +struct MutatePairDelegate<'a, 'tcx> { + cx: &'a LateContext<'a, 'tcx>, hir_id_low: Option<HirId>, hir_id_high: Option<HirId>, span_low: Option<Span>, span_high: Option<Span>, } -impl<'tcx> Delegate<'tcx> for MutatePairDelegate { - fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {} +impl<'a, 'tcx> Delegate<'tcx> for MutatePairDelegate<'a, 'tcx> { + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - if let PlaceBase::Local(id) = cmt.base { + if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(cmt.span) + self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(cmt.span) + self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id)) } } } } - fn mutate(&mut self, cmt: &Place<'tcx>) { - if let PlaceBase::Local(id) = cmt.base { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { + if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(cmt.span) + self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id)) } if Some(id) == self.hir_id_high { - self.span_high = Some(cmt.span) + self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id)) } } } } -impl<'tcx> MutatePairDelegate { +impl<'a, 'tcx> MutatePairDelegate<'a, 'tcx> { fn mutation_span(&self) -> (Option<Span>, Option<Span>) { (self.span_low, self.span_high) } @@ -1579,12 +1580,13 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr<'_>) -> Option<Hi None } -fn check_for_mutation( - cx: &LateContext<'_, '_>, +fn check_for_mutation<'a, 'tcx> ( + cx: &LateContext<'a, 'tcx>, body: &Expr<'_>, bound_ids: &[Option<HirId>], ) -> (Option<Span>, Option<Span>) { let mut delegate = MutatePairDelegate { + cx: cx, hir_id_low: bound_ids[0], hir_id_high: bound_ids[1], span_low: None, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 218b0d27f74..ca87deac989 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -326,21 +326,21 @@ struct MovedVariablesCtxt { } impl MovedVariablesCtxt { - fn move_common(&mut self, cmt: &euv::Place<'_>) { - if let euv::PlaceBase::Local(vid) = cmt.base { + fn move_common(&mut self, cmt: &euv::PlaceWithHirId<'_>) { + if let euv::PlaceBase::Local(vid) = cmt.place.base { self.moved_vars.insert(vid); } } } impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { - fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) { + fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) { if let euv::ConsumeMode::Move = mode { self.move_common(cmt); } } - fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: ty::BorrowKind) {} - fn mutate(&mut self, _: &euv::Place<'tcx>) {} + fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>) {} } diff --git a/src/tools/clippy/clippy_lints/src/utils/usage.rs b/src/tools/clippy/clippy_lints/src/utils/usage.rs index 904d948ad29..6a7a1f1ceaa 100644 --- a/src/tools/clippy/clippy_lints/src/utils/usage.rs +++ b/src/tools/clippy/clippy_lints/src/utils/usage.rs @@ -8,7 +8,7 @@ use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_span::symbol::{Ident, Symbol}; -use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase}; +use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceWithHirId, PlaceBase}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. pub fn mutated_variables<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &'a LateContext<'a, 'tcx>) -> Option<FxHashSet<HirId>> { @@ -46,8 +46,8 @@ struct MutVarsDelegate { impl<'tcx> MutVarsDelegate { #[allow(clippy::similar_names)] - fn update(&mut self, cat: &Place<'tcx>) { - match cat.base { + fn update(&mut self, cat: &PlaceWithHirId<'tcx>) { + match cat.place.base { PlaceBase::Local(id) => { self.used_mutably.insert(id); }, @@ -63,15 +63,15 @@ impl<'tcx> MutVarsDelegate { } impl<'tcx> Delegate<'tcx> for MutVarsDelegate { - fn consume(&mut self, _: &Place<'tcx>, _: ConsumeMode) {} + fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {} - fn borrow(&mut self, cmt: &Place<'tcx>, bk: ty::BorrowKind) { + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { self.update(&cmt) } } - fn mutate(&mut self, cmt: &Place<'tcx>) { + fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) { self.update(&cmt) } } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 9d1940dd4d6..9614707433e 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -43,6 +43,10 @@ impl EarlyProps { let mut props = EarlyProps::default(); let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); + let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); + let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); iter_header(testfile, None, rdr, &mut |ln| { // we should check if any only-<platform> exists and if it exists @@ -74,7 +78,25 @@ impl EarlyProps { props.ignore = true; } - if !rustc_has_sanitizer_support && config.parse_needs_sanitizer_support(ln) { + if !rustc_has_sanitizer_support + && config.parse_name_directive(ln, "needs-sanitizer-support") + { + props.ignore = true; + } + + if !has_asan && config.parse_name_directive(ln, "needs-sanitizer-address") { + props.ignore = true; + } + + if !has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak") { + props.ignore = true; + } + + if !has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory") { + props.ignore = true; + } + + if !has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread") { props.ignore = true; } @@ -829,10 +851,6 @@ impl Config { self.parse_name_directive(line, "needs-profiler-support") } - fn parse_needs_sanitizer_support(&self, line: &str) -> bool { - self.parse_name_directive(line, "needs-sanitizer-support") - } - /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirective { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index f7355433463..72af34d7826 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -201,3 +201,22 @@ fn debugger() { config.debugger = Some(Debugger::Lldb); assert!(parse_rs(&config, "// ignore-lldb").ignore); } + +#[test] +fn sanitizers() { + let mut config = config(); + + // Target that supports all sanitizers: + config.target = "x86_64-unknown-linux-gnu".to_owned(); + assert!(!parse_rs(&config, "// needs-sanitizer-address").ignore); + assert!(!parse_rs(&config, "// needs-sanitizer-leak").ignore); + assert!(!parse_rs(&config, "// needs-sanitizer-memory").ignore); + assert!(!parse_rs(&config, "// needs-sanitizer-thread").ignore); + + // Target that doesn't support sanitizers: + config.target = "wasm32-unknown-emscripten".to_owned(); + assert!(parse_rs(&config, "// needs-sanitizer-address").ignore); + assert!(parse_rs(&config, "// needs-sanitizer-leak").ignore); + assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore); + assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore); +} diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index ca36a15ffc7..0437ff8c944 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -82,6 +82,23 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[ ("xcore", "xcore"), ]; +pub const ASAN_SUPPORTED_TARGETS: &'static [&'static str] = &[ + "aarch64-fuchsia", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-fuchsia", + "x86_64-unknown-linux-gnu", +]; + +pub const LSAN_SUPPORTED_TARGETS: &'static [&'static str] = + &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; + +pub const MSAN_SUPPORTED_TARGETS: &'static [&'static str] = + &["aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu"]; + +pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] = + &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"]; + pub fn matches_os(triple: &str, name: &str) -> bool { // For the wasm32 bare target we ignore anything also ignored on emscripten // and then we also recognize `wasm32-bare` as the os for the target diff --git a/src/tools/remote-test-client/src/main.rs b/src/tools/remote-test-client/src/main.rs index efc29163455..1fafe109d34 100644 --- a/src/tools/remote-test-client/src/main.rs +++ b/src/tools/remote-test-client/src/main.rs @@ -107,13 +107,23 @@ fn start_android_emulator(server: &Path) { Command::new("adb").arg("shell").arg("/data/tmp/testd").spawn().unwrap(); } -fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) { +fn prepare_rootfs(target: &str, rootfs: &Path, server: &Path, rootfs_img: &Path) { + t!(fs::copy(server, rootfs.join("testd"))); + + match target { + "arm-unknown-linux-gnueabihf" | "aarch64-unknown-linux-gnu" => { + prepare_rootfs_cpio(rootfs, rootfs_img) + } + "riscv64gc-unknown-linux-gnu" => prepare_rootfs_ext4(rootfs, rootfs_img), + _ => panic!("{} is not supported", target), + } +} + +fn prepare_rootfs_cpio(rootfs: &Path, rootfs_img: &Path) { // Generate a new rootfs image now that we've updated the test server // executable. This is the equivalent of: // // find $rootfs -print 0 | cpio --null -o --format=newc > rootfs.img - t!(fs::copy(server, rootfs.join("testd"))); - let rootfs_img = tmpdir.join("rootfs.img"); let mut cmd = Command::new("cpio"); cmd.arg("--null") .arg("-o") @@ -128,6 +138,38 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path t!(io::copy(&mut child.stdout.take().unwrap(), &mut t!(File::create(&rootfs_img)))); assert!(t!(child.wait()).success()); + fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) { + for entry in t!(cur.read_dir()) { + let entry = t!(entry); + let path = entry.path(); + let to_print = path.strip_prefix(root).unwrap(); + t!(write!(w, "{}\u{0}", to_print.to_str().unwrap())); + if t!(entry.file_type()).is_dir() { + add_files(w, root, &path); + } + } + } +} + +fn prepare_rootfs_ext4(rootfs: &Path, rootfs_img: &Path) { + let mut dd = Command::new("dd"); + dd.arg("if=/dev/zero") + .arg(&format!("of={}", rootfs_img.to_string_lossy())) + .arg("bs=1M") + .arg("count=1024"); + let mut dd_child = t!(dd.spawn()); + assert!(t!(dd_child.wait()).success()); + + let mut mkfs = Command::new("mkfs.ext4"); + mkfs.arg("-d").arg(rootfs).arg(rootfs_img); + let mut mkfs_child = t!(mkfs.spawn()); + assert!(t!(mkfs_child.wait()).success()); +} + +fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path) { + let rootfs_img = &tmpdir.join("rootfs.img"); + prepare_rootfs(target, rootfs, server, rootfs_img); + // Start up the emulator, in the background match target { "arm-unknown-linux-gnueabihf" => { @@ -170,19 +212,30 @@ fn start_qemu_emulator(target: &str, rootfs: &Path, server: &Path, tmpdir: &Path .arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00"); t!(cmd.spawn()); } - _ => panic!("cannot start emulator for: {}" < target), - } - - fn add_files(w: &mut dyn Write, root: &Path, cur: &Path) { - for entry in t!(cur.read_dir()) { - let entry = t!(entry); - let path = entry.path(); - let to_print = path.strip_prefix(root).unwrap(); - t!(write!(w, "{}\u{0}", to_print.to_str().unwrap())); - if t!(entry.file_type()).is_dir() { - add_files(w, root, &path); - } + "riscv64gc-unknown-linux-gnu" => { + let mut cmd = Command::new("qemu-system-riscv64"); + cmd.arg("-nographic") + .arg("-machine") + .arg("virt") + .arg("-m") + .arg("1024") + .arg("-bios") + .arg("none") + .arg("-kernel") + .arg("/tmp/bbl") + .arg("-append") + .arg("quiet console=ttyS0 root=/dev/vda rw") + .arg("-netdev") + .arg("user,id=net0,hostfwd=tcp::12345-:12345") + .arg("-device") + .arg("virtio-net-device,netdev=net0,mac=00:00:00:00:00:00") + .arg("-device") + .arg("virtio-blk-device,drive=hd0") + .arg("-drive") + .arg(&format!("file={},format=raw,id=hd0", &rootfs_img.to_string_lossy())); + t!(cmd.spawn()); } + _ => panic!("cannot start emulator for: {}", target), } } diff --git a/src/tools/rls b/src/tools/rls -Subproject 8d7a7167c15b9154755588c39b22b2336c89ca6 +Subproject fb46b914c11b06828680cb526e2abe9e1d69b86 diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject aedff61f7ac4fc2b287ff76d33f2584e1f63a3a +Subproject c1e9b7b87493c5197c4330693bdf4ccb30a9097 |
