diff --git a/Cargo.lock b/Cargo.lock index 905f523aa53d6..d3f54fcb2c8cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3996,6 +3996,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_hir", + "rustc_hir_pretty", "rustc_index", "rustc_infer", "rustc_middle", diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 3072a4a1ae7c0..fd36cd9bd8beb 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -76,6 +76,10 @@ fn main() { cmd.env("RUST_BACKTRACE", "1"); } + if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") { + cmd.args(lint_flags.split_whitespace()); + } + if target.is_some() { // The stage0 compiler has a special sysroot distinct from what we // actually downloaded, so we just always pass the `--sysroot` option, diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3cbecbbaa06cb..c6313c19711ec 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -16,6 +16,7 @@ use build_helper::{output, t}; use crate::cache::{Cache, Interned, INTERNER}; use crate::check; use crate::compile; +use crate::config::TargetSelection; use crate::dist; use crate::doc; use crate::flags::Subcommand; @@ -86,8 +87,8 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, - pub host: Interned, - pub target: Interned, + pub host: TargetSelection, + pub target: TargetSelection, pub path: PathBuf, } @@ -576,7 +577,7 @@ impl<'a> Builder<'a> { /// not take `Compiler` since all `Compiler` instances are meant to be /// obtained through this function, since it ensures that they are valid /// (i.e., built and assembled). - pub fn compiler(&self, stage: u32, host: Interned) -> Compiler { + pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler { self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } }) } @@ -594,8 +595,8 @@ impl<'a> Builder<'a> { pub fn compiler_for( &self, stage: u32, - host: Interned, - target: Interned, + host: TargetSelection, + target: TargetSelection, ) -> Compiler { if self.build.force_use_stage1(Compiler { stage, host }, target) { self.compiler(1, self.config.build) @@ -610,15 +611,11 @@ impl<'a> Builder<'a> { /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. - pub fn sysroot_libdir( - &self, - compiler: Compiler, - target: Interned, - ) -> Interned { + pub fn sysroot_libdir(&self, compiler: Compiler, target: TargetSelection) -> Interned { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct Libdir { compiler: Compiler, - target: Interned, + target: TargetSelection, } impl Step for Libdir { type Output = Interned; @@ -633,7 +630,7 @@ impl<'a> Builder<'a> { .sysroot(self.compiler) .join(lib) .join("rustlib") - .join(self.target) + .join(self.target.triple) .join("lib"); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -656,7 +653,7 @@ impl<'a> Builder<'a> { Some(relative_libdir) if compiler.stage >= 1 => { self.sysroot(compiler).join(relative_libdir) } - _ => self.sysroot(compiler).join(libdir(&compiler.host)), + _ => self.sysroot(compiler).join(libdir(compiler.host)), } } } @@ -668,11 +665,11 @@ impl<'a> Builder<'a> { /// Windows. pub fn libdir_relative(&self, compiler: Compiler) -> &Path { if compiler.is_snapshot(self) { - libdir(&self.config.build).as_ref() + libdir(self.config.build).as_ref() } else { match self.config.libdir_relative() { Some(relative_libdir) if compiler.stage >= 1 => relative_libdir, - _ => libdir(&compiler.host).as_ref(), + _ => libdir(compiler.host).as_ref(), } } } @@ -707,7 +704,7 @@ impl<'a> Builder<'a> { if compiler.is_snapshot(self) { self.initial_rustc.clone() } else { - self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host)) + self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host)) } } @@ -741,7 +738,7 @@ impl<'a> Builder<'a> { /// /// Note that this returns `None` if LLVM is disabled, or if we're in a /// check build or dry-run, where there's no need to build all of LLVM. - fn llvm_config(&self, target: Interned) -> Option { + fn llvm_config(&self, target: TargetSelection) -> Option { if self.config.llvm_enabled() && self.kind != Kind::Check && !self.config.dry_run { let llvm_config = self.ensure(native::Llvm { target }); if llvm_config.is_file() { @@ -763,7 +760,7 @@ impl<'a> Builder<'a> { compiler: Compiler, mode: Mode, source_type: SourceType, - target: Interned, + target: TargetSelection, cmd: &str, ) -> Cargo { let mut cargo = Command::new(&self.initial_cargo); @@ -794,7 +791,7 @@ impl<'a> Builder<'a> { } if cmd != "install" { - cargo.arg("--target").arg(target); + cargo.arg("--target").arg(target.rustc_target_arg()); } else { assert_eq!(target, compiler.host); } @@ -820,7 +817,7 @@ impl<'a> Builder<'a> { compiler.stage }; - let mut rustflags = Rustflags::new(&target); + let mut rustflags = Rustflags::new(target); if stage != 0 { if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") { cargo.args(s.split_whitespace()); @@ -993,7 +990,7 @@ impl<'a> Builder<'a> { // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it // fun to pass a flag to a tool to pass a flag to pass a flag to a tool // to change a flag in a binary? - if self.config.rust_rpath && util::use_host_linker(&target) { + if self.config.rust_rpath && util::use_host_linker(target) { let rpath = if target.contains("apple") { // Note that we need to take one extra step on macOS to also pass // `-Wl,-instal_name,@rpath/...` to get things to work right. To @@ -1021,7 +1018,7 @@ impl<'a> Builder<'a> { } if let Some(target_linker) = self.linker(target, can_use_lld) { - let target = crate::envify(&target); + let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } if !(["build", "check", "clippy", "fix", "rustc"].contains(&cmd)) && want_rustdoc { @@ -1130,22 +1127,32 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); if source_type == SourceType::InTree { + let mut lint_flags = Vec::new(); // When extending this list, add the new lints to the RUSTFLAGS of the // build_bootstrap function of src/bootstrap/bootstrap.py as well as // some code doesn't go through this `rustc` wrapper. - rustflags.arg("-Wrust_2018_idioms"); - rustflags.arg("-Wunused_lifetimes"); + lint_flags.push("-Wrust_2018_idioms"); + lint_flags.push("-Wunused_lifetimes"); if self.config.deny_warnings { - rustflags.arg("-Dwarnings"); + lint_flags.push("-Dwarnings"); } // FIXME(#58633) hide "unused attribute" errors in incremental // builds of the standard library, as the underlying checks are // not yet properly integrated with incremental recompilation. if mode == Mode::Std && compiler.stage == 0 && self.config.incremental { - rustflags.arg("-Aunused-attributes"); + lint_flags.push("-Aunused-attributes"); } + // This does not use RUSTFLAGS due to caching issues with Cargo. + // Clippy is treated as an "in tree" tool, but shares the same + // cache as other "submodule" tools. With these options set in + // RUSTFLAGS, that causes *every* shared dependency to be rebuilt. + // By injecting this into the rustc wrapper, this circumvents + // Cargo's fingerprint detection. This is fine because lint flags + // are always ignored in dependencies. Eventually this should be + // fixed via better support from Cargo. + cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" ")); } if let Mode::Rustc | Mode::Codegen = mode { @@ -1182,21 +1189,23 @@ impl<'a> Builder<'a> { } }; let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc); + cargo.env(format!("CC_{}", target.triple), &cc); let cflags = self.cflags(target, GitRepo::Rustc).join(" "); - cargo.env(format!("CFLAGS_{}", target), cflags.clone()); + cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone()); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); - cargo.env(format!("AR_{}", target), ar).env(format!("RANLIB_{}", target), ranlib); + cargo + .env(format!("AR_{}", target.triple), ar) + .env(format!("RANLIB_{}", target.triple), ranlib); } if let Ok(cxx) = self.cxx(target) { let cxx = ccacheify(&cxx); cargo - .env(format!("CXX_{}", target), &cxx) - .env(format!("CXXFLAGS_{}", target), cflags); + .env(format!("CXX_{}", target.triple), &cxx) + .env(format!("CXXFLAGS_{}", target.triple), cflags); } } @@ -1230,7 +1239,7 @@ impl<'a> Builder<'a> { // Environment variables *required* throughout the build // // FIXME: should update code to not require this env var - cargo.env("CFG_COMPILER_HOST_TRIPLE", target); + cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple); // Set this for all builds to make sure doc builds also get it. cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel); @@ -1386,7 +1395,7 @@ mod tests; struct Rustflags(String); impl Rustflags { - fn new(target: &str) -> Rustflags { + fn new(target: TargetSelection) -> Rustflags { let mut ret = Rustflags(String::new()); // Inherit `RUSTFLAGS` by default ... @@ -1394,7 +1403,7 @@ impl Rustflags { // ... and also handle target-specific env RUSTFLAGS if they're // configured. - let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(target)); + let target_specific = format!("CARGO_TARGET_{}_RUSTFLAGS", crate::envify(&target.triple)); ret.env(&target_specific); ret diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 1e75e67af0c9e..69a54bec33b67 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -1,5 +1,5 @@ use super::*; -use crate::config::Config; +use crate::config::{Config, TargetSelection}; use std::thread; use pretty_assertions::assert_eq; @@ -17,16 +17,16 @@ fn configure(host: &[&str], target: &[&str]) -> Config { .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); t!(fs::create_dir_all(&dir)); config.out = dir; - config.build = INTERNER.intern_str("A"); + config.build = TargetSelection::from_user("A"); config.hosts = vec![config.build] .into_iter() - .chain(host.iter().map(|s| INTERNER.intern_str(s))) + .chain(host.iter().map(|s| TargetSelection::from_user(s))) .collect::>(); config.targets = config .hosts .clone() .into_iter() - .chain(target.iter().map(|s| INTERNER.intern_str(s))) + .chain(target.iter().map(|s| TargetSelection::from_user(s))) .collect::>(); config } @@ -41,7 +41,7 @@ fn dist_baseline() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); + let a = TargetSelection::from_user("A"); assert_eq!(first(builder.cache.all::()), &[dist::Docs { host: a },]); assert_eq!(first(builder.cache.all::()), &[dist::Mingw { host: a },]); @@ -67,8 +67,8 @@ fn dist_with_targets() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); assert_eq!( first(builder.cache.all::()), @@ -98,8 +98,8 @@ fn dist_with_hosts() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); assert_eq!( first(builder.cache.all::()), @@ -128,8 +128,8 @@ fn dist_with_hosts() { #[test] fn dist_only_cross_host() { - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); let mut build = Build::new(configure(&["B"], &[])); build.config.docs = false; build.config.extended = true; @@ -156,9 +156,9 @@ fn dist_with_targets_and_hosts() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + let c = TargetSelection::from_user("C"); assert_eq!( first(builder.cache.all::()), @@ -194,9 +194,9 @@ fn dist_with_target_flag() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + let c = TargetSelection::from_user("C"); assert_eq!( first(builder.cache.all::()), @@ -224,8 +224,8 @@ fn dist_with_same_targets_and_hosts() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); assert_eq!( first(builder.cache.all::()), @@ -277,9 +277,9 @@ fn build_default() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + let c = TargetSelection::from_user("C"); assert_eq!( first(builder.cache.all::()), @@ -318,9 +318,9 @@ fn build_with_target_flag() { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - let a = INTERNER.intern_str("A"); - let b = INTERNER.intern_str("B"); - let c = INTERNER.intern_str("C"); + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + let c = TargetSelection::from_user("C"); assert_eq!( first(builder.cache.all::()), @@ -374,7 +374,7 @@ fn test_with_no_doc_stage0() { let build = Build::new(config); let mut builder = Builder::new(&build); - let host = INTERNER.intern_str("A"); + let host = TargetSelection::from_user("A"); builder .run_step_descriptions(&[StepDescription::from::()], &["src/libstd".into()]); @@ -428,7 +428,7 @@ fn doc_default() { let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]); - let a = INTERNER.intern_str("A"); + let a = TargetSelection::from_user("A"); // error_index_generator uses stage 1 to share rustdoc artifacts with the // rustdoc tool. @@ -466,7 +466,7 @@ fn test_docs() { let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); - let a = INTERNER.intern_str("A"); + let a = TargetSelection::from_user("A"); // error_index_generator uses stage 1 to share rustdoc artifacts with the // rustdoc tool. diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index ab16ca3732c1f..7ff00d85dd2f2 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -28,16 +28,15 @@ use std::{env, iter}; use build_helper::output; -use crate::cache::Interned; -use crate::config::Target; +use crate::config::{Target, TargetSelection}; use crate::{Build, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, // so use some simplified logic here. First we respect the environment variable `AR`, then // try to infer the archiver path from the C compiler path. // In the future this logic should be replaced by calling into the `cc` crate. -fn cc2ar(cc: &Path, target: &str) -> Option { - if let Some(ar) = env::var_os(format!("AR_{}", target.replace("-", "_"))) { +fn cc2ar(cc: &Path, target: TargetSelection) -> Option { + if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace("-", "_"))) { Some(PathBuf::from(ar)) } else if let Some(ar) = env::var_os("AR") { Some(PathBuf::from(ar)) @@ -79,8 +78,8 @@ pub fn find(build: &mut Build) { .opt_level(2) .warnings(false) .debug(false) - .target(&target) - .host(&build.build); + .target(&target.triple) + .host(&build.build.triple); match build.crt_static(target) { Some(a) => { cfg.static_crt(a); @@ -106,10 +105,10 @@ pub fn find(build: &mut Build) { let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { ar } else { - cc2ar(compiler.path(), &target) + cc2ar(compiler.path(), target) }; - build.cc.insert(target, compiler); + build.cc.insert(target, compiler.clone()); let cflags = build.cflags(target, GitRepo::Rustc); // If we use llvm-libunwind, we will need a C++ compiler as well for all targets @@ -120,8 +119,8 @@ pub fn find(build: &mut Build) { .warnings(false) .debug(false) .cpp(true) - .target(&target) - .host(&build.build); + .target(&target.triple) + .host(&build.build.triple); let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) { cfg.compiler(cxx); @@ -138,14 +137,14 @@ pub fn find(build: &mut Build) { build.cxx.insert(target, compiler); } - build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target))); - build.verbose(&format!("CFLAGS_{} = {:?}", &target, cflags)); + build.verbose(&format!("CC_{} = {:?}", &target.triple, build.cc(target))); + build.verbose(&format!("CFLAGS_{} = {:?}", &target.triple, cflags)); if let Ok(cxx) = build.cxx(target) { - build.verbose(&format!("CXX_{} = {:?}", &target, cxx)); - build.verbose(&format!("CXXFLAGS_{} = {:?}", &target, cflags)); + build.verbose(&format!("CXX_{} = {:?}", &target.triple, cxx)); + build.verbose(&format!("CXXFLAGS_{} = {:?}", &target.triple, cflags)); } if let Some(ar) = ar { - build.verbose(&format!("AR_{} = {:?}", &target, ar)); + build.verbose(&format!("AR_{} = {:?}", &target.triple, ar)); build.ar.insert(target, ar); } } @@ -154,17 +153,18 @@ pub fn find(build: &mut Build) { fn set_compiler( cfg: &mut cc::Build, compiler: Language, - target: Interned, + target: TargetSelection, config: Option<&Target>, build: &Build, ) { - match &*target { + match &*target.triple { // When compiling for android we may have the NDK configured in the // config.toml in which case we look there. Otherwise the default // compiler already takes into account the triple in question. t if t.contains("android") => { if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) { let target = target + .triple .replace("armv7neon", "arm") .replace("armv7", "arm") .replace("thumbv7neon", "arm") diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0d38d2eebe793..9f34bb4e6ccd7 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -1,15 +1,15 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, std_cargo}; +use crate::config::TargetSelection; use crate::tool::{prepare_tool_cargo, SourceType}; use crate::{Compiler, Mode}; use std::path::PathBuf; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { - pub target: Interned, + pub target: TargetSelection, } fn args(kind: Kind) -> Vec { @@ -71,7 +71,7 @@ impl Step for Std { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { - pub target: Interned, + pub target: TargetSelection, } impl Step for Rustc { @@ -127,7 +127,7 @@ macro_rules! tool_check_step { ($name:ident, $path:expr, $source_type:expr) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $name { - pub target: Interned, + pub target: TargetSelection, } impl Step for $name { @@ -163,8 +163,8 @@ macro_rules! tool_check_step { println!( "Checking {} artifacts ({} -> {})", stringify!($name).to_lowercase(), - &compiler.host, - target + &compiler.host.triple, + target.triple ); run_cargo( builder, @@ -184,7 +184,7 @@ macro_rules! tool_check_step { fn stamp( builder: &Builder<'_>, compiler: Compiler, - target: Interned, + target: TargetSelection, ) -> PathBuf { builder .cargo_out(compiler, Mode::ToolRustc, target) @@ -204,12 +204,12 @@ tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned) -> PathBuf { +fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. -fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: Interned) -> PathBuf { +fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp") } diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index b4e58c06fdea9..f83dfe8e635e3 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -23,7 +23,7 @@ pub fn clean(build: &Build, all: bool) { rm_rf(&build.out.join("dist")); for host in &build.hosts { - let entries = match build.out.join(host).read_dir() { + let entries = match build.out.join(host.triple).read_dir() { Ok(iter) => iter, Err(_) => continue, }; diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9b4926f28d4ed..f3063489c1854 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -22,6 +22,7 @@ use serde::Deserialize; use crate::builder::Cargo; use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; +use crate::config::TargetSelection; use crate::dist; use crate::native; use crate::tool::SourceType; @@ -30,7 +31,7 @@ use crate::{Compiler, DependencyType, GitRepo, Mode}; #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { - pub target: Interned, + pub target: TargetSelection, pub compiler: Compiler, } @@ -129,7 +130,7 @@ fn copy_and_stamp( fn copy_third_party_objects( builder: &Builder<'_>, compiler: &Compiler, - target: Interned, + target: TargetSelection, ) -> Vec<(PathBuf, DependencyType)> { let mut target_deps = vec![]; @@ -157,7 +158,7 @@ fn copy_third_party_objects( fn copy_self_contained_objects( builder: &Builder<'_>, compiler: &Compiler, - target: Interned, + target: TargetSelection, ) -> Vec<(PathBuf, DependencyType)> { // cfg(bootstrap) // Remove when upgrading bootstrap compiler. @@ -212,7 +213,7 @@ fn copy_self_contained_objects( /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. -pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, cargo: &mut Cargo) { +pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) { if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") { cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } @@ -307,7 +308,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, ca struct StdLink { pub compiler: Compiler, pub target_compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for StdLink { @@ -343,7 +344,7 @@ impl Step for StdLink { fn copy_sanitizers( builder: &Builder<'_>, compiler: &Compiler, - target: Interned, + target: TargetSelection, ) -> Vec { let runtimes: Vec = builder.ensure(native::Sanitizers { target }); @@ -378,7 +379,7 @@ fn copy_sanitizers( #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct StartupObjects { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for StartupObjects { @@ -425,7 +426,7 @@ impl Step for StartupObjects { .arg("--cfg") .arg("bootstrap") .arg("--target") - .arg(target) + .arg(target.rustc_target_arg()) .arg("--emit=obj") .arg("-o") .arg(dst_file) @@ -444,7 +445,7 @@ impl Step for StartupObjects { #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { - pub target: Interned, + pub target: TargetSelection, pub compiler: Compiler, } @@ -524,7 +525,7 @@ impl Step for Rustc { } } -pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned) { +pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { cargo .arg("--features") .arg(builder.rustc_features()) @@ -533,7 +534,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned, cargo: &mut Cargo, target: Interned) { +pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { // Set some configuration variables picked up by build scripts and // the compiler alike cargo @@ -614,7 +615,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: Interne struct RustcLink { pub compiler: Compiler, pub target_compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for RustcLink { @@ -644,11 +645,7 @@ impl Step for RustcLink { /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -pub fn libstd_stamp( - builder: &Builder<'_>, - compiler: Compiler, - target: Interned, -) -> PathBuf { +pub fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") } @@ -657,7 +654,7 @@ pub fn libstd_stamp( pub fn librustc_stamp( builder: &Builder<'_>, compiler: Compiler, - target: Interned, + target: TargetSelection, ) -> PathBuf { builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") } @@ -665,7 +662,7 @@ pub fn librustc_stamp( pub fn compiler_file( builder: &Builder<'_>, compiler: &Path, - target: Interned, + target: TargetSelection, file: &str, ) -> PathBuf { let mut cmd = Command::new(compiler); @@ -696,9 +693,9 @@ impl Step for Sysroot { fn run(self, builder: &Builder<'_>) -> Interned { let compiler = self.compiler; let sysroot = if compiler.stage == 0 { - builder.out.join(&compiler.host).join("stage0-sysroot") + builder.out.join(&compiler.host.triple).join("stage0-sysroot") } else { - builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage)) + builder.out.join(&compiler.host.triple).join(format!("stage{}", compiler.stage)) }; let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -812,8 +809,8 @@ impl Step for Assemble { let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host); if let Some(lld_install) = lld_install { - let src_exe = exe("lld", &target_compiler.host); - let dst_exe = exe("rust-lld", &target_compiler.host); + let src_exe = exe("lld", target_compiler.host); + let dst_exe = exe("rust-lld", target_compiler.host); // we prepend this bin directory to the user PATH when linking Rust binaries. To // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. let dst = libdir.parent().unwrap().join("bin"); @@ -828,7 +825,7 @@ impl Step for Assemble { // Link the compiler binary itself into place let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); - let rustc = out_dir.join(exe("rustc_binary", &*host)); + let rustc = out_dir.join(exe("rustc_binary", host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); let compiler = builder.rustc(target_compiler); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ff545a6ddcf47..d71f31704209e 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -7,6 +7,7 @@ use std::cmp; use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::OsString; +use std::fmt; use std::fs; use std::path::{Path, PathBuf}; use std::process; @@ -39,7 +40,7 @@ pub struct Config { pub docs: bool, pub locked_deps: bool, pub vendor: bool, - pub target_config: HashMap, Target>, + pub target_config: HashMap, pub full_bootstrap: bool, pub extended: bool, pub tools: Option>, @@ -112,9 +113,9 @@ pub struct Config { pub rust_thin_lto_import_instr_limit: Option, pub rust_remap_debuginfo: bool, - pub build: Interned, - pub hosts: Vec>, - pub targets: Vec>, + pub build: TargetSelection, + pub hosts: Vec, + pub targets: Vec, pub local_rebuild: bool, pub jemalloc: bool, pub control_flow_guard: bool, @@ -158,6 +159,67 @@ pub struct Config { pub out: PathBuf, } +#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct TargetSelection { + pub triple: Interned, + file: Option>, +} + +impl TargetSelection { + pub fn from_user(selection: &str) -> Self { + let path = Path::new(selection); + + let (triple, file) = if path.exists() { + let triple = path + .file_stem() + .expect("Target specification file has no file stem") + .to_str() + .expect("Target specification file stem is not UTF-8"); + + (triple, Some(selection)) + } else { + (selection, None) + }; + + let triple = INTERNER.intern_str(triple); + let file = file.map(|f| INTERNER.intern_str(f)); + + Self { triple, file } + } + + pub fn rustc_target_arg(&self) -> &str { + self.file.as_ref().unwrap_or(&self.triple) + } + + pub fn contains(&self, needle: &str) -> bool { + self.triple.contains(needle) + } + + pub fn starts_with(&self, needle: &str) -> bool { + self.triple.starts_with(needle) + } + + pub fn ends_with(&self, needle: &str) -> bool { + self.triple.ends_with(needle) + } +} + +impl fmt::Display for TargetSelection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.triple)?; + if let Some(file) = self.file { + write!(f, "({})", file)?; + } + Ok(()) + } +} + +impl PartialEq<&str> for TargetSelection { + fn eq(&self, other: &&str) -> bool { + self.triple == *other + } +} + /// Per-target configuration stored in the global configuration structure. #[derive(Default)] pub struct Target { @@ -403,7 +465,7 @@ impl Config { config.missing_tools = false; // set by bootstrap.py - config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set")); + config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set")); config.src = Config::path_from_python("SRC"); config.out = Config::path_from_python("BUILD_DIR"); @@ -464,14 +526,16 @@ impl Config { let build = toml.build.clone().unwrap_or_default(); // set by bootstrap.py config.hosts.push(config.build.clone()); - for host in build.host.iter() { - let host = INTERNER.intern_str(host); + for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { if !config.hosts.contains(&host) { config.hosts.push(host); } } - for target in - config.hosts.iter().cloned().chain(build.target.iter().map(|s| INTERNER.intern_str(s))) + for target in config + .hosts + .iter() + .copied() + .chain(build.target.iter().map(|h| TargetSelection::from_user(h))) { if !config.targets.contains(&target) { config.targets.push(target); @@ -637,7 +701,7 @@ impl Config { target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); - config.target_config.insert(INTERNER.intern_string(triple.clone()), target); + config.target_config.insert(TargetSelection::from_user(triple), target); } } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 5d2fcba7feaba..af30747a9592e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -20,6 +20,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::channel; use crate::compile; +use crate::config::TargetSelection; use crate::tool::{self, Tool}; use crate::util::{exe, is_dylib, timeit}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; @@ -68,7 +69,7 @@ fn missing_tool(tool_name: &str, skip: bool) { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Docs { - pub host: Interned, + pub host: TargetSelection, } impl Step for Docs { @@ -131,7 +132,7 @@ impl Step for Docs { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustcDocs { - pub host: Interned, + pub host: TargetSelection, } impl Step for RustcDocs { @@ -210,11 +211,11 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec { fn make_win_dist( rust_root: &Path, plat_root: &Path, - target_triple: Interned, + target: TargetSelection, builder: &Builder<'_>, ) { //Ask gcc where it keeps its stuff - let mut cmd = Command::new(builder.cc(target_triple)); + let mut cmd = Command::new(builder.cc(target)); cmd.arg("-print-search-dirs"); let gcc_out = output(&mut cmd); @@ -234,16 +235,16 @@ fn make_win_dist( } } - let compiler = if target_triple == "i686-pc-windows-gnu" { + let compiler = if target == "i686-pc-windows-gnu" { "i686-w64-mingw32-gcc.exe" - } else if target_triple == "x86_64-pc-windows-gnu" { + } else if target == "x86_64-pc-windows-gnu" { "x86_64-w64-mingw32-gcc.exe" } else { "gcc.exe" }; let target_tools = [compiler, "ld.exe", "dlltool.exe", "libwinpthread-1.dll"]; let mut rustc_dlls = vec!["libwinpthread-1.dll"]; - if target_triple.starts_with("i686-") { + if target.starts_with("i686-") { rustc_dlls.push("libgcc_s_dw2-1.dll"); } else { rustc_dlls.push("libgcc_s_seh-1.dll"); @@ -311,7 +312,7 @@ fn make_win_dist( let target_bin_dir = plat_root .join("lib") .join("rustlib") - .join(target_triple) + .join(target.triple) .join("bin") .join("self-contained"); fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); @@ -331,7 +332,7 @@ fn make_win_dist( let target_lib_dir = plat_root .join("lib") .join("rustlib") - .join(target_triple) + .join(target.triple) .join("lib") .join("self-contained"); fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); @@ -342,7 +343,7 @@ fn make_win_dist( #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Mingw { - pub host: Interned, + pub host: TargetSelection, } impl Step for Mingw { @@ -530,11 +531,11 @@ impl Step for Rustc { // Copy over lld if it's there if builder.config.lld_enabled { - let exe = exe("rust-lld", &compiler.host); + let exe = exe("rust-lld", compiler.host); let src = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin").join(&exe); // for the rationale about this rename check `compile::copy_lld_to_sysroot` - let dst = image.join("lib/rustlib").join(&*host).join("bin").join(&exe); + let dst = image.join("lib/rustlib").join(&*host.triple).join("bin").join(&exe); t!(fs::create_dir_all(&dst.parent().unwrap())); builder.copy(&src, &dst); } @@ -592,7 +593,7 @@ impl Step for Rustc { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct DebuggerScripts { pub sysroot: Interned, - pub host: Interned, + pub host: TargetSelection, } impl Step for DebuggerScripts { @@ -662,8 +663,8 @@ 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"); +fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) { + let dst = image.join("lib/rustlib").join(target.triple).join("lib"); let self_contained_dst = dst.join("self-contained"); t!(fs::create_dir_all(&dst)); t!(fs::create_dir_all(&self_contained_dst)); @@ -679,7 +680,7 @@ fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &P #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Std { @@ -718,7 +719,7 @@ impl Step for Std { let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); let stamp = compile::libstd_stamp(builder, compiler_to_use, target); - copy_target_libs(builder, &target, &image, &stamp); + copy_target_libs(builder, target, &image, &stamp); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -747,7 +748,7 @@ impl Step for Std { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustcDev { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for RustcDev { @@ -787,7 +788,7 @@ impl Step for RustcDev { let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); let stamp = compile::librustc_stamp(builder, compiler_to_use, target); - copy_target_libs(builder, &target, &image, &stamp); + copy_target_libs(builder, target, &image, &stamp); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -818,7 +819,7 @@ impl Step for RustcDev { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Analysis { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Analysis { @@ -861,12 +862,12 @@ impl Step for Analysis { let src = builder .stage_out(compiler, Mode::Std) - .join(target) + .join(target.triple) .join(builder.cargo_dir()) .join("deps"); let image_src = src.join("save-analysis"); - let dst = image.join("lib/rustlib").join(target).join("analysis"); + let dst = image.join("lib/rustlib").join(target.triple).join("analysis"); t!(fs::create_dir_all(&dst)); builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst)); builder.cp_r(&image_src, &dst); @@ -1163,7 +1164,7 @@ pub fn sanitize_sh(path: &Path) -> String { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Cargo { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Cargo { @@ -1255,7 +1256,7 @@ impl Step for Cargo { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rls { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Rls { @@ -1345,7 +1346,7 @@ impl Step for Rls { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for RustAnalyzer { @@ -1432,7 +1433,7 @@ impl Step for RustAnalyzer { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Clippy { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Clippy { @@ -1523,7 +1524,7 @@ impl Step for Clippy { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Miri { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Miri { @@ -1620,7 +1621,7 @@ impl Step for Miri { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Rustfmt { @@ -1714,8 +1715,8 @@ impl Step for Rustfmt { #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, - host: Interned, - target: Interned, + host: TargetSelection, + target: TargetSelection, } impl Step for Extended { @@ -2255,7 +2256,7 @@ impl Step for Extended { } } -fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned) { +fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { let mut parts = channel::CFG_RELEASE_NUM.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM) @@ -2266,7 +2267,7 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned) { .env("CFG_VER_BUILD", "0") // just needed to build .env("CFG_PACKAGE_VERS", builder.rust_package_vers()) .env("CFG_PACKAGE_NAME", pkgname(builder, "rust")) - .env("CFG_BUILD", target) + .env("CFG_BUILD", target.triple) .env("CFG_CHANNEL", &builder.config.channel); if target.contains("windows-gnu") { @@ -2348,7 +2349,7 @@ impl Step for HashSign { /// /// Note: This function does not yet support Windows, but we also don't support /// linking LLVM tools dynamically on Windows yet. -fn maybe_install_llvm(builder: &Builder<'_>, target: Interned, dst_libdir: &Path) { +fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { let src_libdir = builder.llvm_out(target).join("lib"); if target.contains("apple-darwin") { @@ -2373,13 +2374,13 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: Interned, dst_libdi } /// Maybe add libLLVM.so to the target lib-dir for linking. -pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: Interned, sysroot: &Path) { - let dst_libdir = sysroot.join("lib/rustlib").join(&*target).join("lib"); +pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { + let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib"); maybe_install_llvm(builder, target, &dst_libdir); } /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself. -pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned, sysroot: &Path) { +pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); maybe_install_llvm(builder, target, &dst_libdir); @@ -2387,7 +2388,7 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: Interned, + pub target: TargetSelection, } impl Step for LlvmTools { @@ -2425,10 +2426,10 @@ impl Step for LlvmTools { // Prepare the image directory let src_bindir = builder.llvm_out(target).join("bin"); - let dst_bindir = image.join("lib/rustlib").join(&*target).join("bin"); + let dst_bindir = image.join("lib/rustlib").join(&*target.triple).join("bin"); t!(fs::create_dir_all(&dst_bindir)); for tool in LLVM_TOOLS { - let exe = src_bindir.join(exe(tool, &target)); + let exe = src_bindir.join(exe(tool, target)); builder.install(&exe, &dst_bindir, 0o755); } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 582bc9da0e804..054daa3cf4814 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -18,7 +18,7 @@ use build_helper::{t, up_to_date}; use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; -use crate::config::Config; +use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::util::symlink_dir; @@ -27,7 +27,7 @@ macro_rules! book { $( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $name { - target: Interned, + target: TargetSelection, } impl Step for $name { @@ -101,7 +101,7 @@ fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { - target: Interned, + target: TargetSelection, } impl Step for UnstableBook { @@ -129,7 +129,7 @@ impl Step for UnstableBook { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct RustbookSrc { - target: Interned, + target: TargetSelection, name: Interned, src: Interned, } @@ -169,7 +169,7 @@ impl Step for RustbookSrc { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct TheBook { compiler: Compiler, - target: Interned, + target: TargetSelection, } impl Step for TheBook { @@ -241,7 +241,7 @@ impl Step for TheBook { fn invoke_rustdoc( builder: &Builder<'_>, compiler: Compiler, - target: Interned, + target: TargetSelection, markdown: &str, ) { let out = builder.doc_out(target); @@ -277,7 +277,7 @@ fn invoke_rustdoc( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Standalone { compiler: Compiler, - target: Interned, + target: TargetSelection, } impl Step for Standalone { @@ -386,7 +386,7 @@ impl Step for Standalone { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { pub stage: u32, - pub target: Interned, + pub target: TargetSelection, } impl Step for Std { @@ -415,7 +415,7 @@ impl Step for Std { let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Std { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Std).join(target).join("doc"); + let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc"); // Here what we're doing is creating a *symlink* (directory junction on // Windows) to the final output location. This is not done as an @@ -487,7 +487,7 @@ impl Step for Std { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustc { stage: u32, - target: Interned, + target: TargetSelection, } impl Step for Rustc { @@ -531,7 +531,7 @@ impl Step for Rustc { // We do not symlink to the same shared folder that already contains std library // documentation from previous steps as we do not want to include that. - let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc"); + let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc"); t!(symlink_dir_force(&builder.config, &out, &out_dir)); // Build cargo command. @@ -568,7 +568,7 @@ impl Step for Rustc { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustdoc { stage: u32, - target: Interned, + target: TargetSelection, } impl Step for Rustdoc { @@ -613,7 +613,7 @@ impl Step for Rustdoc { builder.ensure(tool::Rustdoc { compiler }); // Symlink compiler docs to the output directory of rustdoc documentation. - let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc"); + let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc"); t!(fs::create_dir_all(&out_dir)); t!(symlink_dir_force(&builder.config, &out, &out_dir)); @@ -641,7 +641,7 @@ impl Step for Rustdoc { #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for ErrorIndex { @@ -681,7 +681,7 @@ impl Step for ErrorIndex { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBookGen { - target: Interned, + target: TargetSelection, } impl Step for UnstableBookGen { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index f477c75293385..1055689c81e6a 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -10,8 +10,7 @@ use std::process; use getopts::Options; use crate::builder::Builder; -use crate::cache::{Interned, INTERNER}; -use crate::config::Config; +use crate::config::{Config, TargetSelection}; use crate::{Build, DocTests}; /// Deserialized version of all flags for this compile. @@ -21,8 +20,8 @@ pub struct Flags { pub stage: Option, pub keep_stage: Vec, - pub host: Vec>, - pub target: Vec>, + pub host: Vec, + pub target: Vec, pub config: Option, pub jobs: Option, pub cmd: Subcommand, @@ -532,11 +531,11 @@ Arguments: .collect(), host: split(&matches.opt_strs("host")) .into_iter() - .map(|x| INTERNER.intern_string(x)) + .map(|x| TargetSelection::from_user(&x)) .collect::>(), target: split(&matches.opt_strs("target")) .into_iter() - .map(|x| INTERNER.intern_string(x)) + .map(|x| TargetSelection::from_user(&x)) .collect::>(), config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 7026b25d1b984..7266625ff39f8 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -14,46 +14,47 @@ use crate::dist::{self, pkgname, sanitize_sh, tmpdir}; use crate::Compiler; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; -use crate::config::Config; +use crate::config::{Config, TargetSelection}; -pub fn install_docs(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "docs", "rust-docs", stage, Some(host)); } -pub fn install_std(builder: &Builder<'_>, stage: u32, target: Interned) { +pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) { install_sh(builder, "std", "rust-std", stage, Some(target)); } -pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "cargo", "cargo", stage, Some(host)); } -pub fn install_rls(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "rls", "rls", stage, Some(host)); } -pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: Interned) { + +pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host)); } -pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: Interned) { + +pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "clippy", "clippy", stage, Some(host)); } -pub fn install_miri(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "miri", "miri", stage, Some(host)); } -pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "rustfmt", "rustfmt", stage, Some(host)); } -pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "analysis", "rust-analysis", stage, Some(host)); } pub fn install_src(builder: &Builder<'_>, stage: u32) { install_sh(builder, "src", "rust-src", stage, None); } -pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: Interned) { +pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) { install_sh(builder, "rustc", "rustc", stage, Some(host)); } @@ -62,7 +63,7 @@ fn install_sh( package: &str, name: &str, stage: u32, - host: Option>, + host: Option, ) { builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); @@ -150,7 +151,7 @@ macro_rules! install { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $name { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl $name { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 783a64c3581f9..05c63734b82ae 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -123,6 +123,7 @@ use std::os::windows::fs::symlink_file; use build_helper::{mtime, output, run, run_suppressed, t, try_run, try_run_suppressed}; use filetime::FileTime; +use crate::config::TargetSelection; use crate::util::{exe, libdir, CiEnv}; mod builder; @@ -187,7 +188,7 @@ const LLVM_TOOLS: &[&str] = &[ #[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)] pub struct Compiler { stage: u32, - host: Interned, + host: TargetSelection, } #[derive(PartialEq, Eq, Copy, Clone, Debug)] @@ -236,9 +237,9 @@ pub struct Build { verbosity: usize, // Targets for which to build - build: Interned, - hosts: Vec>, - targets: Vec>, + build: TargetSelection, + hosts: Vec, + targets: Vec, // Stage 0 (downloaded) compiler, lld and cargo or their local rust equivalents initial_rustc: PathBuf, @@ -248,10 +249,10 @@ pub struct Build { // Runtime state filled in later on // C/C++ compilers and archiver for all targets - cc: HashMap, cc::Tool>, - cxx: HashMap, cc::Tool>, - ar: HashMap, PathBuf>, - ranlib: HashMap, PathBuf>, + cc: HashMap, + cxx: HashMap, + ar: HashMap, + ranlib: HashMap, // Miscellaneous crates: HashMap, Crate>, is_sudo: bool, @@ -259,7 +260,7 @@ pub struct Build { delayed_failures: RefCell>, prerelease_version: Cell>, tool_artifacts: - RefCell, HashMap)>>>, + RefCell)>>>, } #[derive(Debug)] @@ -365,7 +366,7 @@ impl Build { output( Command::new(&config.initial_rustc) .arg("--target") - .arg(config.build) + .arg(config.build.rustc_target_arg()) .arg("--print") .arg("target-libdir"), ) @@ -453,7 +454,7 @@ impl Build { } pub fn build_triple(&self) -> &[Interned] { - unsafe { slice::from_raw_parts(&self.build, 1) } + slice::from_ref(&self.build.triple) } /// Executes the entire build, as configured by the flags and configuration. @@ -558,7 +559,10 @@ impl Build { } fn tools_dir(&self, compiler: Compiler) -> PathBuf { - let out = self.out.join(&*compiler.host).join(format!("stage{}-tools-bin", compiler.stage)); + let out = self + .out + .join(&*compiler.host.triple) + .join(format!("stage{}-tools-bin", compiler.stage)); t!(fs::create_dir_all(&out)); out } @@ -575,54 +579,54 @@ impl Build { Mode::ToolBootstrap => "-bootstrap-tools", Mode::ToolStd | Mode::ToolRustc => "-tools", }; - self.out.join(&*compiler.host).join(format!("stage{}{}", compiler.stage, suffix)) + self.out.join(&*compiler.host.triple).join(format!("stage{}{}", compiler.stage, suffix)) } /// Returns the root output directory for all Cargo output in a given stage, /// running a particular compiler, whether or not we're building the /// standard library, and targeting the specified architecture. - fn cargo_out(&self, compiler: Compiler, mode: Mode, target: Interned) -> PathBuf { - self.stage_out(compiler, mode).join(&*target).join(self.cargo_dir()) + fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf { + self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir()) } /// Root output directory for LLVM compiled for `target` /// /// Note that if LLVM is configured externally then the directory returned /// will likely be empty. - fn llvm_out(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("llvm") + fn llvm_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("llvm") } - fn lld_out(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("lld") + fn lld_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("lld") } /// Output directory for all documentation for a target - fn doc_out(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("doc") + fn doc_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("doc") } /// Output directory for all documentation for a target - fn compiler_doc_out(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("compiler-doc") + fn compiler_doc_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("compiler-doc") } /// Output directory for some generated md crate documentation for a target (temporary) - fn md_doc_out(&self, target: Interned) -> Interned { - INTERNER.intern_path(self.out.join(&*target).join("md-doc")) + fn md_doc_out(&self, target: TargetSelection) -> Interned { + INTERNER.intern_path(self.out.join(&*target.triple).join("md-doc")) } /// Output directory for all crate documentation for a target (temporary) /// /// The artifacts here are then copied into `doc_out` above. - fn crate_doc_out(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("crate-docs") + fn crate_doc_out(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("crate-docs") } /// Returns `true` if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. - fn is_rust_llvm(&self, target: Interned) -> bool { + fn is_rust_llvm(&self, target: TargetSelection) -> bool { match self.config.target_config.get(&target) { Some(ref c) => c.llvm_config.is_none(), None => true, @@ -630,13 +634,13 @@ impl Build { } /// Returns the path to `FileCheck` binary for the specified target - fn llvm_filecheck(&self, target: Interned) -> PathBuf { + fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf { let target_config = self.config.target_config.get(&target); if let Some(s) = target_config.and_then(|c| c.llvm_filecheck.as_ref()) { s.to_path_buf() } else if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { let llvm_bindir = output(Command::new(s).arg("--bindir")); - let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target)); + let filecheck = Path::new(llvm_bindir.trim()).join(exe("FileCheck", target)); if filecheck.exists() { filecheck } else { @@ -644,7 +648,7 @@ impl Build { // llvm subdirectory of the libdir. let llvm_libdir = output(Command::new(s).arg("--libdir")); let lib_filecheck = - Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", &*target)); + Path::new(llvm_libdir.trim()).join("llvm").join(exe("FileCheck", target)); if lib_filecheck.exists() { lib_filecheck } else { @@ -669,18 +673,18 @@ impl Build { } else { base }; - base.join("bin").join(exe("FileCheck", &*target)) + base.join("bin").join(exe("FileCheck", target)) } } /// Directory for libraries built from C/C++ code and shared between stages. - fn native_dir(&self, target: Interned) -> PathBuf { - self.out.join(&*target).join("native") + fn native_dir(&self, target: TargetSelection) -> PathBuf { + self.out.join(&*target.triple).join("native") } /// Root output directory for rust_test_helpers library compiled for /// `target` - fn test_helpers_out(&self, target: Interned) -> PathBuf { + fn test_helpers_out(&self, target: TargetSelection) -> PathBuf { self.native_dir(target).join("rust-test-helpers") } @@ -693,7 +697,7 @@ impl Build { /// Returns the libdir of the snapshot compiler. fn rustc_snapshot_libdir(&self) -> PathBuf { - self.rustc_snapshot_sysroot().join(libdir(&self.config.build)) + self.rustc_snapshot_sysroot().join(libdir(self.config.build)) } /// Returns the sysroot of the snapshot compiler. @@ -791,13 +795,13 @@ impl Build { } /// Returns the path to the C compiler for the target specified. - fn cc(&self, target: Interned) -> &Path { + fn cc(&self, target: TargetSelection) -> &Path { self.cc[&target].path() } /// Returns a list of flags to pass to the C compiler for the target /// specified. - fn cflags(&self, target: Interned, which: GitRepo) -> Vec { + fn cflags(&self, target: TargetSelection, which: GitRepo) -> Vec { // Filter out -O and /O (the optimization flags) that we picked up from // cc-rs because the build scripts will determine that for themselves. let mut base = self.cc[&target] @@ -818,7 +822,7 @@ impl Build { // Work around an apparently bad MinGW / GCC optimization, // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936 - if &*target == "i686-pc-windows-gnu" { + if &*target.triple == "i686-pc-windows-gnu" { base.push("-fno-omit-frame-pointer".into()); } @@ -836,17 +840,17 @@ impl Build { } /// Returns the path to the `ar` archive utility for the target specified. - fn ar(&self, target: Interned) -> Option<&Path> { + fn ar(&self, target: TargetSelection) -> Option<&Path> { self.ar.get(&target).map(|p| &**p) } /// Returns the path to the `ranlib` utility for the target specified. - fn ranlib(&self, target: Interned) -> Option<&Path> { + fn ranlib(&self, target: TargetSelection) -> Option<&Path> { self.ranlib.get(&target).map(|p| &**p) } /// Returns the path to the C++ compiler for the target specified. - fn cxx(&self, target: Interned) -> Result<&Path, String> { + fn cxx(&self, target: TargetSelection) -> Result<&Path, String> { match self.cxx.get(&target) { Some(p) => Ok(p.path()), None => { @@ -856,12 +860,12 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: Interned, can_use_lld: bool) -> Option<&Path> { + fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) } else if target != self.config.build - && util::use_host_linker(&target) + && util::use_host_linker(target) && !target.contains("msvc") { Some(self.cc(target)) @@ -873,7 +877,7 @@ impl Build { } /// Returns if this target should statically link the C runtime, if specified - fn crt_static(&self, target: Interned) -> Option { + fn crt_static(&self, target: TargetSelection) -> Option { if target.contains("pc-windows-msvc") { Some(true) } else { @@ -882,7 +886,7 @@ impl Build { } /// Returns the "musl root" for this `target`, if defined - fn musl_root(&self, target: Interned) -> Option<&Path> { + fn musl_root(&self, target: TargetSelection) -> Option<&Path> { self.config .target_config .get(&target) @@ -892,7 +896,7 @@ impl Build { } /// Returns the "musl libdir" for this `target`. - fn musl_libdir(&self, target: Interned) -> Option { + fn musl_libdir(&self, target: TargetSelection) -> Option { let t = self.config.target_config.get(&target)?; if let libdir @ Some(_) = &t.musl_libdir { return libdir.clone(); @@ -901,18 +905,18 @@ impl Build { } /// Returns the sysroot for the wasi target, if defined - fn wasi_root(&self, target: Interned) -> Option<&Path> { + fn wasi_root(&self, target: TargetSelection) -> Option<&Path> { self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p) } /// Returns `true` if this is a no-std `target`, if defined - fn no_std(&self, target: Interned) -> Option { + fn no_std(&self, target: TargetSelection) -> Option { self.config.target_config.get(&target).map(|t| t.no_std) } /// Returns `true` if the target will be tested using the `remote-test-client` /// and `remote-test-server` binaries. - fn remote_tested(&self, target: Interned) -> bool { + fn remote_tested(&self, target: TargetSelection) -> bool { self.qemu_rootfs(target).is_some() || target.contains("android") || env::var_os("TEST_DEVICE_ADDR").is_some() @@ -923,7 +927,7 @@ impl Build { /// /// If `Some` is returned then that means that tests for this target are /// emulated with QEMU and binaries will need to be shipped to the emulator. - fn qemu_rootfs(&self, target: Interned) -> Option<&Path> { + fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> { self.config.target_config.get(&target).and_then(|t| t.qemu_rootfs.as_ref()).map(|p| &**p) } @@ -955,7 +959,7 @@ impl Build { /// /// When all of these conditions are met the build will lift artifacts from /// the previous stage forward. - fn force_use_stage1(&self, compiler: Compiler, target: Interned) -> bool { + fn force_use_stage1(&self, compiler: Compiler, target: TargetSelection) -> bool { !self.config.full_bootstrap && compiler.stage >= 2 && (self.hosts.iter().any(|h| *h == target) || target == self.build) @@ -1065,7 +1069,7 @@ impl Build { self.rust_version() } - fn llvm_link_tools_dynamically(&self, target: Interned) -> bool { + fn llvm_link_tools_dynamically(&self, target: TargetSelection) -> bool { target.contains("linux-gnu") || target.contains("apple-darwin") } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index e8ec575ea3746..bc71242b619db 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -19,8 +19,8 @@ use std::process::Command; use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; use crate::channel; +use crate::config::TargetSelection; use crate::util::{self, exe}; use crate::GitRepo; use build_helper::up_to_date; @@ -41,7 +41,7 @@ pub struct Meta { // if not). pub fn prebuilt_llvm_config( builder: &Builder<'_>, - target: Interned, + target: TargetSelection, ) -> Result { // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. @@ -54,13 +54,14 @@ pub fn prebuilt_llvm_config( let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); + let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); if !builder.config.build.contains("msvc") || builder.config.ninja { llvm_config_ret_dir.push("build"); } llvm_config_ret_dir.push("bin"); - let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", &*builder.config.build)); + let build_llvm_config = llvm_config_ret_dir.join(exe("llvm-config", builder.config.build)); let stamp = out_dir.join("llvm-finished-building"); let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha()); @@ -93,7 +94,7 @@ pub fn prebuilt_llvm_config( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { - pub target: Interned, + pub target: TargetSelection, } impl Step for Llvm { @@ -165,8 +166,8 @@ impl Step for Llvm { .define("LLVM_ENABLE_BINDINGS", "OFF") .define("LLVM_ENABLE_Z3_SOLVER", "OFF") .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) - .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) - .define("LLVM_DEFAULT_TARGET_TRIPLE", target); + .define("LLVM_TARGET_ARCH", target.triple.split('-').next().unwrap()) + .define("LLVM_DEFAULT_TARGET_TRIPLE", target.triple); if !target.contains("netbsd") { cfg.define("LLVM_ENABLE_ZLIB", "ON"); @@ -339,7 +340,7 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { fn configure_cmake( builder: &Builder<'_>, - target: Interned, + target: TargetSelection, cfg: &mut cmake::Config, use_compiler_launcher: bool, ) { @@ -350,7 +351,7 @@ fn configure_cmake( if builder.config.ninja { cfg.generator("Ninja"); } - cfg.target(&target).host(&builder.config.build); + cfg.target(&target.triple).host(&builder.config.build.triple); let sanitize_cc = |cc: &Path| { if target.contains("msvc") { @@ -380,7 +381,7 @@ fn configure_cmake( cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc)) .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc)); cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap()) - .env("SCCACHE_TARGET", target) + .env("SCCACHE_TARGET", target.triple) .env("SCCACHE_CC", &cc) .env("SCCACHE_CXX", &cxx); @@ -480,7 +481,7 @@ fn configure_cmake( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Lld { - pub target: Interned, + pub target: TargetSelection, } impl Step for Lld { @@ -553,8 +554,8 @@ impl Step for Lld { // brittle and will break over time. If anyone knows better how to // cross-compile LLD it would be much appreciated to fix this! if target != builder.config.build { - cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build) - .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target) + cfg.env("LLVM_CONFIG_SHIM_REPLACE", &builder.config.build.triple) + .env("LLVM_CONFIG_SHIM_REPLACE_WITH", &target.triple) .define( "LLVM_TABLEGEN_EXE", llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION), @@ -574,7 +575,7 @@ impl Step for Lld { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TestHelpers { - pub target: Interned, + pub target: TargetSelection, } impl Step for TestHelpers { @@ -621,8 +622,8 @@ impl Step for TestHelpers { cfg.cargo_metadata(false) .out_dir(&dst) - .target(&target) - .host(&builder.config.build) + .target(&target.triple) + .host(&builder.config.build.triple) .opt_level(0) .warnings(false) .debug(false) @@ -633,7 +634,7 @@ impl Step for TestHelpers { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Sanitizers { - pub target: Interned, + pub target: TargetSelection, } impl Step for Sanitizers { @@ -684,7 +685,7 @@ impl Step for Sanitizers { let mut cfg = cmake::Config::new(&compiler_rt_dir); cfg.profile("Release"); - cfg.define("CMAKE_C_COMPILER_TARGET", self.target); + cfg.define("CMAKE_C_COMPILER_TARGET", self.target.triple); cfg.define("COMPILER_RT_BUILD_BUILTINS", "OFF"); cfg.define("COMPILER_RT_BUILD_CRT", "OFF"); cfg.define("COMPILER_RT_BUILD_LIBFUZZER", "OFF"); @@ -727,7 +728,7 @@ pub struct SanitizerRuntime { /// Returns sanitizers available on a given target. fn supported_sanitizers( out_dir: &Path, - target: Interned, + target: TargetSelection, channel: &str, ) -> Vec { let darwin_libs = |os: &str, components: &[&str]| -> Vec { @@ -753,7 +754,7 @@ fn supported_sanitizers( .collect() }; - match &*target { + match &*target.triple { "aarch64-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), "aarch64-unknown-linux-gnu" => { common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan"]) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 3301d41cfeefa..f89bef50de982 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -183,7 +183,11 @@ pub fn check(build: &mut Build) { panic!("the iOS target is only supported on macOS"); } - build.config.target_config.entry(target.clone()).or_insert(Target::from_triple(target)); + build + .config + .target_config + .entry(target.clone()) + .or_insert(Target::from_triple(&target.triple)); if target.contains("-none-") || target.contains("nvptx") { if build.no_std(*target) == Some(false) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 1916d96bed71d..b6641180c92c0 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -16,6 +16,7 @@ use build_helper::{self, output, t}; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; +use crate::config::TargetSelection; use crate::dist; use crate::flags::Subcommand; use crate::native; @@ -93,7 +94,7 @@ fn try_run_quiet(builder: &Builder<'_>, cmd: &mut Command) -> bool { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Linkcheck { - host: Interned, + host: TargetSelection, } impl Step for Linkcheck { @@ -115,7 +116,7 @@ impl Step for Linkcheck { let _time = util::timeit(&builder); try_run( builder, - builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host).join("doc")), + builder.tool_cmd(Tool::Linkchecker).arg(builder.out.join(host.triple).join("doc")), ); } @@ -132,7 +133,7 @@ impl Step for Linkcheck { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Cargotest { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Cargotest { @@ -177,7 +178,7 @@ impl Step for Cargotest { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Cargo { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Cargo { @@ -230,7 +231,7 @@ impl Step for Cargo { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rls { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Rls { @@ -281,7 +282,7 @@ impl Step for Rls { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustfmt { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Rustfmt { @@ -338,7 +339,7 @@ impl Step for Rustfmt { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Miri { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Miri { @@ -464,7 +465,7 @@ impl Step for Miri { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CompiletestTest { - host: Interned, + host: TargetSelection, } impl Step for CompiletestTest { @@ -501,7 +502,7 @@ impl Step for CompiletestTest { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Clippy { stage: u32, - host: Interned, + host: TargetSelection, } impl Step for Clippy { @@ -542,8 +543,10 @@ impl Step for Clippy { cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir()); - let target_libs = - builder.stage_out(compiler, Mode::ToolRustc).join(&self.host).join(builder.cargo_dir()); + let target_libs = builder + .stage_out(compiler, Mode::ToolRustc) + .join(&self.host.triple) + .join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); cargo.env("TARGET_LIBS", target_libs); // clippy tests need to find the driver @@ -607,7 +610,7 @@ impl Step for RustdocTheme { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSStd { - pub target: Interned, + pub target: TargetSelection, } impl Step for RustdocJSStd { @@ -646,8 +649,8 @@ impl Step for RustdocJSStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { - pub host: Interned, - pub target: Interned, + pub host: TargetSelection, + pub target: TargetSelection, pub compiler: Compiler, } @@ -683,8 +686,8 @@ impl Step for RustdocJSNotStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { - pub host: Interned, - pub target: Interned, + pub host: TargetSelection, + pub target: TargetSelection, pub compiler: Compiler, } @@ -785,8 +788,8 @@ impl Step for ExpandYamlAnchors { } } -fn testdir(builder: &Builder<'_>, host: Interned) -> PathBuf { - builder.out.join(host).join("test") +fn testdir(builder: &Builder<'_>, host: TargetSelection) -> PathBuf { + builder.out.join(host.triple).join("test") } macro_rules! default_test { @@ -855,7 +858,7 @@ macro_rules! test_definitions { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $name { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for $name { @@ -943,7 +946,7 @@ default_test!(Assembly { path: "src/test/assembly", mode: "assembly", suite: "as #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] struct Compiletest { compiler: Compiler, - target: Interned, + target: TargetSelection, mode: &'static str, suite: &'static str, path: &'static str, @@ -1023,8 +1026,8 @@ impl Step for Compiletest { cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target)); cmd.arg("--mode").arg(mode); - cmd.arg("--target").arg(target); - cmd.arg("--host").arg(&*compiler.host); + cmd.arg("--target").arg(target.rustc_target_arg()); + cmd.arg("--host").arg(&*compiler.host.triple); cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); if builder.config.cmd.bless() { @@ -1543,7 +1546,7 @@ impl Step for RustcGuide { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CrateLibrustc { compiler: Compiler, - target: Interned, + target: TargetSelection, test_kind: TestKind, krate: Interned, } @@ -1589,7 +1592,7 @@ impl Step for CrateLibrustc { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CrateNotDefault { compiler: Compiler, - target: Interned, + target: TargetSelection, test_kind: TestKind, krate: &'static str, } @@ -1638,7 +1641,7 @@ impl Step for CrateNotDefault { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, pub mode: Mode, pub test_kind: TestKind, pub krate: Interned, @@ -1750,17 +1753,17 @@ impl Step for Crate { if target.contains("emscripten") { cargo.env( - format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), builder.config.nodejs.as_ref().expect("nodejs not configured"), ); } else if target.starts_with("wasm32") { let node = builder.config.nodejs.as_ref().expect("nodejs not configured"); let runner = format!("{} {}/src/etc/wasm32-shim.js", node.display(), builder.src.display()); - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); + cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), &runner); } else if builder.remote_tested(target) { cargo.env( - format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), format!("{} run 0", builder.tool_exe(Tool::RemoteTestClient).display()), ); } @@ -1776,7 +1779,7 @@ impl Step for Crate { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct CrateRustdoc { - host: Interned, + host: TargetSelection, test_kind: TestKind, } @@ -1883,7 +1886,7 @@ impl Step for CrateRustdoc { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct RemoteCopyLibs { compiler: Compiler, - target: Interned, + target: TargetSelection, } impl Step for RemoteCopyLibs { @@ -1911,7 +1914,7 @@ impl Step for RemoteCopyLibs { // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); let mut cmd = Command::new(&tool); - cmd.arg("spawn-emulator").arg(target).arg(&server).arg(builder.out.join("tmp")); + cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.out.join("tmp")); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } @@ -1966,7 +1969,9 @@ impl Step for Distcheck { .current_dir(&dir), ); builder.run( - Command::new(build_helper::make(&builder.config.build)).arg("check").current_dir(&dir), + Command::new(build_helper::make(&builder.config.build.triple)) + .arg("check") + .current_dir(&dir), ); // Now make sure that rust-src has all of libstd's dependencies diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 450b534d5dfdb..f66061975d64d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -7,10 +7,10 @@ use std::process::{exit, Command}; use build_helper::t; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; use crate::channel; use crate::channel::GitInfo; use crate::compile; +use crate::config::TargetSelection; use crate::toolstate::ToolState; use crate::util::{add_dylib_path, exe}; use crate::Compiler; @@ -25,7 +25,7 @@ pub enum SourceType { #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct ToolBuild { compiler: Compiler, - target: Interned, + target: TargetSelection, tool: &'static str, path: &'static str, mode: Mode, @@ -111,7 +111,7 @@ impl Step for ToolBuild { .and_then(|p| p.file_name()) .and_then(|p| p.to_str()) .unwrap(); - if maybe_target != &*target { + if maybe_target != &*target.triple { continue; } } @@ -208,8 +208,8 @@ impl Step for ToolBuild { } } else { let cargo_out = - builder.cargo_out(compiler, self.mode, target).join(exe(tool, &compiler.host)); - let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host)); + builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host)); + let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host)); builder.copy(&cargo_out, &bin); Some(bin) } @@ -220,7 +220,7 @@ pub fn prepare_tool_cargo( builder: &Builder<'_>, compiler: Compiler, mode: Mode, - target: Interned, + target: TargetSelection, command: &'static str, path: &'static str, source_type: SourceType, @@ -303,7 +303,7 @@ macro_rules! bootstrap_tool { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $name { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for $name { @@ -416,7 +416,7 @@ impl Step for ErrorIndex { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RemoteTestServer { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for RemoteTestServer { @@ -476,7 +476,7 @@ impl Step for Rustdoc { if !target_compiler.is_snapshot(builder) { panic!("rustdoc in stage 0 must be snapshot rustdoc"); } - return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host)); + return builder.initial_rustc.with_file_name(exe("rustdoc", target_compiler.host)); } let target = target_compiler.host; // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise @@ -514,14 +514,14 @@ impl Step for Rustdoc { // rustdoc a different name. let tool_rustdoc = builder .cargo_out(build_compiler, Mode::ToolRustc, target) - .join(exe("rustdoc_tool_binary", &target_compiler.host)); + .join(exe("rustdoc_tool_binary", target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { let sysroot = builder.sysroot(target_compiler); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); - let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host)); + let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host)); let _ = fs::remove_file(&bin_rustdoc); builder.copy(&tool_rustdoc, &bin_rustdoc); bin_rustdoc @@ -534,7 +534,7 @@ impl Step for Rustdoc { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Cargo { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, } impl Step for Cargo { @@ -583,7 +583,7 @@ macro_rules! tool_extended { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { pub compiler: Compiler, - pub target: Interned, + pub target: TargetSelection, pub extra_features: Vec, } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2bc6f1939d97b..a307ef39d03a8 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -14,17 +14,16 @@ use std::time::Instant; use build_helper::t; use crate::builder::Builder; -use crate::cache::Interned; -use crate::config::Config; +use crate::config::{Config, TargetSelection}; /// Returns the `name` as the filename of a static library for `target`. -pub fn staticlib(name: &str, target: &str) -> String { +pub fn staticlib(name: &str, target: TargetSelection) -> String { if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) } } /// Given an executable called `name`, return the filename for the /// executable for a particular target. -pub fn exe(name: &str, target: &str) -> String { +pub fn exe(name: &str, target: TargetSelection) -> String { if target.contains("windows") { format!("{}.exe", name) } else { name.to_string() } } @@ -35,7 +34,7 @@ pub fn is_dylib(name: &str) -> bool { /// Returns the corresponding relative library directory that the compiler's /// dylibs will be found in. -pub fn libdir(target: &str) -> &'static str { +pub fn libdir(target: TargetSelection) -> &'static str { if target.contains("windows") { "bin" } else { "lib" } } @@ -294,7 +293,7 @@ pub fn forcing_clang_based_tests() -> bool { } } -pub fn use_host_linker(target: &Interned) -> bool { +pub fn use_host_linker(target: TargetSelection) -> bool { // FIXME: this information should be gotten by checking the linker flavor // of the rustc target !(target.contains("emscripten") diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 820c0a49e7f03..c7496c209bcb0 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -148,6 +148,7 @@ #![feature(associated_type_bounds)] #![feature(const_type_id)] #![feature(const_caller_location)] +#![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 #![feature(unsafe_block_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index fdcfae8530a3b..6ddd41a26f122 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -84,11 +84,8 @@ impl !Send for *mut T {} #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( - on(parent_trait = "std::path::Path", label = "borrow the `Path` instead"), message = "the size for values of type `{Self}` cannot be known at compilation time", - label = "doesn't have a size known at compile-time", - note = "to learn more, visit " + label = "doesn't have a size known at compile-time" )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index d1d7a71523822..39d4aca636a05 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -2,6 +2,7 @@ use super::*; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; use crate::mem; +use crate::slice::SliceIndex; #[lang = "const_ptr"] impl *const T { @@ -826,6 +827,55 @@ impl *const [T] { // Only `std` can make this guarantee. unsafe { Repr { rust: self }.raw }.len } + + /// Returns a raw pointer to the slice's buffer. + /// + /// This is equivalent to casting `self` to `*const T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get)] + /// use std::ptr; + /// + /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); + /// assert_eq!(slice.as_ptr(), 0 as *const i8); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_ptr(self) -> *const T { + self as *const T + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get)] + /// + /// let x = &[1, 2, 4] as *const [i32]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), x.as_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked(self, index: I) -> *const I::Output + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + unsafe { index.get_unchecked(self) } + } } // Equality for pointers diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 7d4b6339b511f..644465d7d17f8 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -1,6 +1,7 @@ use super::*; use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; +use crate::slice::SliceIndex; #[lang = "mut_ptr"] impl *mut T { @@ -1014,7 +1015,6 @@ impl *mut [T] { /// /// ```rust /// #![feature(slice_ptr_len)] - /// /// use std::ptr; /// /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); @@ -1028,6 +1028,55 @@ impl *mut [T] { // Only `std` can make this guarantee. unsafe { Repr { rust_mut: self }.raw }.len } + + /// Returns a raw pointer to the slice's buffer. + /// + /// This is equivalent to casting `self` to `*mut T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get)] + /// use std::ptr; + /// + /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); + /// assert_eq!(slice.as_mut_ptr(), 0 as *mut i8); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_mut_ptr(self) -> *mut T { + self as *mut T + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get)] + /// + /// let x = &mut [1, 2, 4] as *mut [i32]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked_mut(1), x.as_mut_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> *mut I::Output + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + unsafe { index.get_unchecked_mut(self) } + } } // Equality for pointers diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index c2d31bfb6a4ee..b362a49d604e7 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -6,6 +6,7 @@ use crate::marker::Unsize; use crate::mem; use crate::ops::{CoerceUnsized, DispatchFromDyn}; use crate::ptr::Unique; +use crate::slice::SliceIndex; /// `*mut T` but non-zero and covariant. /// @@ -192,7 +193,6 @@ impl NonNull<[T]> { /// /// ```rust /// #![feature(slice_ptr_len, nonnull_slice_from_raw_parts)] - /// /// use std::ptr::NonNull; /// /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); @@ -204,6 +204,57 @@ impl NonNull<[T]> { pub const fn len(self) -> usize { self.as_ptr().len() } + + /// Returns a non-null pointer to the slice's buffer. + /// + /// # Examples + /// + /// ```rust + /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// use std::ptr::NonNull; + /// + /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3); + /// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap()); + /// ``` + #[inline] + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] + pub const fn as_non_null_ptr(self) -> NonNull { + // SAFETY: We know `self` is non-null. + unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) } + } + + /// Returns a raw pointer to an element or subslice, without doing bounds + /// checking. + /// + /// Calling this method with an out-of-bounds index or when `self` is not dereferencable + /// is *[undefined behavior]* even if the resulting pointer is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)] + /// use std::ptr::NonNull; + /// + /// let x = &mut [1, 2, 4]; + /// let x = NonNull::slice_from_raw_parts(NonNull::new(x.as_mut_ptr()).unwrap(), x.len()); + /// + /// unsafe { + /// assert_eq!(x.get_unchecked_mut(1).as_ptr(), x.as_non_null_ptr().as_ptr().add(1)); + /// } + /// ``` + #[unstable(feature = "slice_ptr_get", issue = "74265")] + #[inline] + pub unsafe fn get_unchecked_mut(self, index: I) -> NonNull + where + I: SliceIndex<[T]>, + { + // SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds. + // As a consequence, the resulting pointer cannot be NULL. + unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) } + } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index bed8495993f43..0e202bb7801cf 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -310,8 +310,10 @@ impl [T] { where I: SliceIndex, { - // SAFETY: the caller must uphold the safety requirements for `get_unchecked`. - unsafe { index.get_unchecked(self) } + // SAFETY: the caller must uphold most of the safety requirements for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*index.get_unchecked(self) } } /// Returns a mutable reference to an element or subslice, without doing @@ -342,8 +344,10 @@ impl [T] { where I: SliceIndex, { - // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`. - unsafe { index.get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *index.get_unchecked_mut(self) } } /// Returns a raw pointer to the slice's buffer. @@ -3010,6 +3014,9 @@ mod private_slice_index { } /// A helper trait used for indexing operations. +/// +/// Implementations of this trait have to promise that if the argument +/// to `get_(mut_)unchecked` is a safe reference, then so is the result. #[stable(feature = "slice_get_slice", since = "1.28.0")] #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), @@ -3021,7 +3028,7 @@ see chapter in The Book : private_slice_index::Sealed { +pub unsafe trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] type Output: ?Sized; @@ -3038,21 +3045,21 @@ pub trait SliceIndex: private_slice_index::Sealed { /// Returns a shared reference to the output at this location, without /// performing any bounds checking. - /// Calling this method with an out-of-bounds index is *[undefined behavior]* - /// even if the resulting reference is not used. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. - /// Calling this method with an out-of-bounds index is *[undefined behavior]* - /// even if the resulting reference is not used. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. /// /// [undefined behavior]: ../../reference/behavior-considered-undefined.html #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; + unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. @@ -3068,33 +3075,32 @@ pub trait SliceIndex: private_slice_index::Sealed { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for usize { +unsafe impl SliceIndex<[T]> for usize { type Output = T; #[inline] fn get(self, slice: &[T]) -> Option<&T> { - if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None } + if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &T { - // SAFETY: `slice` cannot be longer than `isize::MAX` and - // the caller guarantees that `self` is in bounds of `slice` - // so `self` cannot overflow an `isize`, so the call to `add` is safe. - // The obtained pointer comes from a reference which is guaranteed - // to be valid. - unsafe { &*slice.as_ptr().add(self) } + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { // SAFETY: see comments for `get_unchecked` above. - unsafe { &mut *slice.as_mut_ptr().add(self) } + unsafe { slice.as_mut_ptr().add(self) } } #[inline] @@ -3111,7 +3117,7 @@ impl SliceIndex<[T]> for usize { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::Range { +unsafe impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -3119,7 +3125,7 @@ impl SliceIndex<[T]> for ops::Range { if self.start > self.end || self.end > slice.len() { None } else { - unsafe { Some(self.get_unchecked(slice)) } + unsafe { Some(&*self.get_unchecked(slice)) } } } @@ -3128,24 +3134,25 @@ impl SliceIndex<[T]> for ops::Range { if self.start > self.end || self.end > slice.len() { None } else { - unsafe { Some(self.get_unchecked_mut(slice)) } + unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - // SAFETY: `slice` cannot be longer than `isize::MAX` and - // the caller guarantees that `self` is in bounds of `slice` - // so `self` cannot overflow an `isize`, so the call to `add` is safe. - // Also, since the caller guarantees that `self` is in bounds of `slice`, - // `from_raw_parts` will give a subslice of `slice` which is always safe. - unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: see comments for `get_unchecked` above. - unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } + unsafe { + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + } } #[inline] @@ -3155,7 +3162,7 @@ impl SliceIndex<[T]> for ops::Range { } else if self.end > slice.len() { slice_index_len_fail(self.end, slice.len()); } - unsafe { self.get_unchecked(slice) } + unsafe { &*self.get_unchecked(slice) } } #[inline] @@ -3165,12 +3172,12 @@ impl SliceIndex<[T]> for ops::Range { } else if self.end > slice.len() { slice_index_len_fail(self.end, slice.len()); } - unsafe { self.get_unchecked_mut(slice) } + unsafe { &mut *self.get_unchecked_mut(slice) } } } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeTo { +unsafe impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -3184,13 +3191,13 @@ impl SliceIndex<[T]> for ops::RangeTo { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (0..self.end).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (0..self.end).get_unchecked_mut(slice) } } @@ -3207,7 +3214,7 @@ impl SliceIndex<[T]> for ops::RangeTo { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeFrom { +unsafe impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -3221,13 +3228,13 @@ impl SliceIndex<[T]> for ops::RangeFrom { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (self.start..slice.len()).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } } @@ -3244,7 +3251,7 @@ impl SliceIndex<[T]> for ops::RangeFrom { } #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -impl SliceIndex<[T]> for ops::RangeFull { +unsafe impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -3258,12 +3265,12 @@ impl SliceIndex<[T]> for ops::RangeFull { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { slice } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { slice } @@ -3279,7 +3286,7 @@ impl SliceIndex<[T]> for ops::RangeFull { } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl SliceIndex<[T]> for ops::RangeInclusive { +unsafe impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -3297,13 +3304,13 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } @@ -3326,7 +3333,7 @@ impl SliceIndex<[T]> for ops::RangeInclusive { } #[stable(feature = "inclusive_range", since = "1.26.0")] -impl SliceIndex<[T]> for ops::RangeToInclusive { +unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] @@ -3340,13 +3347,13 @@ impl SliceIndex<[T]> for ops::RangeToInclusive { } #[inline] - unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. unsafe { (0..=self.end).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. unsafe { (0..=self.end).get_unchecked_mut(slice) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 003ed7df36e2a..89233259a04db 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1731,7 +1731,8 @@ Section: Trait implementations mod traits { use crate::cmp::Ordering; use crate::ops; - use crate::slice::{self, SliceIndex}; + use crate::ptr; + use crate::slice::SliceIndex; /// Implements ordering of strings. /// @@ -1822,7 +1823,7 @@ mod traits { /// /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeFull { + unsafe impl SliceIndex for ops::RangeFull { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -1833,11 +1834,11 @@ mod traits { Some(slice) } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { slice } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { slice } #[inline] @@ -1886,7 +1887,7 @@ mod traits { /// // &s[3 .. 100]; /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::Range { + unsafe impl SliceIndex for ops::Range { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -1894,8 +1895,10 @@ mod traits { && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { - // SAFETY: just checked that `start` and `end` are on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + // We also checked char boundaries, so this is valid UTF-8. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -1907,34 +1910,28 @@ mod traits { && slice.is_char_boundary(self.end) { // SAFETY: just checked that `start` and `end` are on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // We know the pointer is unique because we got it from `slice`. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = self.end - self.start; - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.start` and `self.end` are char boundaries. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } + ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; // SAFETY: see comments for `get_unchecked`. let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = self.end - self.start; - // SAFETY: mostly identical to the comments for `get_unchecked`, except that we - // can return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1949,8 +1946,9 @@ mod traits { && slice.is_char_boundary(self.start) && slice.is_char_boundary(self.end) { - // SAFETY: just checked that `start` and `end` are on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, self.start, self.end) } @@ -1973,13 +1971,14 @@ mod traits { /// Panics if `end` does not point to the starting byte offset of a /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeTo { + unsafe impl SliceIndex for ops::RangeTo { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -1987,30 +1986,24 @@ mod traits { #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; let ptr = slice.as_ptr(); - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.end` is a char boundary. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) } + ptr::slice_from_raw_parts(ptr, self.end) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; let ptr = slice.as_mut_ptr(); - // SAFETY: mostly identical to `get_unchecked`, except that we can safely - // return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) } + ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2020,8 +2013,9 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, 0, self.end) } @@ -2045,13 +2039,14 @@ mod traits { /// Panics if `begin` does not point to the starting byte offset of /// a character (as defined by `is_char_boundary`), or if `begin >= len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] - impl SliceIndex for ops::RangeFrom { + unsafe impl SliceIndex for ops::RangeFrom { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - Some(unsafe { self.get_unchecked(slice) }) + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) } else { None } @@ -2059,35 +2054,29 @@ mod traits { #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - Some(unsafe { self.get_unchecked_mut(slice) }) + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) } else { None } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = slice.len() - self.start; - // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, - // we can safely construct a subslice with `from_raw_parts` and use it - // since we return a shared thus immutable reference. - // The call to `from_utf8_unchecked` is safe since the data comes from - // a `str` which is guaranteed to be valid utf8, since the caller - // must guarantee that `self.start` is a char boundary. - unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } + ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; // SAFETY: identical to `get_unchecked`. let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = slice.len() - self.start; - // SAFETY: mostly identical to `get_unchecked`, except that we can safely - // return a mutable reference since the caller passed a mutable reference - // and is thus guaranteed to have exclusive write access to `slice`. - unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2097,8 +2086,9 @@ mod traits { #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary. - unsafe { self.get_unchecked_mut(slice) } + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } } else { super::slice_error_fail(slice, self.start, slice.len()) } @@ -2122,7 +2112,7 @@ mod traits { /// to the ending byte offset of a character (`end + 1` is either a starting /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] - impl SliceIndex for ops::RangeInclusive { + unsafe impl SliceIndex for ops::RangeInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -2141,12 +2131,12 @@ mod traits { } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked`. unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } @@ -2181,7 +2171,7 @@ mod traits { /// (`end + 1` is either a starting byte offset as defined by /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] - impl SliceIndex for ops::RangeToInclusive { + unsafe impl SliceIndex for ops::RangeToInclusive { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { @@ -2192,12 +2182,12 @@ mod traits { if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } } #[inline] - unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked`. unsafe { (..self.end + 1).get_unchecked(slice) } } #[inline] - unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. unsafe { (..self.end + 1).get_unchecked_mut(slice) } } @@ -2560,8 +2550,10 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { i.get_unchecked(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*i.get_unchecked(self) } } /// Returns a mutable, unchecked subslice of `str`. @@ -2593,8 +2585,10 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { i.get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *i.get_unchecked_mut(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2644,8 +2638,10 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (begin..end).get_unchecked(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &*(begin..end).get_unchecked(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2676,8 +2672,10 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (begin..end).get_unchecked_mut(self) } + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`; + // the slice is dereferencable because `self` is a safe reference. + // The returned pointer is safe because impls of `SliceIndex` have to guarantee that it is. + unsafe { &mut *(begin..end).get_unchecked_mut(self) } } /// Divide one string slice into two at an index. diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 90a3a5ec64e0e..201972fcf264b 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -526,7 +526,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Ident::with_dummy_span(sym::_task_context), hir::BindingAnnotation::Mutable, ); - let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span }; + let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, ty_span: span, span }; let params = arena_vec![self; param]; let body_id = self.lower_body(move |this| { diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 00665c4cafb6b..dd5e658102fac 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -972,6 +972,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: self.lower_attrs(¶m.attrs), hir_id: self.lower_node_id(param.id), pat: self.lower_pat(¶m.pat), + ty_span: param.ty.span, span: param.span, } } @@ -1098,6 +1099,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: parameter.attrs, hir_id: parameter.hir_id, pat: new_parameter_pat, + ty_span: parameter.ty_span, span: parameter.span, }; diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index f687221d78e03..60aa12b0511c7 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -383,6 +383,7 @@ E0669: include_str!("./error_codes/E0669.md"), E0670: include_str!("./error_codes/E0670.md"), E0671: include_str!("./error_codes/E0671.md"), E0687: include_str!("./error_codes/E0687.md"), +E0688: include_str!("./error_codes/E0688.md"), E0689: include_str!("./error_codes/E0689.md"), E0690: include_str!("./error_codes/E0690.md"), E0691: include_str!("./error_codes/E0691.md"), @@ -450,6 +451,7 @@ E0765: include_str!("./error_codes/E0765.md"), E0766: include_str!("./error_codes/E0766.md"), E0767: include_str!("./error_codes/E0767.md"), E0768: include_str!("./error_codes/E0768.md"), +E0769: include_str!("./error_codes/E0769.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard @@ -616,7 +618,6 @@ E0768: include_str!("./error_codes/E0768.md"), E0640, // infer outlives requirements // E0645, // trait aliases not finished E0667, // `impl Trait` in projections - E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders // E0694, // an unknown tool name found in scoped attributes // E0702, // replaced with a generic attribute input check // E0707, // multiple elided lifetimes used in arguments of `async fn` diff --git a/src/librustc_error_codes/error_codes/E0688.md b/src/librustc_error_codes/error_codes/E0688.md new file mode 100644 index 0000000000000..db50f490208f4 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0688.md @@ -0,0 +1,36 @@ +In-band lifetimes were mixed with explicit lifetime binders. + +Erroneous code example: + +```compile_fail,E0688 +#![feature(in_band_lifetimes)] + +fn foo<'a>(x: &'a u32, y: &'b u32) {} // error! + +struct Foo<'a> { x: &'a u32 } + +impl Foo<'a> { + fn bar<'b>(x: &'a u32, y: &'b u32, z: &'c u32) {} // error! +} + +impl<'b> Foo<'a> { // error! + fn baz() {} +} +``` + +In-band lifetimes cannot be mixed with explicit lifetime binders. +For example: + +``` +fn foo<'a, 'b>(x: &'a u32, y: &'b u32) {} // ok! + +struct Foo<'a> { x: &'a u32 } + +impl<'a> Foo<'a> { + fn bar<'b,'c>(x: &'a u32, y: &'b u32, z: &'c u32) {} // ok! +} + +impl<'a> Foo<'a> { // ok! + fn baz() {} +} +``` diff --git a/src/librustc_error_codes/error_codes/E0718.md b/src/librustc_error_codes/error_codes/E0718.md index e7ae51ca58835..1fe62ecf1f4e0 100644 --- a/src/librustc_error_codes/error_codes/E0718.md +++ b/src/librustc_error_codes/error_codes/E0718.md @@ -1,7 +1,6 @@ -This error indicates that a `#[lang = ".."]` attribute was placed -on the wrong type of item. +A `#[lang = ".."]` attribute was placed on the wrong item type. -Examples of erroneous code: +Erroneous code example: ```compile_fail,E0718 #![feature(lang_items)] diff --git a/src/librustc_error_codes/error_codes/E0769.md b/src/librustc_error_codes/error_codes/E0769.md new file mode 100644 index 0000000000000..d1995be9899b1 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0769.md @@ -0,0 +1,39 @@ +A tuple struct or tuple variant was used in a pattern as if it were a +struct or struct variant. + +Erroneous code example: + +```compile_fail,E0769 +enum E { + A(i32), +} +let e = E::A(42); +match e { + E::A { number } => println!("{}", x), +} +``` + +To fix this error, you can use the tuple pattern: + +``` +# enum E { +# A(i32), +# } +# let e = E::A(42); +match e { + E::A(number) => println!("{}", number), +} +``` + +Alternatively, you can also use the struct pattern by using the correct +field names and binding them to new identifiers: + +``` +# enum E { +# A(i32), +# } +# let e = E::A(42); +match e { + E::A { 0: number } => println!("{}", number), +} +``` diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index f3dfec7ca7215..07b489a756267 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2148,6 +2148,7 @@ pub struct Param<'hir> { pub attrs: &'hir [Attribute], pub hir_id: HirId, pub pat: &'hir Pat<'hir>, + pub ty_span: Span, pub span: Span, } diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index fc37cb2504daa..c15c31a53f0c9 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -215,7 +215,7 @@ pub enum ObligationCauseCode<'tcx> { /// Type of each variable must be `Sized`. VariableType(hir::HirId), /// Argument type must be `Sized`. - SizedArgumentType, + SizedArgumentType(Option), /// Return type must be `Sized`. SizedReturnType, /// Yield type must be `Sized`. @@ -229,6 +229,7 @@ pub enum ObligationCauseCode<'tcx> { /// Types of fields (other than the last, except for packed structs) in a struct must be sized. FieldSized { adt_kind: AdtKind, + span: Span, last: bool, }, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index faaa576f17903..334462790edbc 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -151,12 +151,14 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::VariableType(id) => Some(super::VariableType(id)), super::ReturnValue(id) => Some(super::ReturnValue(id)), super::ReturnType => Some(super::ReturnType), - super::SizedArgumentType => Some(super::SizedArgumentType), + super::SizedArgumentType(sp) => Some(super::SizedArgumentType(sp)), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), super::InlineAsmSized => Some(super::InlineAsmSized), super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)), - super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), + super::FieldSized { adt_kind, span, last } => { + Some(super::FieldSized { adt_kind, span, last }) + } super::ConstSized => Some(super::ConstSized), super::ConstPatternStructural => Some(super::ConstPatternStructural), super::SharedStatic => Some(super::SharedStatic), diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 66ad923b8c007..82daae7d921b2 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -774,12 +774,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { (present_variants.next(), present_variants.next()) }; let present_first = match present_first { - present_first @ Some(_) => present_first, + Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), // If it's a struct, still compute a layout so that we can still compute the // field offsets. - None => Some(VariantIdx::new(0)), + None => VariantIdx::new(0), }; let is_struct = !def.is_enum() || @@ -791,7 +791,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) - let v = present_first.unwrap(); + let v = present_first; let kind = if def.is_enum() || variants[v].is_empty() { StructKind::AlwaysSized } else { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fbe3377d87500..237a5a64f8bf8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { lint: &'static lint::Lint, source_info: SourceInfo, message: &'static str, - panic: AssertKind, + panic: AssertKind, ) -> Option<()> { let lint_root = self.lint_root(source_info)?; self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { @@ -1004,11 +1004,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); let value_const = self.ecx.read_scalar(value).unwrap(); if expected != value_const { + enum DbgVal { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } let mut eval_to_int = |op| { - let op = self - .eval_operand(op, source_info) - .expect("if we got here, it must be const"); - self.ecx.read_immediate(op).unwrap().to_const_int() + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + match self.eval_operand(op, source_info) { + Some(op) => { + DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int()) + } + None => DbgVal::Underscore, + } }; let msg = match msg { AssertKind::DivisionByZero(op) => { diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/src/librustc_target/spec/linux_kernel_base.rs index 201d6a0fff93b..6d929d1244789 100644 --- a/src/librustc_target/spec/linux_kernel_base.rs +++ b/src/librustc_target/spec/linux_kernel_base.rs @@ -17,7 +17,6 @@ pub fn opts() -> TargetOptions { needs_plt: true, relro_level: RelroLevel::Full, relocation_model: RelocModel::Static, - target_family: Some("unix".to_string()), pre_link_args, ..Default::default() diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index ad6e81ed3e889..4ade1ce91632f 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -376,7 +376,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s.as_str()); - err.help(&explanation); + if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) { + // When the self type is a type param We don't need to "the trait + // `std::marker::Sized` is not implemented for `T`" as we will point + // at the type param with a label to suggest constraining it. + err.help(&explanation); + } } else { err.span_label(span, explanation); } @@ -403,7 +408,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } self.suggest_dereferences(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index d677d84b2ba13..9bcc2a885fe12 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -43,12 +43,6 @@ pub trait InferCtxtExt<'tcx> { body_id: hir::HirId, ); - fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ); - fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, @@ -515,32 +509,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a - /// suggestion to borrow the initializer in order to use have a slice instead. - fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let &ObligationCauseCode::VariableType(hir_id) = code { - let parent_node = self.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { - if let Some(ref expr) = local.init { - if let hir::ExprKind::Index(_, _) = expr.kind { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - } - } - /// Given a closure's `DefId`, return the given name of the closure. /// /// This doesn't account for reassignments, but it's only used for suggestions. @@ -1817,15 +1785,56 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - ObligationCauseCode::VariableType(_) => { - err.note("all local variables must have a statically known size"); + ObligationCauseCode::VariableType(hir_id) => { + let parent_node = self.tcx.hir().get_parent_node(hir_id); + match self.tcx.hir().find(parent_node) { + Some(Node::Local(hir::Local { + init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }), + .. + })) => { + // When encountering an assignment of an unsized trait, like + // `let x = ""[..];`, provide a suggestion to borrow the initializer in + // order to use have a slice instead. + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider borrowing here", + "&".to_owned(), + Applicability::MachineApplicable, + ); + err.note("all local variables must have a statically known size"); + } + Some(Node::Param(param)) => { + err.span_suggestion_verbose( + param.ty_span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_owned(), + Applicability::MachineApplicable, + ); + } + _ => { + err.note("all local variables must have a statically known size"); + } + } if !self.tcx.features().unsized_locals { err.help("unsized locals are gated as an unstable feature"); } } - ObligationCauseCode::SizedArgumentType => { - err.note("all function arguments must have a statically known size"); - if !self.tcx.features().unsized_locals { + ObligationCauseCode::SizedArgumentType(sp) => { + if let Some(span) = sp { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "function arguments must have a statically known size, borrowed types \ + always have a known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + } else { + err.note("all function arguments must have a statically known size"); + } + if tcx.sess.opts.unstable_features.is_nightly_build() + && !self.tcx.features().unsized_locals + { err.help("unsized locals are gated as an unstable feature"); } } @@ -1844,26 +1853,43 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::StructInitializerSized => { err.note("structs must have a statically known size to be initialized"); } - ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item { - AdtKind::Struct => { - if last { - err.note( - "the last field of a packed struct may only have a \ - dynamically sized type if it does not need drop to be run", - ); - } else { - err.note( - "only the last field of a struct may have a dynamically sized type", - ); + ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => { + match *item { + AdtKind::Struct => { + if last { + err.note( + "the last field of a packed struct may only have a \ + dynamically sized type if it does not need drop to be run", + ); + } else { + err.note( + "only the last field of a struct may have a dynamically sized type", + ); + } + } + AdtKind::Union => { + err.note("no field of a union may have a dynamically sized type"); + } + AdtKind::Enum => { + err.note("no field of an enum variant may have a dynamically sized type"); } } - AdtKind::Union => { - err.note("no field of a union may have a dynamically sized type"); - } - AdtKind::Enum => { - err.note("no field of an enum variant may have a dynamically sized type"); - } - }, + err.help("change the field's type to have a statically known size"); + err.span_suggestion( + span.shrink_to_lo(), + "borrowed types always have a statically known size", + "&".to_string(), + Applicability::MachineApplicable, + ); + err.multipart_suggestion( + "heap allocated types always have a statically known size", + vec![ + (span.shrink_to_lo(), "Box<".to_string()), + (span.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } ObligationCauseCode::ConstSized => { err.note("constant expressions must have a statically known size"); } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index 9329069c48dd1..93b503c976be4 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,6 +18,7 @@ rustc_attr = { path = "../librustc_attr" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_hir = { path = "../librustc_hir" } +rustc_hir_pretty = { path = "../librustc_hir_pretty" } rustc_target = { path = "../librustc_target" } rustc_session = { path = "../librustc_session" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5d1949626dd84..7581940b6ac69 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -3049,14 +3049,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let bare_fn_ty = ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); - if let (false, Some(ident_span)) = (self.allow_ty_infer(), ident_span) { + if !self.allow_ty_infer() { // We always collect the spans for placeholder types when evaluating `fn`s, but we // only want to emit an error complaining about them if infer types (`_`) are not // allowed. `allow_ty_infer` gates this behavior. We check for the presence of // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. crate::collect::placeholder_type_error( tcx, - ident_span.shrink_to_hi(), + ident_span.map(|sp| sp.shrink_to_hi()), &generics.params[..], visitor.0, true, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index e6b51f4c2cd2a..3956e91a16734 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -487,7 +487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized_deferred( input, expr.span, - traits::SizedArgumentType, + traits::SizedArgumentType(None), ); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index fa7360ce90051..aa768f1d251b5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1342,14 +1342,15 @@ fn check_fn<'a, 'tcx>( let inputs_fn = fn_sig.inputs().iter().copied(); for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { // Check the pattern. - fcx.check_pat_top(¶m.pat, param_ty, try { inputs_hir?.get(idx)?.span }, false); + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType); + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); } fcx.write_ty(param.hir_id, param_ty); diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index ea47ae68ce7d3..a654fc3dfc2df 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1082,20 +1082,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|ident| !used_fields.contains_key(&ident)) .collect::>(); - if !inexistent_fields.is_empty() && !variant.recovered { - self.error_inexistent_fields( + let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered { + Some(self.error_inexistent_fields( adt.variant_descr(), &inexistent_fields, &mut unmentioned_fields, variant, - ); - } + )) + } else { + None + }; // Require `..` if struct has non_exhaustive attribute. if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } + let mut unmentioned_err = None; // Report an error if incorrect number of the fields were specified. if adt.is_union() { if fields.len() != 1 { @@ -1107,7 +1110,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - self.error_unmentioned_fields(pat.span, &unmentioned_fields, variant); + unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields)); + } + match (inexistent_fields_err, unmentioned_err) { + (Some(mut i), Some(mut u)) => { + if let Some(mut e) = self.error_tuple_variant_as_struct_pat(pat, fields, variant) { + // We don't want to show the inexistent fields error when this was + // `Foo { a, b }` when it should have been `Foo(a, b)`. + i.delay_as_bug(); + u.delay_as_bug(); + e.emit(); + } else { + i.emit(); + u.emit(); + } + } + (None, Some(mut err)) | (Some(mut err), None) => { + err.emit(); + } + (None, None) => {} } no_field_errors } @@ -1154,7 +1175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inexistent_fields: &[Ident], unmentioned_fields: &mut Vec, variant: &ty::VariantDef, - ) { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; let (field_names, t, plural) = if inexistent_fields.len() == 1 { (format!("a field named `{}`", inexistent_fields[0]), "this", "") @@ -1221,15 +1242,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { it explicitly.", ); } - err.emit(); + err + } + + fn error_tuple_variant_as_struct_pat( + &self, + pat: &Pat<'_>, + fields: &'tcx [hir::FieldPat<'tcx>], + variant: &ty::VariantDef, + ) -> Option> { + if let (CtorKind::Fn, PatKind::Struct(qpath, ..)) = (variant.ctor_kind, &pat.kind) { + let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_qpath(qpath, false) + }); + let mut err = struct_span_err!( + self.tcx.sess, + pat.span, + E0769, + "tuple variant `{}` written as struct variant", + path + ); + let (sugg, appl) = if fields.len() == variant.fields.len() { + ( + fields + .iter() + .map(|f| match self.tcx.sess.source_map().span_to_snippet(f.pat.span) { + Ok(f) => f, + Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { + s.print_pat(f.pat) + }), + }) + .collect::>() + .join(", "), + Applicability::MachineApplicable, + ) + } else { + ( + variant.fields.iter().map(|_| "_").collect::>().join(", "), + Applicability::MaybeIncorrect, + ) + }; + err.span_suggestion( + pat.span, + "use the tuple variant pattern syntax instead", + format!("{}({})", path, sugg), + appl, + ); + return Some(err); + } + None } fn error_unmentioned_fields( &self, span: Span, unmentioned_fields: &[Ident], - variant: &ty::VariantDef, - ) { + ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { format!("field `{}`", unmentioned_fields[0]) } else { @@ -1248,9 +1316,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_names ); diag.span_label(span, format!("missing {}", field_names)); - if variant.ctor_kind == CtorKind::Fn { - diag.note("trying to match a tuple variant with a struct variant pattern"); - } if self.tcx.sess.teach(&diag.get_code().unwrap()) { diag.note( "This error indicates that a pattern for a struct fails to specify a \ @@ -1259,7 +1324,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ignore unwanted fields.", ); } - diag.emit(); + diag } fn check_pat_box( diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d1a86a7ee89a8..19c556942afc1 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -394,6 +394,7 @@ fn check_type_defn<'tcx, F>( Some(i) => i, None => bug!(), }, + span: field.span, last, }, ), @@ -1326,10 +1327,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .map(|field| { let field_ty = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id)); - let field_ty = self.normalize_associated_types_in(field.span, &field_ty); + let field_ty = self.normalize_associated_types_in(field.ty.span, &field_ty); let field_ty = self.resolve_vars_if_possible(&field_ty); debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty); - AdtField { ty: field_ty, span: field.span } + AdtField { ty: field_ty, span: field.ty.span } }) .collect(); AdtVariant { fields, explicit_discr: None } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 15481660a5218..625b72091a6cc 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -129,7 +129,7 @@ struct CollectItemTypesVisitor<'tcx> { /// all already existing generic type parameters to avoid suggesting a name that is already in use. crate fn placeholder_type_error( tcx: TyCtxt<'tcx>, - span: Span, + span: Option, generics: &[hir::GenericParam<'_>], placeholder_types: Vec, suggest: bool, @@ -137,12 +137,15 @@ crate fn placeholder_type_error( if placeholder_types.is_empty() { return; } - let type_name = generics.next_type_param_name(None); + let type_name = generics.next_type_param_name(None); let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); + if generics.is_empty() { - sugg.push((span, format!("<{}>", type_name))); + if let Some(span) = span { + sugg.push((span, format!("<{}>", type_name))); + } } else if let Some(arg) = generics.iter().find(|arg| match arg.name { hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true, _ => false, @@ -158,6 +161,7 @@ crate fn placeholder_type_error( format!(", {}", type_name), )); } + let mut err = bad_placeholder_type(tcx, placeholder_types); if suggest { err.multipart_suggestion( @@ -186,7 +190,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_item(item); - placeholder_type_error(tcx, generics.span, &generics.params[..], visitor.0, suggest); + placeholder_type_error(tcx, Some(generics.span), &generics.params[..], visitor.0, suggest); } impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -722,7 +726,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) { // Account for `const C: _;` and `type T = _;`. let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); + placeholder_type_error(tcx, None, &[], visitor.0, false); } hir::TraitItemKind::Type(_, None) => {} @@ -745,7 +749,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) { // Account for `type T = _;` let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, DUMMY_SP, &[], visitor.0, false); + placeholder_type_error(tcx, None, &[], visitor.0, false); } hir::ImplItemKind::Const(..) => {} } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8bba21a2e7ace..301896fd2c1ad 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -42,6 +42,7 @@ use std::str; use std::string::ToString; use std::sync::Arc; +use itertools::Itertools; use rustc_ast_pretty::pprust; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -3170,15 +3171,19 @@ const ALLOWED_ATTRIBUTES: &[Symbol] = &[ // bar: usize, // } fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) { - let mut attrs = String::new(); - - for attr in &it.attrs.other_attrs { - if !ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { - continue; - } + let attrs = it + .attrs + .other_attrs + .iter() + .filter_map(|attr| { + if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { + Some(pprust::attribute_to_string(&attr)) + } else { + None + } + }) + .join("\n"); - attrs.push_str(&pprust::attribute_to_string(&attr)); - } if !attrs.is_empty() { write!( w, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4fcf6ceb44d50..f707c1a3e1a10 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -799,6 +799,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let hir_id = self.cx.tcx.hir().as_local_hir_id(local); if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id) + && (item.visibility == Visibility::Public) && !self.cx.render_options.document_private { let item_name = item.name.as_deref().unwrap_or(""); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index b4c91cced43bf..dae8806bf2917 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -518,33 +518,80 @@ impl BufWriter { BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } } + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. fn flush_buf(&mut self) -> io::Result<()> { - let mut written = 0; - let len = self.buf.len(); - let mut ret = Ok(()); - while written < len { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete + struct BufGuard<'a> { + buffer: &'a mut Vec, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { self.panicked = true; - let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); + let r = inner.write(guard.remaining()); self.panicked = false; match r { Ok(0) => { - ret = - Err(Error::new(ErrorKind::WriteZero, "failed to write the buffered data")); - break; + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); } - Ok(n) => written += n, + Ok(n) => guard.consume(n), Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - if written > 0 { - self.buf.drain(..written); - } - ret + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer } /// Gets a reference to the underlying writer. @@ -657,13 +704,35 @@ impl Write for BufWriter { if self.buf.len() + buf.len() > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if buf.len() >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write(buf); self.panicked = false; r } else { - self.buf.write(buf) + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) } } @@ -672,13 +741,15 @@ impl Write for BufWriter { if self.buf.len() + total_len > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if total_len >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write_vectored(bufs); self.panicked = false; r } else { - self.buf.write_vectored(bufs) + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) } } @@ -710,7 +781,8 @@ impl Seek for BufWriter { /// /// Seeking always writes out the internal buffer before seeking. fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + self.flush_buf()?; + self.get_mut().seek(pos) } } @@ -816,6 +888,267 @@ impl fmt::Display for IntoInnerError { } } +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub(super) struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline; this helps prevent + // flushing partial lines on subsequent calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_all(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = buf.split_at(newline_idx + 1); + + // Write `lines` directly to the inner writer, bypassing the buffer. + self.inner_mut().write_all(lines)?; + + // Now that the write has succeeded, buffer the rest with + // BufWriter::write_all. This will buffer as much as possible, but + // continue flushing as necessary if our tail is huge. + self.buffer.write_all(tail) + } +} + /// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// @@ -883,7 +1216,6 @@ impl fmt::Display for IntoInnerError { #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, - need_flush: bool, } impl LineWriter { @@ -924,7 +1256,7 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { - LineWriter { inner: BufWriter::with_capacity(capacity, inner), need_flush: false } + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } } /// Gets a reference to the underlying writer. @@ -998,110 +1330,40 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { - self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { - IntoInnerError(LineWriter { inner: buf, need_flush: false }, e) - }) + self.inner + .into_inner() + .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { - if self.need_flush { - self.flush()?; - } - - // Find the last newline character in the buffer provided. If found then - // we're going to write all the data up to that point and then flush, - // otherwise we just write the whole block to the underlying writer. - let i = match memchr::memrchr(b'\n', buf) { - Some(i) => i, - None => return self.inner.write(buf), - }; - - // Ok, we're going to write a partial amount of the data given first - // followed by flushing the newline. After we've successfully written - // some data then we *must* report that we wrote that data, so future - // errors are ignored. We set our internal `need_flush` flag, though, in - // case flushing fails and we need to try it first next time. - let n = self.inner.write(&buf[..=i])?; - self.need_flush = true; - if self.flush().is_err() || n != i + 1 { - return Ok(n); - } + LineWriterShim::new(&mut self.inner).write(buf) + } - // At this point we successfully wrote `i + 1` bytes and flushed it out, - // meaning that the entire line is now flushed out on the screen. While - // we can attempt to finish writing the rest of the data provided. - // Remember though that we ignore errors here as we've successfully - // written data, so we need to report that. - match self.inner.write(&buf[i + 1..]) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() } - // Vectored writes are very similar to the writes above, but adjusted for - // the list of buffers that we have to write. fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - if self.need_flush { - self.flush()?; - } + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } - // Find the last newline, and failing that write the whole buffer - let last_newline = bufs.iter().enumerate().rev().find_map(|(i, buf)| { - let pos = memchr::memrchr(b'\n', buf)?; - Some((i, pos)) - }); - let (i, j) = match last_newline { - Some(pair) => pair, - None => return self.inner.write_vectored(bufs), - }; - let (prefix, suffix) = bufs.split_at(i); - let (buf, suffix) = suffix.split_at(1); - let buf = &buf[0]; - - // Write everything up to the last newline, flushing afterwards. Note - // that only if we finished our entire `write_vectored` do we try the - // subsequent - // `write` - let mut n = 0; - let prefix_amt = prefix.iter().map(|i| i.len()).sum(); - if prefix_amt > 0 { - n += self.inner.write_vectored(prefix)?; - self.need_flush = true; - } - if n == prefix_amt { - match self.inner.write(&buf[..=j]) { - Ok(m) => n += m, - Err(e) if n == 0 => return Err(e), - Err(_) => return Ok(n), - } - self.need_flush = true; - } - if self.flush().is_err() || n != j + 1 + prefix_amt { - return Ok(n); - } + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } - // ... and now write out everything remaining - match self.inner.write(&buf[j + 1..]) { - Ok(i) => n += i, - Err(_) => return Ok(n), - } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } - if suffix.iter().map(|s| s.len()).sum::() == 0 { - return Ok(n); - } - match self.inner.write_vectored(suffix) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) } - fn flush(&mut self) -> io::Result<()> { - self.inner.flush()?; - self.need_flush = false; - Ok(()) + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) } } @@ -1124,7 +1386,7 @@ where #[cfg(test)] mod tests { use crate::io::prelude::*; - use crate::io::{self, BufReader, BufWriter, IoSlice, LineWriter, SeekFrom}; + use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::thread; @@ -1133,6 +1395,9 @@ mod tests { lengths: Vec, } + // FIXME: rustfmt and tidy disagree about the correct formatting of this + // function. This leads to issues for users with editors configured to + // rustfmt-on-save. impl Read for ShortReader { fn read(&mut self, _: &mut [u8]) -> io::Result { if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } @@ -1408,34 +1673,6 @@ mod tests { assert_eq!(v, []); } - #[test] - fn test_line_buffer_fail_flush() { - // Issue #32085 - struct FailFlushWriter<'a>(&'a mut Vec); - - impl Write for FailFlushWriter<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "flush failed")) - } - } - - let mut buf = Vec::new(); - { - let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); - let to_write = b"abc\ndef"; - if let Ok(written) = writer.write(to_write) { - assert!(written < to_write.len(), "didn't flush on new line"); - // PASS - return; - } - } - assert!(buf.is_empty(), "write returned an error but wrote data"); - } - #[test] fn test_line_buffer() { let mut writer = LineWriter::new(Vec::new()); @@ -1556,41 +1793,104 @@ mod tests { b.iter(|| BufWriter::new(io::sink())); } - struct AcceptOneThenFail { - written: bool, - flushed: bool, + /// A simple `Write` target, designed to be wrapped by `LineWriter` / + /// `BufWriter` / etc, that can have its `write` & `flush` behavior + /// configured + #[derive(Default, Clone)] + struct ProgrammableSink { + // Writes append to this slice + pub buffer: Vec, + + // Flush sets this flag + pub flushed: bool, + + // If true, writes will always be an error + pub always_write_error: bool, + + // If true, flushes will always be an error + pub always_flush_error: bool, + + // If set, only up to this number of bytes will be written in a single + // call to `write` + pub accept_prefix: Option, + + // If set, counts down with each write, and writes return an error + // when it hits 0 + pub max_writes: Option, + + // If set, attempting to write when max_writes == Some(0) will be an + // error; otherwise, it will return Ok(0). + pub error_after_max_writes: bool, } - impl Write for AcceptOneThenFail { + impl Write for ProgrammableSink { fn write(&mut self, data: &[u8]) -> io::Result { - if !self.written { - assert_eq!(data, b"a\nb\n"); - self.written = true; - Ok(data.len()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "test")) + if self.always_write_error { + return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error")); + } + + match self.max_writes { + Some(0) if self.error_after_max_writes => { + return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes")); + } + Some(0) => return Ok(0), + Some(ref mut count) => *count -= 1, + None => {} } + + let len = match self.accept_prefix { + None => data.len(), + Some(prefix) => data.len().min(prefix), + }; + + let data = &data[..len]; + self.buffer.extend_from_slice(data); + + Ok(len) } fn flush(&mut self) -> io::Result<()> { - assert!(self.written); - assert!(!self.flushed); - self.flushed = true; - Err(io::Error::new(io::ErrorKind::Other, "test")) + if self.always_flush_error { + Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) + } else { + self.flushed = true; + Ok(()) + } } } + /// Previously the `LineWriter` could successfully write some bytes but + /// then fail to report that it has done so. Additionally, an erroneous + /// flush after a successful write was permanently ignored. + /// + /// Test that a line writer correctly reports the number of written bytes, + /// and that it attempts to flush buffered lines from previous writes + /// before processing new data + /// + /// Regression test for #37807 #[test] fn erroneous_flush_retried() { - let a = AcceptOneThenFail { written: false, flushed: false }; + let writer = ProgrammableSink { + // Only write up to 4 bytes at a time + accept_prefix: Some(4), + + // Accept the first two writes, then error the others + max_writes: Some(2), + error_after_max_writes: true, - let mut l = LineWriter::new(a); - assert_eq!(l.write(b"a\nb\na").unwrap(), 4); - assert!(l.get_ref().written); - assert!(l.get_ref().flushed); - l.get_mut().flushed = false; + ..Default::default() + }; + + // This should write the first 4 bytes. The rest will be buffered, out + // to the last newline. + let mut writer = LineWriter::new(writer); + assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8); - assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other) + // This write should attempt to flush "c\nd\n", then buffer "e". No + // errors should happen here because no further writes should be + // attempted against `writer`. + assert_eq!(writer.write(b"e").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n"); } #[test] @@ -1635,17 +1935,21 @@ mod tests { 0, ); assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); - assert_eq!(a.get_ref(), b"\nabaca\n"); + assert_eq!(a.get_ref(), b"\nabaca\nb"); } #[test] fn line_vectored_partial_and_errors() { + use crate::collections::VecDeque; + enum Call { Write { inputs: Vec<&'static [u8]>, output: io::Result }, Flush { output: io::Result<()> }, } + + #[derive(Default)] struct Writer { - calls: Vec, + calls: VecDeque, } impl Write for Writer { @@ -1654,19 +1958,23 @@ mod tests { } fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result { - match self.calls.pop().unwrap() { + match self.calls.pop_front().expect("unexpected call to write") { Call::Write { inputs, output } => { assert_eq!(inputs, buf.iter().map(|b| &**b).collect::>()); output } - _ => panic!("unexpected call to write"), + Call::Flush { .. } => panic!("unexpected call to write; expected a flush"), } } + fn is_write_vectored(&self) -> bool { + true + } + fn flush(&mut self) -> io::Result<()> { - match self.calls.pop().unwrap() { + match self.calls.pop_front().expect("Unexpected call to flush") { Call::Flush { output } => output, - _ => panic!("unexpected call to flush"), + Call::Write { .. } => panic!("unexpected call to flush; expected a write"), } } } @@ -1680,24 +1988,275 @@ mod tests { } // partial writes keep going - let mut a = LineWriter::new(Writer { calls: Vec::new() }); + let mut a = LineWriter::new(Writer::default()); a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) }); + + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) }); + a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); + + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); a.flush().unwrap(); // erroneous writes stop and don't write more - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) }); - assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) }); + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); + assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err()); a.flush().unwrap(); fn err() -> io::Error { io::Error::new(io::ErrorKind::Other, "x") } } + + /// Test that, in cases where vectored writing is not enabled, the + /// LineWriter uses the normal `write` call, which more-corectly handles + /// partial lines + #[test] + fn line_vectored_ignored() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + let content = [ + IoSlice::new(&[]), + IoSlice::new(b"Line 1\nLine"), + IoSlice::new(b" 2\nLine 3\nL"), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(b"ine 4"), + IoSlice::new(b"\nLine 5\n"), + ]; + + let count = writer.write_vectored(&content).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + let count = writer.write_vectored(&content[2..]).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[5..]).unwrap(); + assert_eq!(count, 5); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[6..]).unwrap(); + assert_eq!(count, 8); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref() + ); + } + + /// Test that, given this input: + /// + /// Line 1\n + /// Line 2\n + /// Line 3\n + /// Line 4 + /// + /// And given a result that only writes to midway through Line 2 + /// + /// That only up to the end of Line 3 is buffered + /// + /// This behavior is desirable because it prevents flushing partial lines + #[test] + fn partial_write_buffers_line() { + let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() }; + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2"); + + assert_eq!(writer.write(b"Line 4").unwrap(), 6); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + } + + /// Test that, given this input: + /// + /// Line 1\n + /// Line 2\n + /// Line 3 + /// + /// And given that the full write of lines 1 and 2 was successful + /// That data up to Line 3 is buffered + #[test] + fn partial_line_buffered_after_line_write() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n"); + + assert!(writer.flush().is_ok()); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3"); + } + + /// Test that, given a partial line that exceeds the length of + /// LineBuffer's buffer (that is, without a trailing newline), that that + /// line is written to the inner writer + #[test] + fn long_line_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + assert_eq!(writer.write(b"0123456789").unwrap(), 10); + assert_eq!(&writer.get_ref().buffer, b"0123456789"); + } + + /// Test that, given a very long partial line *after* successfully + /// flushing a complete line, that that line is buffered unconditionally, + /// and no additional writes take place. This assures the property that + /// `write` should make at-most-one attempt to write new data. + #[test] + fn line_long_tail_not_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + // Assert that Line 1\n is flushed, and 01234 is buffered + assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // Because the buffer is full, this subsequent write will flush it + assert_eq!(writer.write(b"5").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234"); + } + + /// Test that, if an attempt to pre-flush buffered data returns Ok(0), + /// this is propagated as an error. + #[test] + fn line_buffer_write0_error() { + let writer = ProgrammableSink { + // Accept one write, then return Ok(0) on subsequent ones + max_writes: Some(1), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will attempt to flush "partial", which will return Ok(0), which + // needs to be an error, because we've already informed the client + // that we accepted the write. + let err = writer.write(b" Line End\n").unwrap_err(); + assert_eq!(err.kind(), ErrorKind::WriteZero); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + } + + /// Test that, if a write returns Ok(0) after a successful pre-flush, this + /// is propogated as Ok(0) + #[test] + fn line_buffer_write0_normal() { + let writer = ProgrammableSink { + // Accept two writes, then return Ok(0) on subsequent ones + max_writes: Some(2), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will flush partial, which will succeed, but then return Ok(0) + // when flushing " Line End\n" + assert_eq!(writer.write(b" Line End\n").unwrap(), 0); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial"); + } + + /// LineWriter has a custom `write_all`; make sure it works correctly + #[test] + fn line_write_all() { + let writer = ProgrammableSink { + // Only write 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap(); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n"); + writer.write_all(b" Line 5\n").unwrap(); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(), + ); + } + + #[test] + fn line_write_all_error() { + let writer = ProgrammableSink { + // Only accept up to 3 writes of up to 5 bytes each + accept_prefix: Some(5), + max_writes: Some(3), + ..Default::default() + }; + + let mut writer = LineWriter::new(writer); + let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial"); + assert!(res.is_err()); + // An error from write_all leaves everything in an indeterminate state, + // so there's nothing else to test here + } + + /// Under certain circumstances, the old implementation of LineWriter + /// would try to buffer "to the last newline" but be forced to buffer + /// less than that, leading to inappropriate partial line writes. + /// Regression test for that issue. + #[test] + fn partial_multiline_buffering() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(10, writer); + + let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE"; + + // When content is written, LineWriter will try to write blocks A, B, + // C, and D. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B, C and D, but because its capacity is 10, + // it will only be able to buffer B and C. We don't want to buffer + // partial lines concurrent with whole lines, so the correct behavior + // is to buffer only block B (out to the newline) + assert_eq!(writer.write(content).unwrap(), 11); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n"); + } + + /// Same as test_partial_multiline_buffering, but in the event NO full lines + /// fit in the buffer, just buffer as much as possible + #[test] + fn partial_multiline_buffering_without_full_line() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(5, writer); + + let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD"; + + // When content is written, LineWriter will try to write blocks A, B, + // and C. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B and C, but because its capacity is 5, + // it will only be able to buffer part of B. Because it's not possible + // for it to buffer any complete lines, it should buffer as much of B as + // possible + assert_eq!(writer.write(content).unwrap(), 10); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB"); + } } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 0b3386c05d54b..a53e7f5cf57aa 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1732,8 +1732,72 @@ mod dyn_keyword {} // /// The [Rust equivalent of a C-style union][union]. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `union` looks like a [`struct`] in terms of declaration, but all of its +/// fields exist in the same memory, superimposed over one another. For instance, +/// if we wanted some bits in memory that we sometimes interpret as a `u32` and +/// sometimes as an `f32`, we could write: +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let mut u = IntOrFloat { f: 1.0 }; +/// // Reading the fields of an union is always unsafe +/// assert_eq!(unsafe { u.i }, 1065353216); +/// // Updating through any of the field will modify all of them +/// u.i = 1073741824; +/// assert_eq!(unsafe { u.f }, 2.0); +/// ``` +/// +/// # Matching on unions +/// +/// It is possible to use pattern matching on `union`s. A single field name must +/// be used and it must match the name of one of the `union`'s field. +/// Like reading from a `union`, pattern matching on a `union` requires `unsafe`. +/// +/// ```rust +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } +/// +/// let u = IntOrFloat { f: 1.0 }; +/// +/// unsafe { +/// match u { +/// IntOrFloat { i: 10 } => println!("Found exactly ten!"), +/// // Matching the field `f` provides an `f32`. +/// IntOrFloat { f } => println!("Found f = {} !", f), +/// } +/// } +/// ``` +/// +/// # References to union fields +/// +/// All fields in a `union` are all at the same place in memory which means +/// borrowing one borrows the entire `union`, for the same lifetime: +/// +/// ```rust,compile_fail,E0502 +/// union IntOrFloat { +/// i: u32, +/// f: f32, +/// } /// +/// let mut u = IntOrFloat { f: 1.0 }; +/// +/// let f = unsafe { &u.f }; +/// // This will not compile because the field has already been borrowed, even +/// // if only immutably +/// let i = unsafe { &mut u.i }; +/// +/// *i = 10; +/// println!("f = {} and i = {}", f, i); +/// ``` +/// +/// See the [Reference][union] for more informations on `union`s. +/// +/// [`struct`]: keyword.struct.html /// [union]: ../reference/items/unions.html -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 mod union_keyword {} diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index 8dbc31472d637..f7dd2c8d00fd2 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -16,8 +16,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -#[path = "../unix/thread_local.rs"] -pub mod thread_local; +#[path = "../unix/thread_local_key.rs"] +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs index 7bdc1be3b1702..675b82ceb775f 100644 --- a/src/libstd/sys/hermit/mod.rs +++ b/src/libstd/sys/hermit/mod.rs @@ -22,7 +22,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -37,7 +36,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; use crate::io::ErrorKind; diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/thread_local_dtor.rs similarity index 100% rename from src/libstd/sys/hermit/fast_thread_local.rs rename to src/libstd/sys/hermit/thread_local_dtor.rs diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/hermit/thread_local_key.rs similarity index 54% rename from src/libstd/sys/wasm/thread_local.rs rename to src/libstd/sys/hermit/thread_local_key.rs index f8be9863ed56f..bf1b49eb83b7e 100644 --- a/src/libstd/sys/wasm/thread_local.rs +++ b/src/libstd/sys/hermit/thread_local_key.rs @@ -2,25 +2,25 @@ pub type Key = usize; #[inline] pub unsafe fn create(_dtor: Option) -> Key { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn set(_key: Key, _value: *mut u8) { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn get(_key: Key) -> *mut u8 { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub unsafe fn destroy(_key: Key) { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } #[inline] pub fn requires_synchronized_create() -> bool { - panic!("should not be used on the wasm target"); + panic!("should not be used on the hermit target"); } diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 397dd496ae8af..a4968ff7d4f54 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -30,7 +30,7 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local_key.rs similarity index 100% rename from src/libstd/sys/sgx/thread_local.rs rename to src/libstd/sys/sgx/thread_local_key.rs diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b1688e74173d7..eddf00d3979f5 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -47,7 +47,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -68,7 +67,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/thread_local_dtor.rs similarity index 94% rename from src/libstd/sys/unix/fast_thread_local.rs rename to src/libstd/sys/unix/thread_local_dtor.rs index 8730b4de8bed2..c3275eb6f0e50 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/thread_local_dtor.rs @@ -1,6 +1,9 @@ #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "none")] +//! Provides thread-local destructors without an associated "key", which +//! can be more efficient. + // Since what appears to be glibc 2.18 this symbol has been shipped which // GCC and clang both use to invoke destructors in thread_local globals, so // let's do the same! @@ -16,7 +19,7 @@ ))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::mem; - use crate::sys_common::thread_local::register_dtor_fallback; + use crate::sys_common::thread_local_dtor::register_dtor_fallback; extern "C" { #[linkage = "extern_weak"] diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local_key.rs similarity index 100% rename from src/libstd/sys/unix/thread_local.rs rename to src/libstd/sys/unix/thread_local_key.rs diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index 0787e7098988c..1132a849e2f18 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -13,7 +13,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod io; @@ -29,7 +28,8 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/vxworks/fast_thread_local.rs b/src/libstd/sys/vxworks/thread_local_dtor.rs similarity index 82% rename from src/libstd/sys/vxworks/fast_thread_local.rs rename to src/libstd/sys/vxworks/thread_local_dtor.rs index 098668cf521dd..3f73f6c490326 100644 --- a/src/libstd/sys/vxworks/fast_thread_local.rs +++ b/src/libstd/sys/vxworks/thread_local_dtor.rs @@ -5,7 +5,3 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { use crate::sys_common::thread_local::register_dtor_fallback; register_dtor_fallback(t, dtor); } - -pub fn requires_move_before_drop() -> bool { - false -} diff --git a/src/libstd/sys/vxworks/thread_local.rs b/src/libstd/sys/vxworks/thread_local_key.rs similarity index 100% rename from src/libstd/sys/vxworks/thread_local.rs rename to src/libstd/sys/vxworks/thread_local_key.rs diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 4fe9661421b03..85f5282034ff1 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -36,8 +36,6 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; -#[path = "../wasm/fast_thread_local.rs"] -pub mod fast_thread_local; pub mod path; pub mod pipe; pub mod process; @@ -47,8 +45,10 @@ pub mod rwlock; pub mod stack_overflow; pub mod stdio; pub mod thread; -#[path = "../wasm/thread_local.rs"] -pub mod thread_local; +#[path = "../wasm/thread_local_dtor.rs"] +pub mod thread_local_dtor; +#[path = "../wasm/thread_local_key.rs"] +pub mod thread_local_key; pub mod time; #[cfg(not(test))] diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index 050e8099af4ba..6939596e52d78 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -20,7 +20,6 @@ pub mod alloc; pub mod args; pub mod cmath; pub mod env; -pub mod fast_thread_local; pub mod fs; pub mod io; pub mod memchr; @@ -32,7 +31,8 @@ pub mod process; pub mod stack_overflow; pub mod stdio; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/src/libstd/sys/wasm/fast_thread_local.rs b/src/libstd/sys/wasm/thread_local_dtor.rs similarity index 100% rename from src/libstd/sys/wasm/fast_thread_local.rs rename to src/libstd/sys/wasm/thread_local_dtor.rs diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/wasm/thread_local_key.rs similarity index 100% rename from src/libstd/sys/hermit/thread_local.rs rename to src/libstd/sys/wasm/thread_local_key.rs diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 193ab5b47ef13..9a52371280e15 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -20,7 +20,6 @@ pub mod cmath; pub mod condvar; pub mod env; pub mod ext; -pub mod fast_thread_local; pub mod fs; pub mod handle; pub mod io; @@ -35,7 +34,8 @@ pub mod process; pub mod rand; pub mod rwlock; pub mod thread; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod time; cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { diff --git a/src/libstd/sys/windows/fast_thread_local.rs b/src/libstd/sys/windows/thread_local_dtor.rs similarity index 52% rename from src/libstd/sys/windows/fast_thread_local.rs rename to src/libstd/sys/windows/thread_local_dtor.rs index 191fa07f32a55..7be13bc4b2bc7 100644 --- a/src/libstd/sys/windows/fast_thread_local.rs +++ b/src/libstd/sys/windows/thread_local_dtor.rs @@ -1,4 +1,4 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![cfg(target_thread_local)] -pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor; +pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local_key.rs similarity index 100% rename from src/libstd/sys/windows/thread_local.rs rename to src/libstd/sys/windows/thread_local_key.rs diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index e03e0fc83454b..e57bb267cbd0f 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -65,7 +65,8 @@ pub mod remutex; pub mod rwlock; pub mod thread; pub mod thread_info; -pub mod thread_local; +pub mod thread_local_dtor; +pub mod thread_local_key; pub mod util; pub mod wtf8; diff --git a/src/libstd/sys_common/thread_local_dtor.rs b/src/libstd/sys_common/thread_local_dtor.rs new file mode 100644 index 0000000000000..6f5ebf4a27158 --- /dev/null +++ b/src/libstd/sys_common/thread_local_dtor.rs @@ -0,0 +1,49 @@ +//! Thread-local destructor +//! +//! Besides thread-local "keys" (pointer-sized non-adressable thread-local store +//! with an associated destructor), many platforms also provide thread-local +//! destructors that are not associated with any particular data. These are +//! often more efficient. +//! +//! This module provides a fallback implementation for that interface, based +//! on the less efficient thread-local "keys". Each platform provides +//! a `thread_local_dtor` module which will either re-export the fallback, +//! or implement something more efficient. + +#![unstable(feature = "thread_local_internals", issue = "none")] +#![allow(dead_code)] // sys isn't exported yet + +use crate::ptr; +use crate::sys_common::thread_local_key::StaticKey; + +pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + // The fallback implementation uses a vanilla OS-based TLS key to track + // the list of destructors that need to be run for this thread. The key + // then has its own destructor which runs all the other destructors. + // + // The destructor for DTORS is a little special in that it has a `while` + // loop to continuously drain the list of registered destructors. It + // *should* be the case that this loop always terminates because we + // provide the guarantee that a TLS key cannot be set after it is + // flagged for destruction. + + static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); + type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box = Box::from_raw(ptr as *mut List); + for (ptr, dtor) in list.into_iter() { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } +} diff --git a/src/libstd/sys_common/thread_local.rs b/src/libstd/sys_common/thread_local_key.rs similarity index 85% rename from src/libstd/sys_common/thread_local.rs rename to src/libstd/sys_common/thread_local_key.rs index 756b8d044a20e..ac5b128298d78 100644 --- a/src/libstd/sys_common/thread_local.rs +++ b/src/libstd/sys_common/thread_local_key.rs @@ -4,7 +4,7 @@ //! using the native OS-provided facilities (think `TlsAlloc` or //! `pthread_setspecific`). The interface of this differs from the other types //! of thread-local-storage provided in this crate in that OS-based TLS can only -//! get/set pointers, +//! get/set pointer-sized data, possibly with an associated destructor. //! //! This module also provides two flavors of TLS. One is intended for static //! initialization, and does not contain a `Drop` implementation to deallocate @@ -14,7 +14,7 @@ //! # Usage //! //! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::spawn::Key` are likely much +//! being built on. Types such as `thread_local::spawn::Key` are likely much //! more useful in practice than this OS-based version which likely requires //! unsafe code to interoperate with. //! @@ -48,9 +48,8 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] // sys isn't exported yet -use crate::ptr; use crate::sync::atomic::{self, AtomicUsize, Ordering}; -use crate::sys::thread_local as imp; +use crate::sys::thread_local_key as imp; use crate::sys_common::mutex::Mutex; /// A type for TLS keys that are statically allocated. @@ -233,38 +232,6 @@ impl Drop for Key { } } -pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - - static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box = Box::from_raw(ptr as *mut List); - for (ptr, dtor) in list.into_iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } -} - #[cfg(test)] mod tests { use super::{Key, StaticKey}; diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 094c468a6770e..ecd6fbc6b9395 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -363,7 +363,7 @@ pub mod fast { use crate::cell::Cell; use crate::fmt; use crate::mem; - use crate::sys::fast_thread_local::register_dtor; + use crate::sys::thread_local_dtor::register_dtor; #[derive(Copy, Clone)] enum DtorState { @@ -468,7 +468,7 @@ pub mod os { use crate::fmt; use crate::marker; use crate::ptr; - use crate::sys_common::thread_local::StaticKey as OsStaticKey; + use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; pub struct Key { // OS-TLS key that we'll use to key off. diff --git a/src/llvm-project b/src/llvm-project index d134a53927fa0..86b120e6f302d 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit d134a53927fa033ae7e0f3e8ee872ff2dc71468d +Subproject commit 86b120e6f302d39cd6973b6391fb299d7bc22122 diff --git a/src/test/codegen/intrinsics/nearby.rs b/src/test/codegen/intrinsics/nearby.rs new file mode 100644 index 0000000000000..520fe2f1886eb --- /dev/null +++ b/src/test/codegen/intrinsics/nearby.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics; + +// CHECK-LABEL: @nearbyintf32 +#[no_mangle] +pub unsafe fn nearbyintf32(a: f32) -> f32 { + // CHECK: llvm.nearbyint.f32 + intrinsics::nearbyintf32(a) +} + +// CHECK-LABEL: @nearbyintf64 +#[no_mangle] +pub unsafe fn nearbyintf64(a: f64) -> f64 { + // CHECK: llvm.nearbyint.f64 + intrinsics::nearbyintf64(a) +} diff --git a/src/test/codegen/intrinsics/volatile.rs b/src/test/codegen/intrinsics/volatile.rs new file mode 100644 index 0000000000000..1970517e73262 --- /dev/null +++ b/src/test/codegen/intrinsics/volatile.rs @@ -0,0 +1,55 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics; + +// CHECK-LABEL: @volatile_copy_memory +#[no_mangle] +pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memmove.p0i8.p0i8.{{\w*(.*true)}} + intrinsics::volatile_copy_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_copy_nonoverlapping_memory +#[no_mangle] +pub unsafe fn volatile_copy_nonoverlapping_memory(a: *mut u8, b: *const u8) { + // CHECK: llvm.memcpy.p0i8.p0i8.{{\w*(.*true)}} + intrinsics::volatile_copy_nonoverlapping_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_set_memory +#[no_mangle] +pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) { + // CHECK: llvm.memset.p0i8.{{\w*(.*true)}} + intrinsics::volatile_set_memory(a, b, 1) +} + +// CHECK-LABEL: @volatile_load +#[no_mangle] +pub unsafe fn volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::volatile_load(a) +} + +// CHECK-LABEL: @volatile_store +#[no_mangle] +pub unsafe fn volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::volatile_store(a, b) +} + +// CHECK-LABEL: @unaligned_volatile_load +#[no_mangle] +pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 { + // CHECK: load volatile + intrinsics::unaligned_volatile_load(a) +} + +// CHECK-LABEL: @unaligned_volatile_store +#[no_mangle] +pub unsafe fn unaligned_volatile_store(a: *mut u8, b: u8) { + // CHECK: store volatile + intrinsics::unaligned_volatile_store(a, b) +} diff --git a/src/test/codegen/intrinsics/volatile_order.rs b/src/test/codegen/intrinsics/volatile_order.rs new file mode 100644 index 0000000000000..29331219ba6ee --- /dev/null +++ b/src/test/codegen/intrinsics/volatile_order.rs @@ -0,0 +1,18 @@ +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub unsafe fn test_volatile_order() { + let mut a: Box = Box::new(0); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: load volatile + let x = volatile_load(&*a); + // CHECK: store volatile + volatile_store(&mut *a, 12); + // CHECK: store volatile + unaligned_volatile_store(&mut *a, 12); + // CHECK: llvm.memset.p0i8 + volatile_set_memory(&mut *a, 12, 1) +} diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr new file mode 100644 index 0000000000000..03f95f19d326e --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -0,0 +1,10 @@ +warning: `[PrivateType]` public documentation for `public_item` links to a private item + --> $DIR/issue-74134.rs:19:10 + | +LL | /// [`PrivateType`] + | ^^^^^^^^^^^^^ this item is private + | + = note: `#[warn(intra_doc_link_resolution_failure)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/issue-74134.rs b/src/test/rustdoc-ui/issue-74134.rs new file mode 100644 index 0000000000000..d561c2dd89015 --- /dev/null +++ b/src/test/rustdoc-ui/issue-74134.rs @@ -0,0 +1,41 @@ +// revisions: public private +// [private]compile-flags: --document-private-items +// check-pass + +// There are 4 cases here: +// 1. public item -> public type: no warning +// 2. public item -> private type: warning, if --document-private-items is not passed +// 3. private item -> public type: no warning +// 4. private item -> private type: no warning +// All 4 cases are tested with and without --document-private-items. +// +// Case 4 without --document-private-items is the one described in issue #74134. + +struct PrivateType; +pub struct PublicType; + +pub struct Public { + /// [`PublicType`] + /// [`PrivateType`] + //[public]~^ WARNING public documentation for `public_item` links to a private + pub public_item: u32, + + /// [`PublicType`] + /// [`PrivateType`] + private_item: u32, +} + +// The following cases are identical to the ones above, except that they are in a private +// module. Thus they all fall into cases 3 and 4 and should not produce a warning. + +mod private { + pub struct Public { + /// [`super::PublicType`] + /// [`super::PrivateType`] + pub public_item: u32, + + /// [`super::PublicType`] + /// [`super::PrivateType`] + private_item: u32, + } +} diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs index e9cd3514a07e2..54c5939f908d4 100644 --- a/src/test/rustdoc/attributes.rs +++ b/src/test/rustdoc/attributes.rs @@ -8,8 +8,8 @@ pub extern "C" fn f() {} #[export_name = "bar"] pub extern "C" fn g() {} -// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[repr(i64)]' -// @has foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' '#[must_use]' +// @matches foo/enum.Foo.html '//*[@class="docblock attributes top-attr"]' \ +// '(?m)\A#\[repr\(i64\)\]\n#\[must_use\]\Z' #[repr(i64)] #[must_use] pub enum Foo { diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 7c9c041f45784..1f11d19c70ea2 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -17,7 +17,6 @@ LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -27,7 +26,6 @@ LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time @@ -37,7 +35,6 @@ LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u64]` - = note: to learn more, visit = note: all inline asm arguments must have a statically known size error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index 6daba54ac6969..e96d0e0eff719 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -5,7 +5,6 @@ LL | let x = t.get(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Value` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr index 8676c1fa22319..de0acc88324a5 100644 --- a/src/test/ui/associated-types/defaults-suitability.stderr +++ b/src/test/ui/associated-types/defaults-suitability.stderr @@ -139,7 +139,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit error: aborting due to 11 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr index 69c310766c1cc..2ba854eac4665 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized { LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { @@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized { LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `Self` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider further restricting `Self` | @@ -69,7 +67,6 @@ LL | + Display = Self; LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `T` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` | @@ -105,7 +102,6 @@ LL | + AddAssign<&'static str> LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ no implementation for `T += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` help: consider restricting type parameter `T` | LL | impl> UncheckedCopy for T {} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr index 84f0ba7529ea2..d4fd0ca98ee54 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -21,7 +21,6 @@ LL | trait UncheckedCopy: Sized { LL | + AddAssign<&'static str> | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` help: consider further restricting `Self` | LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { @@ -50,7 +49,6 @@ LL | trait UncheckedCopy: Sized { LL | + Display = Self; | ^^^^^^^ `Self` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `Self` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider further restricting `Self` | @@ -69,7 +67,6 @@ LL | + Display = Self; LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `T` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead help: consider restricting type parameter `T` | @@ -105,7 +102,6 @@ LL | + AddAssign<&'static str> LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^ no implementation for `T += &'static str` | - = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` help: consider restricting type parameter `T` | LL | impl> UncheckedCopy for T {} diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr index 82e76ff0b7cb5..be3b61665b11f 100644 --- a/src/test/ui/associated-types/issue-63593.stderr +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -6,8 +6,6 @@ LL | trait MyTrait { LL | type This = Self; | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | trait MyTrait: std::marker::Sized { diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr index a37573dffff44..7813d3b6596bf 100644 --- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -9,8 +9,6 @@ LL | trait ArithmeticOps: Add + Sub + Mul LL | pub trait Add { | --- required by this bound in `std::ops::Add` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | trait ArithmeticOps: Add + Sub + Mul + Div + std::marker::Sized {} diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr index 5fb772fa10acb..2166420070a07 100644 --- a/src/test/ui/async-await/issue-70818.stderr +++ b/src/test/ui/async-await/issue-70818.stderr @@ -7,7 +7,6 @@ LL | LL | async { (ty, ty1) } | ------------------- this returned value is of type `impl std::future::Future` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `U` note: captured value is not `Send` --> $DIR/issue-70818.rs:6:18 | diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr index 603895b598c16..762afa6450a95 100644 --- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -17,10 +17,12 @@ LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because it appears within the type `Foo` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | async fn frob(&self) {} + | ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index 81fc961e3dea0..fd3999ae6fbec 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | 1.bar::(); | ^^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider further restricting this bound | LL | fn foo() { diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 5c169af4eb8ae..47d8cc1f06fd1 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -21,7 +21,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: to learn more, visit error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 @@ -30,7 +29,6 @@ LL | let x: Vec = Vec::new(); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: to learn more, visit = note: required by `std::vec::Vec::::new` error: aborting due to 3 previous errors diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index b9bc503f5301a..623252a8c1139 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -4,7 +4,6 @@ error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `impl Sized` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -18,7 +17,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `T` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` @@ -32,7 +30,6 @@ error[E0277]: `T` doesn't implement `std::fmt::Debug` LL | println!("{:?}", t); | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `T` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -46,7 +43,6 @@ error[E0277]: `Y` doesn't implement `std::fmt::Debug` LL | println!("{:?} {:?}", x, y); | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `Y` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` @@ -60,7 +56,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `X` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound @@ -74,7 +69,6 @@ error[E0277]: `X` doesn't implement `std::fmt::Debug` LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `X` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr index dfc4999958a57..b3e7b5b4feea4 100644 --- a/src/test/ui/box-into-boxed-slice-fail.stderr +++ b/src/test/ui/box-into-boxed-slice-fail.stderr @@ -5,7 +5,6 @@ LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required by `std::boxed::Box::::into_boxed_slice` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time @@ -25,7 +23,6 @@ LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: to learn more, visit = note: required by `std::boxed::Box::::into_boxed_slice` error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time @@ -35,7 +32,6 @@ LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to 4 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 4e7b513629d05..7ff986ec38109 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -7,7 +7,6 @@ LL | LL | impl Foo for (T,) { } | ^^^ `T` cannot be sent between threads safely | - = help: within `(T,)`, the trait `std::marker::Send` is not implemented for `T` = note: required because it appears within the type `(T,)` help: consider further restricting this bound | @@ -23,7 +22,6 @@ LL | trait Foo : Send+Sync { } LL | impl Foo for (T,T) { } | ^^^ `T` cannot be shared between threads safely | - = help: within `(T, T)`, the trait `std::marker::Sync` is not implemented for `T` = note: required because it appears within the type `(T, T)` help: consider further restricting this bound | diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index 3fb1af3a67cc2..9ee045edfe546 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -9,7 +9,6 @@ LL | impl RequiresRequiresShareAndSend for X { } LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { } | ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend` | - = help: within `X`, the trait `std::marker::Send` is not implemented for `T` = note: required because it appears within the type `X` help: consider further restricting this bound | diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index 9c5073a1e49d7..ad80b3fa8d11f 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -7,7 +7,6 @@ LL | LL | impl Foo for T { } | ^^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider further restricting this bound | LL | impl Foo for T { } diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr index e5d7615e43e31..fb2e0fc1a6169 100644 --- a/src/test/ui/chalkify/impl_wf.stderr +++ b/src/test/ui/chalkify/impl_wf.stderr @@ -8,7 +8,6 @@ LL | impl Foo for str { } | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error[E0277]: the trait bound `f32: Foo` is not satisfied --> $DIR/impl_wf.rs:27:17 diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index ffd70fac6b19b..273eae995538a 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -7,7 +7,6 @@ LL | struct X where F: FnOnce() + 'static + Send { LL | fn foo(blk: F) -> X where F: FnOnce() + 'static { | ^^^^ `F` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `F` help: consider further restricting this bound | LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + std::marker::Send { diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 691864c9e1d45..7df29d5a098a0 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -7,7 +7,6 @@ LL | fn take_const_owned(_: F) where F: FnOnce() + Sync + Send { LL | take_const_owned(f); | ^ `F` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `F` help: consider further restricting this bound | LL | fn give_owned(f: F) where F: FnOnce() + Send + std::marker::Sync { diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr index 14cf64eeb7ac6..ad67a87265bd3 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.stderr @@ -16,10 +16,10 @@ LL | struct ArithArrayLen([u32; 0 + N]); = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/array-size-in-generic-struct-param.rs:14:5 + --> $DIR/array-size-in-generic-struct-param.rs:14:10 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs index 5f2d5e80243fe..a67510d15b09c 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs @@ -1,9 +1,11 @@ -// check-pass +// build-pass + +// compile-flags: --crate-type lib + +#![warn(unconditional_panic)] pub struct Fixed64(i64); pub fn div(f: Fixed64) { - f.0 / 0; + f.0 / 0; //~ WARN will panic at runtime } - -fn main() {} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr new file mode 100644 index 0000000000000..0b42f4abf344e --- /dev/null +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -0,0 +1,14 @@ +warning: this operation will panic at runtime + --> $DIR/ice-assert-fail-div-by-zero.rs:10:5 + | +LL | f.0 / 0; + | ^^^^^^^ attempt to divide _ by zero + | +note: the lint level is defined here + --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 + | +LL | #![warn(unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr index beeea87bfb1d3..bf2844cfb70d6 100644 --- a/src/test/ui/consts/const-unsized.stderr +++ b/src/test/ui/consts/const-unsized.stderr @@ -5,7 +5,6 @@ LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:6:18 @@ -14,7 +13,6 @@ LL | const CONST_FOO: str = *"foo"; | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:9:18 @@ -23,7 +21,6 @@ LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` - = note: to learn more, visit error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:12:20 @@ -32,7 +29,6 @@ LL | static STATIC_BAR: str = *"bar"; | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-bad-assign-2.stderr b/src/test/ui/dst/dst-bad-assign-2.stderr index 4e1e67c7f4809..a5374aedab86b 100644 --- a/src/test/ui/dst/dst-bad-assign-2.stderr +++ b/src/test/ui/dst/dst-bad-assign-2.stderr @@ -5,7 +5,6 @@ LL | f5.ptr = *z; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr index 0b6f9df2d83ee..f8d9300f11a31 100644 --- a/src/test/ui/dst/dst-bad-assign-3.stderr +++ b/src/test/ui/dst/dst-bad-assign-3.stderr @@ -14,7 +14,6 @@ LL | f5.2 = Bar1 {f: 36}; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr index 434c460759fb4..8e3eeefb9ea66 100644 --- a/src/test/ui/dst/dst-bad-assign.stderr +++ b/src/test/ui/dst/dst-bad-assign.stderr @@ -14,7 +14,6 @@ LL | f5.ptr = Bar1 {f: 36}; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-deep-2.stderr b/src/test/ui/dst/dst-bad-deep-2.stderr index cb2735147a35b..d9d6ca3292311 100644 --- a/src/test/ui/dst/dst-bad-deep-2.stderr +++ b/src/test/ui/dst/dst-bad-deep-2.stderr @@ -5,7 +5,6 @@ LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr index 521adf601cc70..1304f04f82062 100644 --- a/src/test/ui/dst/dst-bad-deep.stderr +++ b/src/test/ui/dst/dst-bad-deep.stderr @@ -5,7 +5,6 @@ LL | let h: &Fat> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Fat>`, the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit = note: required because it appears within the type `Fat<[isize]>` = note: required because it appears within the type `Fat>` = note: structs must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index 80d188bf2f89b..da8ead885c898 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -6,8 +6,6 @@ LL | fn test1(t: &T) { LL | let u: &dyn Foo = 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 = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `T` cannot be known at compilation time @@ -18,8 +16,6 @@ LL | fn test2(t: &T) { LL | let v: &dyn Foo = t as &dyn Foo; | ^ 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 = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -29,7 +25,6 @@ LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -39,7 +34,6 @@ LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 006a334021b14..7e90e9ce1792d 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -8,7 +8,6 @@ LL | impl Foo<[isize]> for usize { } | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[isize]` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized @@ -24,7 +23,6 @@ LL | impl Foo for [usize] { } | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[usize]` - = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index a9ea85d14cff5..203fc18915647 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/E0277.rs:13:6 | LL | fn f(p: Path) { } - | ^ borrow the `Path` instead + | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `std::path::Path` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(p: &Path) { } + | ^ error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/E0277.rs:17:15 diff --git a/src/test/ui/error-codes/E0478.stderr b/src/test/ui/error-codes/E0478.stderr index 1380840e0db2d..38736de8d9ac7 100644 --- a/src/test/ui/error-codes/E0478.stderr +++ b/src/test/ui/error-codes/E0478.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/E0478.rs:4:5 + --> $DIR/E0478.rs:4:12 | LL | child: Box + 'SnowWhite>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined on the struct at 3:22 --> $DIR/E0478.rs:3:22 diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 0c7995fde3273..8938afd33ffde 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -8,7 +8,6 @@ LL | assert_sized::(); | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() { } @@ -24,7 +23,6 @@ LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Foo` help: consider relaxing the implicit `Sized` restriction | @@ -41,7 +39,6 @@ LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Bar` help: consider relaxing the implicit `Sized` restriction | @@ -58,7 +55,6 @@ LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `Bar>`, the trait `std::marker::Sized` is not implemented for `A` - = note: to learn more, visit = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr index add3a8e79267d..5a58e57d36c70 100644 --- a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr +++ b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -5,7 +5,6 @@ LL | static symbol: [usize]; | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[usize]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index 2beeba8184a7d..987cde191cbb9 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:5 + --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index b4d4c992c9086..d4c09ec40fd92 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -95,7 +95,6 @@ LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -108,7 +107,6 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Dst<(dyn A + 'static)>` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -122,7 +120,6 @@ LL | | } | |_^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index d20b9e2981e8c..0195cc1481e74 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -5,9 +5,11 @@ LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(f: &dyn FnOnce()) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 79aeec2ec0280..379bd8ebd1cad 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -9,7 +9,6 @@ LL | | }; | |____^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the yield type of a generator must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -19,7 +18,6 @@ LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 89cc5dfd06018..2fab7ffb66050 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index efd3287853f03..186e142138be2 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index 5da924a512f00..d16bdcbbb6b00 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 12d84ab6a369b..72c42917c83c9 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -16,7 +16,6 @@ LL | type F<'a>: Fn() -> u32; LL | type F<'a> = Self; | ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T` | - = help: the trait `std::ops::Fn<()>` is not implemented for `T` = note: wrap the `T` in a closure with no arguments: `|| { /* code */ } help: consider restricting type parameter `T` | diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr index 95f4aa9e6dbaa..7a6c07d4e082e 100644 --- a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -8,7 +8,6 @@ LL | impl Tsized for () {} | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[()]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index c55dbd7d2fafe..96f961a2aaf6b 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -16,7 +16,6 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -38,7 +37,6 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | doesn't have a size known at compile-time | = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/in-band-lifetimes/E0688.stderr b/src/test/ui/in-band-lifetimes/E0688.stderr index 0078cd58001e3..afefcd9fc2c66 100644 --- a/src/test/ui/in-band-lifetimes/E0688.stderr +++ b/src/test/ui/in-band-lifetimes/E0688.stderr @@ -24,3 +24,4 @@ LL | impl<'b> Foo<'a> { error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0688`. diff --git a/src/test/ui/intrinsics/intrinsic-nearby.rs b/src/test/ui/intrinsics/intrinsic-nearby.rs new file mode 100644 index 0000000000000..7b1d1eeaadbd0 --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-nearby.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +fn main() { + unsafe { + assert_eq!(nearbyintf32(5.234f32), 5f32); + assert_eq!(nearbyintf64(6.777f64), 7f64); + } +} diff --git a/src/test/ui/intrinsics/intrinsic-volatile.rs b/src/test/ui/intrinsics/intrinsic-volatile.rs new file mode 100644 index 0000000000000..7b2c825a2084b --- /dev/null +++ b/src/test/ui/intrinsics/intrinsic-volatile.rs @@ -0,0 +1,44 @@ +// run-pass + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +pub fn main() { + unsafe { + let mut x: Box = Box::new(0); + let mut y: Box = Box::new(0); + + // test volatile load + assert_eq!(volatile_load(&*x), 0); + *x = 1; + assert_eq!(volatile_load(&*x), 1); + + // test volatile store + volatile_store(&mut *x, 2); + assert_eq!(*x, 2); + + // test volatile copy memory + volatile_copy_memory(&mut *y, &*x, 1); + assert_eq!(*y, 2); + + // test volatile copy non-overlapping memory + *x = 3; + volatile_copy_nonoverlapping_memory(&mut *y, &*x, 1); + assert_eq!(*y, 3); + + // test volatile set memory + volatile_set_memory(&mut *x, 4, 1); + assert_eq!(*x, 4); + + // test unaligned volatile load + let arr: [u8; 3] = [1, 2, 3]; + let ptr = arr[1..].as_ptr() as *const u16; + assert_eq!(unaligned_volatile_load(ptr), u16::from_ne_bytes([arr[1], arr[2]])); + + // test unaligned volatile store + let ptr = arr[1..].as_ptr() as *mut u16; + unaligned_volatile_store(ptr, 0); + assert_eq!(arr, [1, 0, 0]); + } +} diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index d7a4bf4f21f18..d241e6406d579 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -56,7 +56,6 @@ LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait Serializable<'self, T: ?Sized> { diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index 542d8a904c4e3..4e41acf433e59 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -5,7 +5,6 @@ LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::any::Any` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr index 987bc512163d6..68ceebc5b651d 100644 --- a/src/test/ui/issues/issue-15756.stderr +++ b/src/test/ui/issues/issue-15756.stderr @@ -5,7 +5,6 @@ LL | &mut something | ^^^^^^^^^ 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 = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index c3445024c3752..812778911a865 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -5,7 +5,6 @@ LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: required by `std::boxed::Box::::new` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 383cdd4979ad9..3b5dfd1ad158c 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -8,7 +8,6 @@ LL | enum Option { | - required by this bound in `Option` | = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-18919.rs:7:13 | diff --git a/src/test/ui/issues/issue-19380.stderr b/src/test/ui/issues/issue-19380.stderr index 0a080171a7951..63f0701974b8b 100644 --- a/src/test/ui/issues/issue-19380.stderr +++ b/src/test/ui/issues/issue-19380.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Qiz` cannot be made into an object - --> $DIR/issue-19380.rs:11:3 + --> $DIR/issue-19380.rs:11:9 | LL | trait Qiz { | --- this trait cannot be made into an object... @@ -7,7 +7,7 @@ LL | fn qiz(); | --- ...because associated function `qiz` has no `self` parameter ... LL | foos: &'static [&'static (dyn Qiz + 'static)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Qiz` cannot be made into an object | help: consider turning `qiz` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index 775f9702401a6..cbaa7507244a3 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -7,8 +7,6 @@ LL | trait From { LL | ) -> >::Result where Dst: From { | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | ) -> >::Result where Dst: From, Self: std::marker::Sized { diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index 1dab637e489db..0e96b12066937 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -10,7 +10,6 @@ LL | pub struct Vec { | - required by this bound in `std::vec::Vec` | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 5e050f27ac546..5e06e3bc95c36 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -5,7 +5,6 @@ LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` - = note: to learn more, visit = note: required by `std::iter::IntoIterator::into_iter` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr index 229f99f90640b..6f22fe6a99717 100644 --- a/src/test/ui/issues/issue-22874.stderr +++ b/src/test/ui/issues/issue-22874.stderr @@ -1,11 +1,10 @@ error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time - --> $DIR/issue-22874.rs:2:5 + --> $DIR/issue-22874.rs:2:11 | LL | rows: [[String]], - | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type 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 cffa52361696c..46b4be6fd3649 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -8,7 +8,6 @@ LL | struct Vec { | - required by this bound in `Vec` | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-23281.rs:8:12 | diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr index 344443e783038..d2714408d8a39 100644 --- a/src/test/ui/issues/issue-24446.stderr +++ b/src/test/ui/issues/issue-24446.stderr @@ -5,7 +5,6 @@ LL | static foo: dyn Fn() -> u32 = || -> u32 { | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index 1ddea73e00ae0..96696fabd9338 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -1,14 +1,21 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/issue-27060-2.rs:3:5 + --> $DIR/issue-27060-2.rs:3:11 | LL | pub struct Bad { | - this type parameter needs to be `std::marker::Sized` LL | data: T, - | ^^^^^^^ doesn't have a size known at compile-time + | ^ 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 = note: the last field of a packed struct may only have a dynamically sized type if it does not need drop to be run + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | data: &T, + | ^ +help: heap allocated types always have a statically known size + | +LL | data: Box, + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index 3eb9d3c62039f..de1810e99aac6 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -4,14 +4,15 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation LL | fn foo(self) -> &'static i32 { | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting `Self` | LL | fn foo(self) -> &'static i32 where Self: std::marker::Sized { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(&self) -> &'static i32 { + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 48b151c73c956..98de768a5a819 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -5,7 +5,6 @@ LL | &X(*Y) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr index 825c0de5e53ea..a137549693844 100644 --- a/src/test/ui/issues/issue-35988.stderr +++ b/src/test/ui/issues/issue-35988.stderr @@ -5,8 +5,16 @@ LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V(&[Box]), + | ^ +help: heap allocated types always have a statically known size + | +LL | V(Box<[Box]>), + | ^^^^ ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index d3168ef9e4aaf..e96bbe1a99312 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -5,9 +5,11 @@ LL | fn _test(ref _p: str) {} | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn _test(ref _p: &str) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index 9d854e4be9ead..35aa1acdc1c9b 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -5,9 +5,11 @@ LL | pub fn example(ref s: str) {} | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | pub fn example(ref s: &str) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index 0d4797a7a0673..fbe87aa2dbee5 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -5,13 +5,15 @@ LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `::Target` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | LL | fn baz(_: Self::Target) where Self: Deref, ::Target: std::marker::Sized {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn baz(_: &Self::Target) where Self: Deref {} + | ^ error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:8:10 @@ -20,9 +22,11 @@ LL | pub fn f(_: dyn ToString) {} | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` - = note: to learn more, visit - = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | pub fn f(_: &dyn ToString) {} + | ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-54410.stderr b/src/test/ui/issues/issue-54410.stderr index 992c691bf21ef..9205a518c8c3a 100644 --- a/src/test/ui/issues/issue-54410.stderr +++ b/src/test/ui/issues/issue-54410.stderr @@ -5,7 +5,6 @@ LL | pub static mut symbol: [i8]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index d886ecc11d17b..897984d0ae410 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -5,9 +5,11 @@ LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn new_struct(r: &dyn A + 'static) + | ^ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:8:8 @@ -19,7 +21,6 @@ LL | Struct { r: r } | --------------- this returned value is of type `Struct` | = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Struct` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr index 114f2d62e561a..fef64ebf2d365 100644 --- a/src/test/ui/issues/issue-65673.stderr +++ b/src/test/ui/issues/issue-65673.stderr @@ -10,7 +10,6 @@ LL | type Ctx = dyn Alias; | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` - = note: to learn more, visit error: aborting due to previous error diff --git a/src/test/ui/issues/issue-74086.rs b/src/test/ui/issues/issue-74086.rs new file mode 100644 index 0000000000000..f68a665b2f38d --- /dev/null +++ b/src/test/ui/issues/issue-74086.rs @@ -0,0 +1,4 @@ +fn main() { + static BUG: fn(_) -> u8 = |_| 8; + //~^ ERROR the type placeholder `_` is not allowed within types on item signatures [E0121] +} diff --git a/src/test/ui/issues/issue-74086.stderr b/src/test/ui/issues/issue-74086.stderr new file mode 100644 index 0000000000000..4127f48a093f4 --- /dev/null +++ b/src/test/ui/issues/issue-74086.stderr @@ -0,0 +1,12 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/issue-74086.rs:2:20 + | +LL | static BUG: fn(_) -> u8 = |_| 8; + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index cc98f1d9f34b8..ab9dfc9b8a779 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -4,7 +4,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a = &t as &dyn Gettable; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` @@ -31,7 +30,6 @@ error[E0277]: `T` cannot be sent between threads safely LL | let a: &dyn Gettable = &t; | ^^ `T` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `T` = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr index 6e19251c72800..98bf9923823d7 100644 --- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr +++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr @@ -9,8 +9,6 @@ LL | fn test() { LL | let _: [u8; sof::()]; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | pub const fn sof() -> usize { diff --git a/src/test/ui/lazy_normalization_consts/issue-57739.stderr b/src/test/ui/lazy_normalization_consts/issue-57739.stderr index 1987f5890c041..ce0495dd8b0cb 100644 --- a/src/test/ui/lazy_normalization_consts/issue-57739.stderr +++ b/src/test/ui/lazy_normalization_consts/issue-57739.stderr @@ -8,10 +8,10 @@ LL | #![feature(lazy_normalization_consts)] = note: see issue #72219 for more information error: constant expression depends on a generic parameter - --> $DIR/issue-57739.rs:12:5 + --> $DIR/issue-57739.rs:12:12 | LL | array: [u8; T::SIZE], - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: this may fail depending on what value the parameter takes diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index d682478db0eef..e5083e3a088b6 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/lifetime-doesnt-live-long-enough.rs:19:5 + --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | foo: &'static T - | ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 95936de218b8f..71abda520653e 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -209,7 +209,6 @@ LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -219,7 +218,6 @@ LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.rs b/src/test/ui/missing/missing-fields-in-struct-pattern.rs index 24b6b55db6692..40304a674a633 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.rs +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.rs @@ -2,8 +2,7 @@ struct S(usize, usize, usize, usize); fn main() { if let S { a, b, c, d } = S(1, 2, 3, 4) { - //~^ ERROR struct `S` does not have fields named `a`, `b`, `c`, `d` [E0026] - //~| ERROR pattern does not mention fields `0`, `1`, `2`, `3` [E0027] + //~^ ERROR tuple variant `S` written as struct variant println!("hi"); } } diff --git a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr index f7037468996f4..6583524aad18f 100644 --- a/src/test/ui/missing/missing-fields-in-struct-pattern.stderr +++ b/src/test/ui/missing/missing-fields-in-struct-pattern.stderr @@ -1,18 +1,9 @@ -error[E0026]: struct `S` does not have fields named `a`, `b`, `c`, `d` - --> $DIR/missing-fields-in-struct-pattern.rs:4:16 - | -LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | ^ ^ ^ ^ struct `S` does not have these fields - -error[E0027]: pattern does not mention fields `0`, `1`, `2`, `3` +error[E0769]: tuple variant `S` written as struct variant --> $DIR/missing-fields-in-struct-pattern.rs:4:12 | LL | if let S { a, b, c, d } = S(1, 2, 3, 4) { - | ^^^^^^^^^^^^^^^^ missing fields `0`, `1`, `2`, `3` - | - = note: trying to match a tuple variant with a struct variant pattern + | ^^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `S(a, b, c, d)` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0026, E0027. -For more information about an error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0769`. diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index fd0307f15c79a..e143747d637ee 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -7,7 +7,6 @@ LL | fn is_zen(_: T) {} LL | is_zen(x) | ^ `T` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `T` = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` @@ -25,7 +24,6 @@ LL | fn is_zen(_: T) {} LL | is_zen(x) | ^ `T` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `T` = note: required because of the requirements on the impl of `Zen` for `&T` = note: required because it appears within the type `std::marker::PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 05009358106fa..e179feba7a799 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -19,7 +19,6 @@ LL | let range = *arr..; | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: to learn more, visit = note: required by `std::ops::RangeFrom` error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index ea9be77a3e8b5..22586b5de91ff 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -5,10 +5,10 @@ LL | z: Box+'b+'c>, | ^^ error[E0478]: lifetime bound not satisfied - --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:5 + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8 | LL | z: Box+'b+'c>, - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 11:15 --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 diff --git a/src/test/ui/regions/regions-wf-trait-object.stderr b/src/test/ui/regions/regions-wf-trait-object.stderr index 9f39508604110..1ddbf73a46372 100644 --- a/src/test/ui/regions/regions-wf-trait-object.stderr +++ b/src/test/ui/regions/regions-wf-trait-object.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/regions-wf-trait-object.rs:7:5 + --> $DIR/regions-wf-trait-object.rs:7:8 | LL | x: Box+'b> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'b` as defined on the struct at 6:15 --> $DIR/regions-wf-trait-object.rs:6:15 diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 89eb3d97ce0a5..4ed93ad3279ad 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -5,9 +5,11 @@ LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(_x: &K) {} + | ^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index 2bb51731583a6..a449fac11930d 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -1,10 +1,10 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/dont-infer-static.rs:8:5 + --> $DIR/dont-infer-static.rs:8:10 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar - | ^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index 7f3c49e753fd7..3da8725d88a0c 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -24,7 +24,6 @@ LL | type U<'a>: PartialEq<&'a Self>; LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | - = help: the trait `std::cmp::PartialEq` is not implemented for `T` = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` help: consider further restricting this bound | diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index cc767de3845d2..52d3aefe125c0 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -19,14 +19,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t --> $DIR/str-array-assignment.rs:7:7 | LL | let v = s[..2]; - | ^ ------ help: consider borrowing here: `&s[..2]` - | | - | doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: consider borrowing here + | +LL | let v = &s[..2]; + | ^ error[E0308]: mismatched types --> $DIR/str-array-assignment.rs:9:17 diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index 2fd805e646991..7c834165e7f1c 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -8,7 +8,6 @@ LL | s[1..2] = bot(); | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn bot() -> T { loop {} } @@ -21,7 +20,6 @@ LL | s[1..2] = bot(); | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the left-hand-side of an assignment must have a statically known size error[E0277]: the type `str` cannot be indexed by `usize` diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index bcdeed262ecba..8dab8add80b8a 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -80,7 +80,6 @@ LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index fb5e6fbcfe712..a40d5e4bf7ba1 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -80,7 +80,6 @@ LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str` error: aborting due to 5 previous errors 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 index ee08f51f80270..f4c0d0f96c428 100644 --- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -1,5 +1,5 @@ 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 + --> $DIR/adt-param-with-implicit-sized-bound.rs:25:9 | LL | struct X(T); | - required by this bound in `X` @@ -7,10 +7,8 @@ LL | struct X(T); LL | struct Struct5{ | - this type parameter needs to be `std::marker::Sized` LL | _t: X, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:18:10 | @@ -28,8 +26,6 @@ LL | fn func1() -> Struct1; LL | struct Struct1{ | - required by this bound in `Struct1` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | fn func1() -> Struct1 where Self: std::marker::Sized; @@ -48,8 +44,6 @@ LL | fn func2<'a>() -> Struct2<'a, Self>; 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 help: consider further restricting `Self` | LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; @@ -68,8 +62,6 @@ LL | fn func3() -> Struct3; LL | struct Struct3{ | - required by this bound in `Struct3` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/adt-param-with-implicit-sized-bound.rs:14:16 | @@ -91,8 +83,6 @@ LL | fn func4() -> Struct4; LL | struct Struct4{ | - required by this bound in `Struct4` | - = help: the trait `std::marker::Sized` is not implemented for `Self` - = note: to learn more, visit help: consider further restricting `Self` | LL | fn func4() -> Struct4 where Self: std::marker::Sized; diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr index b073e10749cc1..2b7c29e20cd31 100644 --- a/src/test/ui/suggestions/path-by-value.stderr +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -2,13 +2,15 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation --> $DIR/path-by-value.rs:3:6 | LL | fn f(p: Path) { } - | ^ borrow the `Path` instead + | ^ doesn't have a size known at compile-time | = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `std::path::Path` - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn f(p: &Path) { } + | ^ error: aborting due to previous error diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr index 0c52778b0d886..33af13d943f74 100644 --- a/src/test/ui/suggestions/restrict-type-argument.stderr +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -7,7 +7,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `impl Sync` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `impl Sync` help: consider further restricting this bound | LL | fn use_impl_sync(val: impl Sync + std::marker::Send) { @@ -22,7 +21,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_where(val: S) where S: Sync + std::marker::Send { @@ -37,7 +35,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_bound(val: S) { @@ -52,7 +49,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | Sync + std::marker::Send @@ -67,7 +63,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider further restricting this bound | LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + std::marker::Send { @@ -82,7 +77,6 @@ LL | fn is_send(val: T) {} LL | is_send(val); | ^^^ `S` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `S` help: consider restricting type parameter `S` | LL | fn use_unbound(val: S) { diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr index 3188ee83e7d39..324316ceaf6ba 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.stderr +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase` - --> $DIR/cycle-cache-err-60010.rs:27:5 + --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: >::Data, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: required because of the requirements on the impl of `Query` for `ParseQuery` diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index 5e685105b45a3..daca91abff843 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -13,9 +13,11 @@ LL | fn foo(_x: Foo + Send) { | ^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn foo(_x: &Foo + Send) { + | ^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr index 271ed07ce42ab..d7549835a0905 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums.stderr @@ -13,13 +13,13 @@ LL | impl Foo { | ^^^^^^^ error[E0277]: the trait bound `isize: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:19:5 + --> $DIR/trait-bounds-on-structs-and-enums.rs:19:8 | LL | struct Foo { | ----- required by this bound in `Foo` ... LL | a: Foo, - | ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `isize` + | ^^^^^^^^^^ the trait `Trait` is not implemented for `isize` error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums.rs:23:10 @@ -31,13 +31,13 @@ LL | Quux(Bar), | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` error[E0277]: the trait bound `U: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:27:5 + --> $DIR/trait-bounds-on-structs-and-enums.rs:27:8 | LL | struct Foo { | ----- required by this bound in `Foo` ... LL | b: Foo, - | ^^^^^^^^^ the trait `Trait` is not implemented for `U` + | ^^^^^^ the trait `Trait` is not implemented for `U` | help: consider restricting type parameter `U` | @@ -68,13 +68,13 @@ LL | Foo, | ^^^^^^^^ the trait `Trait` is not implemented for `i32` error[E0277]: the trait bound `u8: Trait` is not satisfied - --> $DIR/trait-bounds-on-structs-and-enums.rs:39:22 + --> $DIR/trait-bounds-on-structs-and-enums.rs:39:29 | LL | enum Bar { | ----- required by this bound in `Bar` ... LL | DictionaryLike { field: Bar }, - | ^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `u8` + | ^^^^^^^ the trait `Trait` is not implemented for `u8` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index 4dddcd68f26c9..86a313baa5c38 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -11,9 +11,6 @@ LL | mem::size_of::(); | LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` - | - = help: the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit error[E0277]: the size for values of type `U` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:10:5 @@ -29,8 +26,6 @@ LL | mem::size_of::>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: within `Misc`, the trait `std::marker::Sized` is not implemented for `U` - = note: to learn more, visit = note: required because it appears within the type `Misc` error[E0277]: the trait bound `u64: std::convert::From` is not satisfied @@ -69,7 +64,6 @@ LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | = help: the trait `std::marker::Sized` is not implemented for `[T]` - = note: to learn more, visit error[E0277]: the size for values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:31:5 @@ -83,7 +77,6 @@ LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | = help: the trait `std::marker::Sized` is not implemented for `[&U]` - = note: to learn more, visit error: aborting due to 7 previous errors diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index 006fa933d34ca..4f4695612de0b 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -5,7 +5,6 @@ LL | fn cant_return_str() -> str { | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: the return type of a function must have a statically known size error[E0599]: no method named `test` found for type `i32` in the current scope diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 247d68ef2a1f0..28e30cbdd9d96 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -19,7 +19,6 @@ LL | type Underconstrained = impl 'static; LL | 5u32 | ---- this returned value is of type `u32` | - = help: the trait `std::fmt::Debug` is not implemented for `U` = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | @@ -35,7 +34,6 @@ LL | type Underconstrained2 = impl 'static; LL | 5u32 | ---- this returned value is of type `u32` | - = help: the trait `std::fmt::Debug` is not implemented for `V` = note: the return type of a function must have a statically known size help: consider restricting type parameter `V` | diff --git a/src/test/ui/type/type-check/issue-41314.rs b/src/test/ui/type/type-check/issue-41314.rs index 856d4ff6334bc..cbd39f5f9e6ed 100644 --- a/src/test/ui/type/type-check/issue-41314.rs +++ b/src/test/ui/type/type-check/issue-41314.rs @@ -4,7 +4,7 @@ enum X { fn main() { match X::Y(0) { - X::Y { number } => {} //~ ERROR does not have a field named `number` - //~^ ERROR pattern does not mention field `0` + X::Y { number } => {} + //~^ ERROR tuple variant `X::Y` written as struct variant } } diff --git a/src/test/ui/type/type-check/issue-41314.stderr b/src/test/ui/type/type-check/issue-41314.stderr index c2bba98d10a83..bd4d2071c2059 100644 --- a/src/test/ui/type/type-check/issue-41314.stderr +++ b/src/test/ui/type/type-check/issue-41314.stderr @@ -1,18 +1,9 @@ -error[E0026]: variant `X::Y` does not have a field named `number` - --> $DIR/issue-41314.rs:7:16 - | -LL | X::Y { number } => {} - | ^^^^^^ variant `X::Y` does not have this field - -error[E0027]: pattern does not mention field `0` +error[E0769]: tuple variant `X::Y` written as struct variant --> $DIR/issue-41314.rs:7:9 | LL | X::Y { number } => {} - | ^^^^^^^^^^^^^^^ missing field `0` - | - = note: trying to match a tuple variant with a struct variant pattern + | ^^^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `X::Y(number)` -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0026, E0027. -For more information about an error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0769`. diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index 9cba3578449c3..7398b48a238d1 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -7,7 +7,6 @@ LL | is_send::() LL | fn is_send() { | ---- required by this bound in `is_send` | - = help: the trait `std::marker::Send` is not implemented for `T` help: consider restricting type parameter `T` | LL | fn foo() { diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.rs b/src/test/ui/typeck/typeck_type_placeholder_item.rs index 99a7023089283..133c5231031fd 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.rs +++ b/src/test/ui/typeck/typeck_type_placeholder_item.rs @@ -32,6 +32,7 @@ fn test7(x: _) { let _x: usize = x; } fn test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures +//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures struct Test9; @@ -98,6 +99,7 @@ pub fn main() { fn fn_test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures + //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures struct FnTest9; diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 6c0653d5fcb7c..a1945f2b9cf4e 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -1,35 +1,35 @@ error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:152:18 + --> $DIR/typeck_type_placeholder_item.rs:154:18 | LL | struct BadStruct<_>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:155:16 + --> $DIR/typeck_type_placeholder_item.rs:157:16 | LL | trait BadTrait<_> {} | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:165:19 + --> $DIR/typeck_type_placeholder_item.rs:167:19 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:165:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` - --> $DIR/typeck_type_placeholder_item.rs:170:19 + --> $DIR/typeck_type_placeholder_item.rs:172:19 | LL | struct BadStruct2<_, T>(_, T); | ^ expected identifier, found reserved identifier error: associated constant in `impl` without body - --> $DIR/typeck_type_placeholder_item.rs:201:5 + --> $DIR/typeck_type_placeholder_item.rs:203:5 | LL | const C: _; | ^^^^^^^^^^- @@ -37,7 +37,7 @@ LL | const C: _; | help: provide a definition for the constant: `= ;` error[E0403]: the name `_` is already used for a generic parameter in this item's generic parameters - --> $DIR/typeck_type_placeholder_item.rs:165:22 + --> $DIR/typeck_type_placeholder_item.rs:167:22 | LL | struct BadStruct1<_, _>(_); | - ^ already used @@ -131,6 +131,15 @@ help: use type parameters instead LL | fn test7(x: T) { let _x: usize = x; } | ^^^ ^ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:33:22 + | +LL | fn test8(_f: fn() -> _) { } + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:33:22 | @@ -143,7 +152,7 @@ LL | fn test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:46:26 + --> $DIR/typeck_type_placeholder_item.rs:47:26 | LL | fn test11(x: &usize) -> &_ { | -^ @@ -152,7 +161,7 @@ LL | fn test11(x: &usize) -> &_ { | help: replace with the correct return type: `&&usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:51:52 + --> $DIR/typeck_type_placeholder_item.rs:52:52 | LL | unsafe fn test12(x: *const usize) -> *const *const _ { | --------------^ @@ -161,7 +170,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ { | help: replace with the correct return type: `*const *const usize` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:65:8 + --> $DIR/typeck_type_placeholder_item.rs:66:8 | LL | a: _, | ^ not allowed in type signatures @@ -180,13 +189,13 @@ LL | b: (T, T), | error: missing type for `static` item - --> $DIR/typeck_type_placeholder_item.rs:71:12 + --> $DIR/typeck_type_placeholder_item.rs:72:12 | LL | static A = 42; | ^ help: provide a type for the item: `A: i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:73:15 + --> $DIR/typeck_type_placeholder_item.rs:74:15 | LL | static B: _ = 42; | ^ @@ -195,13 +204,13 @@ LL | static B: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:75:15 + --> $DIR/typeck_type_placeholder_item.rs:76:15 | LL | static C: Option<_> = Some(42); | ^^^^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:78:21 + --> $DIR/typeck_type_placeholder_item.rs:79:21 | LL | fn fn_test() -> _ { 5 } | ^ @@ -210,7 +219,7 @@ LL | fn fn_test() -> _ { 5 } | help: replace with the correct return type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:81:23 + --> $DIR/typeck_type_placeholder_item.rs:82:23 | LL | fn fn_test2() -> (_, _) { (5, 5) } | -^--^- @@ -220,7 +229,7 @@ LL | fn fn_test2() -> (_, _) { (5, 5) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:84:22 + --> $DIR/typeck_type_placeholder_item.rs:85:22 | LL | static FN_TEST3: _ = "test"; | ^ @@ -229,7 +238,7 @@ LL | static FN_TEST3: _ = "test"; | help: replace `_` with the correct type: `&str` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:87:22 + --> $DIR/typeck_type_placeholder_item.rs:88:22 | LL | static FN_TEST4: _ = 145; | ^ @@ -238,13 +247,13 @@ LL | static FN_TEST4: _ = 145; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:90:22 + --> $DIR/typeck_type_placeholder_item.rs:91:22 | LL | static FN_TEST5: (_, _) = (1, 2); | ^^^^^^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:93:20 + --> $DIR/typeck_type_placeholder_item.rs:94:20 | LL | fn fn_test6(_: _) { } | ^ not allowed in type signatures @@ -255,7 +264,7 @@ LL | fn fn_test6(_: T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:96:20 + --> $DIR/typeck_type_placeholder_item.rs:97:20 | LL | fn fn_test7(x: _) { let _x: usize = x; } | ^ not allowed in type signatures @@ -266,7 +275,16 @@ LL | fn fn_test7(x: T) { let _x: usize = x; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:99:29 + --> $DIR/typeck_type_placeholder_item.rs:100:29 + | +LL | fn fn_test8(_f: fn() -> _) { } + | ^ + | | + | not allowed in type signatures + | help: use type parameters instead: `T` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:100:29 | LL | fn fn_test8(_f: fn() -> _) { } | ^ not allowed in type signatures @@ -277,7 +295,7 @@ LL | fn fn_test8(_f: fn() -> T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:121:12 + --> $DIR/typeck_type_placeholder_item.rs:123:12 | LL | a: _, | ^ not allowed in type signatures @@ -296,13 +314,13 @@ LL | b: (T, T), | error[E0282]: type annotations needed - --> $DIR/typeck_type_placeholder_item.rs:126:18 + --> $DIR/typeck_type_placeholder_item.rs:128:18 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ cannot infer type error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:126:28 + --> $DIR/typeck_type_placeholder_item.rs:128:28 | LL | fn fn_test11(_: _) -> (_, _) { panic!() } | ^ ^ not allowed in type signatures @@ -310,7 +328,7 @@ LL | fn fn_test11(_: _) -> (_, _) { panic!() } | not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:130:30 + --> $DIR/typeck_type_placeholder_item.rs:132:30 | LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | -^--^- @@ -320,7 +338,7 @@ LL | fn fn_test12(x: i32) -> (_, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:133:33 + --> $DIR/typeck_type_placeholder_item.rs:135:33 | LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | ------^- @@ -329,7 +347,7 @@ LL | fn fn_test13(x: _) -> (i32, _) { (x, x) } | help: replace with the correct return type: `(i32, i32)` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:152:21 + --> $DIR/typeck_type_placeholder_item.rs:154:21 | LL | struct BadStruct<_>(_); | ^ not allowed in type signatures @@ -340,7 +358,7 @@ LL | struct BadStruct(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:157:15 + --> $DIR/typeck_type_placeholder_item.rs:159:15 | LL | impl BadTrait<_> for BadStruct<_> {} | ^ ^ not allowed in type signatures @@ -353,13 +371,13 @@ LL | impl BadTrait for BadStruct {} | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:160:34 + --> $DIR/typeck_type_placeholder_item.rs:162:34 | LL | fn impl_trait() -> impl BadTrait<_> { | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:165:25 + --> $DIR/typeck_type_placeholder_item.rs:167:25 | LL | struct BadStruct1<_, _>(_); | ^ not allowed in type signatures @@ -370,7 +388,7 @@ LL | struct BadStruct1(T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:170:25 + --> $DIR/typeck_type_placeholder_item.rs:172:25 | LL | struct BadStruct2<_, T>(_, T); | ^ not allowed in type signatures @@ -381,13 +399,13 @@ LL | struct BadStruct2(U, T); | ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:174:14 + --> $DIR/typeck_type_placeholder_item.rs:176:14 | LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:42:27 + --> $DIR/typeck_type_placeholder_item.rs:43:27 | LL | fn test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -398,7 +416,7 @@ LL | fn test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:138:31 + --> $DIR/typeck_type_placeholder_item.rs:140:31 | LL | fn method_test1(&self, x: _); | ^ not allowed in type signatures @@ -409,7 +427,7 @@ LL | fn method_test1(&self, x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:140:31 + --> $DIR/typeck_type_placeholder_item.rs:142:31 | LL | fn method_test2(&self, x: _) -> _; | ^ ^ not allowed in type signatures @@ -422,7 +440,7 @@ LL | fn method_test2(&self, x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:142:31 + --> $DIR/typeck_type_placeholder_item.rs:144:31 | LL | fn method_test3(&self) -> _; | ^ not allowed in type signatures @@ -433,7 +451,7 @@ LL | fn method_test3(&self) -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:144:26 + --> $DIR/typeck_type_placeholder_item.rs:146:26 | LL | fn assoc_fn_test1(x: _); | ^ not allowed in type signatures @@ -444,7 +462,7 @@ LL | fn assoc_fn_test1(x: T); | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:146:26 + --> $DIR/typeck_type_placeholder_item.rs:148:26 | LL | fn assoc_fn_test2(x: _) -> _; | ^ ^ not allowed in type signatures @@ -457,7 +475,7 @@ LL | fn assoc_fn_test2(x: T) -> T; | ^^^ ^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:148:28 + --> $DIR/typeck_type_placeholder_item.rs:150:28 | LL | fn assoc_fn_test3() -> _; | ^ not allowed in type signatures @@ -468,7 +486,7 @@ LL | fn assoc_fn_test3() -> T; | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:60:37 + --> $DIR/typeck_type_placeholder_item.rs:61:37 | LL | fn clone_from(&mut self, other: _) { *self = Test9; } | ^ not allowed in type signatures @@ -479,7 +497,7 @@ LL | fn clone_from(&mut self, other: T) { *self = Test9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:108:34 + --> $DIR/typeck_type_placeholder_item.rs:110:34 | LL | fn fn_test10(&self, _x : _) { } | ^ not allowed in type signatures @@ -490,7 +508,7 @@ LL | fn fn_test10(&self, _x : T) { } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:116:41 + --> $DIR/typeck_type_placeholder_item.rs:118:41 | LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } | ^ not allowed in type signatures @@ -501,25 +519,25 @@ LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:180:21 + --> $DIR/typeck_type_placeholder_item.rs:182:21 | LL | type Y = impl Trait<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:188:14 + --> $DIR/typeck_type_placeholder_item.rs:190:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:190:14 + --> $DIR/typeck_type_placeholder_item.rs:192:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:192:14 + --> $DIR/typeck_type_placeholder_item.rs:194:14 | LL | const D: _ = 42; | ^ @@ -528,7 +546,7 @@ LL | const D: _ = 42; | help: replace `_` with the correct type: `i32` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:39:24 + --> $DIR/typeck_type_placeholder_item.rs:40:24 | LL | fn test9(&self) -> _ { () } | ^ @@ -537,7 +555,7 @@ LL | fn test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:57:24 + --> $DIR/typeck_type_placeholder_item.rs:58:24 | LL | fn clone(&self) -> _ { Test9 } | ^ @@ -546,7 +564,7 @@ LL | fn clone(&self) -> _ { Test9 } | help: replace with the correct return type: `Test9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:105:31 + --> $DIR/typeck_type_placeholder_item.rs:107:31 | LL | fn fn_test9(&self) -> _ { () } | ^ @@ -555,7 +573,7 @@ LL | fn fn_test9(&self) -> _ { () } | help: replace with the correct return type: `()` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:113:28 + --> $DIR/typeck_type_placeholder_item.rs:115:28 | LL | fn clone(&self) -> _ { FnTest9 } | ^ @@ -564,25 +582,25 @@ LL | fn clone(&self) -> _ { FnTest9 } | help: replace with the correct return type: `main::FnTest9` error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:197:14 + --> $DIR/typeck_type_placeholder_item.rs:199:14 | LL | type A = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:199:14 + --> $DIR/typeck_type_placeholder_item.rs:201:14 | LL | type B = _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:201:14 + --> $DIR/typeck_type_placeholder_item.rs:203:14 | LL | const C: _; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:204:14 + --> $DIR/typeck_type_placeholder_item.rs:206:14 | LL | const D: _ = 42; | ^ @@ -590,7 +608,7 @@ LL | const D: _ = 42; | not allowed in type signatures | help: replace `_` with the correct type: `i32` -error: aborting due to 64 previous errors +error: aborting due to 66 previous errors Some errors have detailed explanations: E0121, E0282, E0403. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/union/union-fields-2.stderr b/src/test/ui/union/union-fields-2.stderr index 68cb66d89d218..48654347285d3 100644 --- a/src/test/ui/union/union-fields-2.stderr +++ b/src/test/ui/union/union-fields-2.stderr @@ -48,18 +48,18 @@ error: union patterns should have exactly one field LL | let U { a, b } = u; | ^^^^^^^^^^ -error[E0026]: union `U` does not have a field named `c` - --> $DIR/union-fields-2.rs:18:19 - | -LL | let U { a, b, c } = u; - | ^ union `U` does not have this field - error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:18:9 | LL | let U { a, b, c } = u; | ^^^^^^^^^^^^^ +error[E0026]: union `U` does not have a field named `c` + --> $DIR/union-fields-2.rs:18:19 + | +LL | let U { a, b, c } = u; + | ^ union `U` does not have this field + error: union patterns should have exactly one field --> $DIR/union-fields-2.rs:20:9 | diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index 62dacd064bed0..d7224e46add3d 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -1,26 +1,40 @@ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/union-sized-field.rs:4:5 + --> $DIR/union-sized-field.rs:4:12 | LL | union Foo { | - this type parameter needs to be `std::marker::Sized` LL | value: T, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^ 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 = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | value: &T, + | ^ +help: heap allocated types always have a statically known size + | +LL | value: Box, + | ^^^^ ^ error[E0277]: the size for values of type `T` cannot be known at compilation time - --> $DIR/union-sized-field.rs:9:5 + --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2 { | - this type parameter needs to be `std::marker::Sized` LL | value: T, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^ 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 = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | value: &T, + | ^ +help: heap allocated types always have a statically known size + | +LL | value: Box, + | ^^^^ ^ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/union-sized-field.rs:15:11 @@ -30,9 +44,16 @@ LL | enum Foo3 { LL | Value(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 = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | Value(&T), + | ^ +help: heap allocated types always have a statically known size + | +LL | Value(Box), + | ^^^^ ^ error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr index e702f2c61bee3..574f182ecc687 100644 --- a/src/test/ui/union/union-unsized.stderr +++ b/src/test/ui/union/union-unsized.stderr @@ -1,22 +1,38 @@ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:4:5 + --> $DIR/union-unsized.rs:4:8 | LL | a: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | a: &str, + | ^ +help: heap allocated types always have a statically known size + | +LL | a: Box, + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/union-unsized.rs:12:5 + --> $DIR/union-unsized.rs:12:8 | LL | b: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | b: &str, + | ^ +help: heap allocated types always have a statically known size + | +LL | b: Box, + | ^^^^ ^ error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index 35f63a91b2b53..2ed35dc0e2c12 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -5,7 +5,6 @@ LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: required because it appears within the type `Test` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr index d42fddb3a4a26..461efcf3dbf29 100644 --- a/src/test/ui/unsized-locals/issue-30276.stderr +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -5,7 +5,6 @@ LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr index 7b6c2d11ea169..04a8de1b5dc5b 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -5,7 +5,6 @@ LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required because it appears within the type `main::A` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr index be006c09d6f5c..8e5f753082734 100644 --- a/src/test/ui/unsized-locals/issue-50940.stderr +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -5,7 +5,6 @@ LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 43c35cdd7b5b0..0a9b43dac3344 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -5,7 +5,6 @@ LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -16,7 +15,6 @@ LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized @@ -27,7 +25,6 @@ LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time | = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr index f9a7452a5ebf2..11435ec0353bc 100644 --- a/src/test/ui/unsized-locals/unsized-exprs3.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -5,7 +5,6 @@ LL | udrop as fn([u8]); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index 3ff6f30db2a84..19978ae24cacb 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -7,9 +7,6 @@ LL | fn foo() { bar::() } | - ^ doesn't have a size known at compile-time | | | this type parameter needs to be `std::marker::Sized` - | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit 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 1908aee25ea7b..fdfdb9b4e2a5b 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -9,8 +9,6 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` --> $DIR/unsized-enum.rs:4:10 | diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index bc3b3831f3269..742abc39209e6 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -7,22 +7,36 @@ LL | // parameter LL | VA(W), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `W` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VA(&W), + | ^ +help: heap allocated types always have a statically known size + | +LL | VA(Box), + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:25:8 + --> $DIR/unsized-enum2.rs:25:11 | LL | enum E { | - this type parameter needs to be `std::marker::Sized` ... LL | VB{x: X}, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VB{x: &X}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VB{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized-enum2.rs:27:15 @@ -33,22 +47,36 @@ LL | enum E { LL | VC(isize, Y), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VC(isize, &Y), + | ^ +help: heap allocated types always have a statically known size + | +LL | VC(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `Z` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:29:18 + --> $DIR/unsized-enum2.rs:29:21 | LL | enum E { | - this type parameter needs to be `std::marker::Sized` ... LL | VD{u: isize, x: Z}, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Z` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VD{u: isize, x: &Z}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VD{u: isize, x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:33:8 @@ -57,18 +85,34 @@ LL | VE([u8]), | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VE(&[u8]), + | ^ +help: heap allocated types always have a statically known size + | +LL | VE(Box<[u8]>), + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:35:8 + --> $DIR/unsized-enum2.rs:35:11 | LL | VF{x: str}, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VF{x: &str}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VF{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[f32]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:37:15 @@ -77,18 +121,34 @@ LL | VG(isize, [f32]), | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VG(isize, &[f32]), + | ^ +help: heap allocated types always have a statically known size + | +LL | VG(isize, Box<[f32]>), + | ^^^^ ^ error[E0277]: the size for values of type `[u32]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:39:18 + --> $DIR/unsized-enum2.rs:39:21 | LL | VH{u: isize, x: [u32]}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VH{u: isize, x: &[u32]}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VH{u: isize, x: Box<[u32]>}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:53:8 @@ -97,18 +157,34 @@ LL | VM(dyn Foo), | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VM(&dyn Foo), + | ^ +help: heap allocated types always have a statically known size + | +LL | VM(Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:55:8 + --> $DIR/unsized-enum2.rs:55:11 | LL | VN{x: dyn Bar}, - | ^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VN{x: &dyn Bar}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VN{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:57:15 @@ -117,18 +193,34 @@ LL | VO(isize, dyn FooBar), | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VO(isize, &dyn FooBar), + | ^ +help: heap allocated types always have a statically known size + | +LL | VO(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:59:18 + --> $DIR/unsized-enum2.rs:59:21 | LL | VP{u: isize, x: dyn BarFoo}, - | ^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VP{u: isize, x: &dyn BarFoo}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VP{u: isize, x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:63:8 @@ -137,18 +229,34 @@ LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i8]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VQ(&<&'static [i8] as Deref>::Target), + | ^ +help: heap allocated types always have a statically known size + | +LL | VQ(Box<<&'static [i8] as Deref>::Target>), + | ^^^^ ^ error[E0277]: the size for values of type `[char]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:65:8 + --> $DIR/unsized-enum2.rs:65:11 | LL | VR{x: <&'static [char] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[char]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VR{x: &<&'static [char] as Deref>::Target}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VR{x: Box<<&'static [char] as Deref>::Target>}, + | ^^^^ ^ error[E0277]: the size for values of type `[f64]` cannot be known at compilation time --> $DIR/unsized-enum2.rs:67:15 @@ -157,18 +265,34 @@ LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[f64]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VS(isize, &<&'static [f64] as Deref>::Target), + | ^ +help: heap allocated types always have a statically known size + | +LL | VS(isize, Box<<&'static [f64] as Deref>::Target>), + | ^^^^ ^ error[E0277]: the size for values of type `[i32]` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:69:18 + --> $DIR/unsized-enum2.rs:69:21 | LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[i32]` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VT{u: isize, x: &<&'static [i32] as Deref>::Target}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VT{u: isize, x: Box<<&'static [i32] as Deref>::Target>}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:43:8 @@ -177,20 +301,36 @@ LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VI(&Path1), + | ^ +help: heap allocated types always have a statically known size + | +LL | VI(Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:45:8 + --> $DIR/unsized-enum2.rs:45:11 | LL | VJ{x: Path2}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VJ{x: &Path2}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VJ{x: Box}, + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot be known at compilation time --> $DIR/unsized-enum2.rs:47:15 @@ -199,20 +339,36 @@ LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VK(isize, &Path3), + | ^ +help: heap allocated types always have a statically known size + | +LL | VK(isize, Box), + | ^^^^ ^ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot be known at compilation time - --> $DIR/unsized-enum2.rs:49:18 + --> $DIR/unsized-enum2.rs:49:21 | LL | VL{u: isize, x: Path4}, - | ^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^ doesn't have a size known at compile-time | = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)` - = note: to learn more, visit = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | VL{u: isize, x: &Path4}, + | ^ +help: heap allocated types always have a statically known size + | +LL | VL{u: isize, x: Box}, + | ^^^^ ^ error: aborting due to 20 previous errors diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index ed2c2e75cbd44..6b54db7148a74 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -5,7 +5,6 @@ LL | foo11("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -15,7 +14,6 @@ LL | foo12(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -25,7 +23,6 @@ LL | foo21("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -35,7 +32,6 @@ LL | foo22(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: required for the cast to the object type `dyn std::convert::AsRef` error: aborting due to 4 previous errors 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 e0f077d66f99c..50b54593f3aa1 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -9,8 +9,6 @@ LL | impl S5 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 | diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index d92d1d9113e5c..0c8529bf1a9af 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -9,8 +9,6 @@ LL | fn foo2() { not_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/unsized-struct.rs:4:12 | @@ -30,8 +28,6 @@ LL | fn bar2() { is_sized::>() } | | | this type parameter needs to be `std::marker::Sized` | - = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `T` - = note: to learn more, visit = note: required because it appears within the type `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index 73c5439da53b6..4514208a90dc9 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -9,8 +9,6 @@ LL | impl T3 for S5 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-trait-impl-self-type.rs:8:11 | 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 e423a9bdeab6f..f48d4ef9f1461 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -9,8 +9,6 @@ LL | impl T2 for S4 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait T2 { diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index e0a0389dc4690..ddddae4eaba57 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -9,8 +9,6 @@ LL | f2::(x); LL | fn f2(x: &X) { | - required by this bound in `f2` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn f2(x: &X) { @@ -27,8 +25,6 @@ LL | f4::(x); LL | fn f4(x: &X) { | - required by this bound in `f4` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | fn f4(x: &X) { @@ -45,8 +41,6 @@ LL | fn f8(x1: &S, x2: &S) { LL | f5(x1); | ^^ doesn't have a size known at compile-time | - = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` help: consider relaxing the implicit `Sized` restriction | @@ -61,8 +55,6 @@ LL | fn f9(x1: Box>) { LL | f5(&(*x1, 34)); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `S`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: only the last element of a tuple may have a dynamically sized type @@ -74,8 +66,6 @@ LL | fn f10(x1: Box>) { LL | f5(&(32, *x1)); | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` = note: tuples must have a statically known size to be initialized @@ -91,8 +81,6 @@ LL | fn f10(x1: Box>) { LL | f5(&(32, *x1)); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, S)`, the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: required because it appears within the type `S` = note: required because it appears within the type `({integer}, S)` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr index de4da309791c0..80cf4baeab794 100644 --- a/src/test/ui/unsized5.stderr +++ b/src/test/ui/unsized5.stderr @@ -1,47 +1,77 @@ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:4:5 + --> $DIR/unsized5.rs:4:9 | LL | struct S1 { | - this type parameter needs to be `std::marker::Sized` LL | f1: X, - | ^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f1: &X, + | ^ +help: heap allocated types always have a statically known size + | +LL | f1: Box, + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:10:5 + --> $DIR/unsized5.rs:10:8 | LL | struct S2 { | - this type parameter needs to be `std::marker::Sized` LL | f: isize, LL | g: X, - | ^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | g: &X, + | ^ +help: heap allocated types always have a statically known size + | +LL | g: Box, + | ^^^^ ^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/unsized5.rs:15:5 + --> $DIR/unsized5.rs:15:8 | LL | f: str, - | ^^^^^^ doesn't have a size known at compile-time + | ^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `str` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f: &str, + | ^ +help: heap allocated types always have a statically known size + | +LL | f: Box, + | ^^^^ ^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/unsized5.rs:20:5 + --> $DIR/unsized5.rs:20:8 | LL | f: [u8], - | ^^^^^^^ doesn't have a size known at compile-time + | ^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | f: &[u8], + | ^ +help: heap allocated types always have a statically known size + | +LL | f: Box<[u8]>, + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized5.rs:25:8 @@ -51,21 +81,35 @@ LL | enum E { LL | V1(X, isize), | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V1(&X, isize), + | ^ +help: heap allocated types always have a statically known size + | +LL | V1(Box, isize), + | ^^^^ ^ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized5.rs:29:8 + --> $DIR/unsized5.rs:29:12 | LL | enum F { | - this type parameter needs to be `std::marker::Sized` LL | V2{f1: X, f: isize}, - | ^^^^^ doesn't have a size known at compile-time + | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | V2{f1: &X, f: isize}, + | ^ +help: heap allocated types always have a statically known size + | +LL | V2{f1: Box, f: isize}, + | ^^^^ ^ error: aborting due to 6 previous errors diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index 337afd2ee7e10..f045bfe2444bc 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -7,8 +7,6 @@ LL | fn f1(x: &X) { LL | let y: Y; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -21,8 +19,6 @@ LL | let _: W; // <-- this is OK, no bindings created, no initializer. LL | let _: (isize, (X, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `Z` cannot be known at compilation time @@ -34,8 +30,6 @@ LL | fn f1(x: &X) { LL | let y: (isize, (Z, usize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Z` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time @@ -46,8 +40,6 @@ LL | fn f2(x: &X) { LL | let y: X; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -60,8 +52,6 @@ LL | fn f2(x: &X) { LL | let y: (isize, (Y, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `Y` - = note: to learn more, visit = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `X` cannot be known at compilation time @@ -72,8 +62,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -86,8 +74,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let y = *x2; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -100,8 +86,6 @@ LL | fn f3(x1: Box, x2: Box, x3: Box) { LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -113,8 +97,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -127,8 +109,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let y = *x2; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -141,8 +121,6 @@ LL | fn f4(x1: Box, x2: Box, x3: Box) { LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature @@ -154,10 +132,11 @@ LL | fn g1(x: X) {} | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn g1(x: &X) {} + | ^ error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:40:22 @@ -167,10 +146,11 @@ LL | fn g2(x: X) {} | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit - = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn g2(x: &X) {} + | ^ error: aborting due to 13 previous errors diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index e616a5cf0f9c2..7dbddd4ed2443 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -9,8 +9,6 @@ LL | impl T1 for S3 { | | | this type parameter needs to be `std::marker::Sized` | - = help: the trait `std::marker::Sized` is not implemented for `X` - = note: to learn more, visit help: consider relaxing the implicit `Sized` restriction | LL | trait T1 { diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr index b222d07580eaf..fedec1909fd33 100644 --- a/src/test/ui/wf/wf-array-elem-sized.stderr +++ b/src/test/ui/wf/wf-array-elem-sized.stderr @@ -1,11 +1,10 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-array-elem-sized.rs:7:5 + --> $DIR/wf-array-elem-sized.rs:7:10 | LL | foo: [[u8]], - | ^^^^^^^^^^^ doesn't have a size known at compile-time + | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: to learn more, visit = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 0a3665fcf0436..1eb7010c77a79 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied - --> $DIR/wf-enum-fields-struct-variant.rs:13:9 + --> $DIR/wf-enum-fields-struct-variant.rs:13:12 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | f: IsCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | help: consider restricting type parameter `A` | diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 731d31ac34f62..938336d3ace76 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -22,7 +22,6 @@ LL | struct Vec { | - required by this bound in `Vec` | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` - = note: to learn more, visit help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/wf-fn-where-clause.rs:16:12 | diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index c0bb3a50b1f1e..212c61e1e5e07 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-fn-type-arg.rs:9:5 + --> $DIR/wf-in-fn-type-arg.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn(MustBeCopy) - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index e203058250790..3fb05fe81763b 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-fn-type-ret.rs:9:5 + --> $DIR/wf-in-fn-type-ret.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index a79c446247794..44cacf4ef4dfe 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -1,20 +1,20 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:13:5 + --> $DIR/wf-in-fn-type-static.rs:13:8 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: fn() -> &'static T - | ^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-fn-type-static.rs:18:5 + --> $DIR/wf-in-fn-type-static.rs:18:8 | LL | struct Bar { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: Copy LL | x: fn(&'static T) - | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index c0057f3c82977..c50a6bb6e4d87 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -1,11 +1,11 @@ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/wf-in-obj-type-static.rs:14:5 + --> $DIR/wf-in-obj-type-static.rs:14:8 | LL | struct Foo { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // needs T: 'static LL | x: dyn Object<&'static T> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 6d85cdde7f991..129f9484df29b 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/wf-in-obj-type-trait.rs:11:5 + --> $DIR/wf-in-obj-type-trait.rs:11:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: dyn Object> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` | help: consider restricting type parameter `T` | diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index cda3b8fe4fddb..d7d0b7a0820a8 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied - --> $DIR/wf-struct-field.rs:12:5 + --> $DIR/wf-struct-field.rs:12:11 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | data: IsCopy - | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` | help: consider restricting type parameter `A` |