diff options
784 files changed, 10394 insertions, 7024 deletions
diff --git a/Cargo.lock b/Cargo.lock index 81f19668c24..4677d34d2a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.1.14", ] [[package]] @@ -1192,6 +1192,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921" [[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1458,9 +1464,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width 0.2.1", ] @@ -2167,6 +2173,7 @@ version = "0.1.0" dependencies = [ "html5ever", "regex", + "urlencoding", ] [[package]] @@ -2346,11 +2353,11 @@ dependencies = [ [[package]] name = "miow" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" +checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] @@ -3122,6 +3129,26 @@ dependencies = [ ] [[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3248,6 +3275,7 @@ dependencies = [ "rustc_driver_impl", "rustc_public", "rustc_public_bridge", + "rustc_windows_rc", "tikv-jemalloc-sys", ] @@ -3623,6 +3651,7 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "rustc_driver_impl", + "rustc_windows_rc", ] [[package]] @@ -4409,7 +4438,6 @@ dependencies = [ "rustc_middle", "rustc_query_system", "rustc_serialize", - "rustc_session", "rustc_span", "tracing", ] @@ -4575,6 +4603,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "schemars", "serde", "serde_derive", "serde_json", @@ -4681,6 +4710,7 @@ dependencies = [ name = "rustc_type_ir" version = "0.0.0" dependencies = [ + "arrayvec", "bitflags", "derive-where", "ena", @@ -4719,6 +4749,13 @@ dependencies = [ ] [[package]] +name = "rustc_windows_rc" +version = "0.0.0" +dependencies = [ + "cc", +] + +[[package]] name = "rustdoc" version = "0.0.0" dependencies = [ @@ -4891,6 +4928,31 @@ dependencies = [ ] [[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.106", +] + +[[package]] name = "scoped-tls" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4965,6 +5027,17 @@ dependencies = [ ] [[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] name = "serde_json" version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5518,11 +5591,10 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -5826,6 +5898,12 @@ dependencies = [ ] [[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5969,9 +6047,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.16" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cd35d6cae91109a0ffd207b573cf3c741cab7e921dd376ea7aaf2c52a3408c" +checksum = "1c9208f87cac2332fd80dcf36d54e9163d3446e28301e0c6e424984425738984" dependencies = [ "anyhow", "clap", @@ -5979,9 +6057,9 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.237.0", + "wasmparser 0.239.0", "wat", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "winsplit", "wit-component", "wit-parser", @@ -6006,24 +6084,24 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.237.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" dependencies = [ "leb128fmt", - "wasmparser 0.237.0", + "wasmparser 0.239.0", ] [[package]] name = "wasm-metadata" -version = "0.237.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc0b0a0c4f35ca6efa7a797671372915d4e9659dba2d59edc6fafc931d19997" +checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.237.0", - "wasmparser 0.237.0", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", ] [[package]] @@ -6048,9 +6126,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.237.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ "bitflags", "hashbrown", @@ -6061,22 +6139,22 @@ dependencies = [ [[package]] name = "wast" -version = "237.0.0" +version = "239.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767" +checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.1", - "wasm-encoder 0.237.0", + "wasm-encoder 0.239.0", ] [[package]] name = "wat" -version = "1.237.0" +version = "1.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9" +checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75" dependencies = [ "wast", ] @@ -6301,15 +6379,6 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" @@ -6337,21 +6406,6 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" @@ -6394,12 +6448,6 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" @@ -6412,12 +6460,6 @@ checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" @@ -6430,12 +6472,6 @@ checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" @@ -6460,12 +6496,6 @@ checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" [[package]] name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" @@ -6478,12 +6508,6 @@ checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" @@ -6496,12 +6520,6 @@ checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" @@ -6514,12 +6532,6 @@ checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" @@ -6565,9 +6577,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.237.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb7674f76c10e82fe00b256a9d4ffb2b8d037d42ab8e9a83ebb3be35c9d0bf6" +checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136" dependencies = [ "anyhow", "bitflags", @@ -6576,17 +6588,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.237.0", + "wasm-encoder 0.239.0", "wasm-metadata", - "wasmparser 0.237.0", + "wasmparser 0.239.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.237.0" +version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2596a5bc7c24cc965b56ad6ff9e32394c4e401764f89620a888519c6e849ab" +checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" dependencies = [ "anyhow", "id-arena", @@ -6597,7 +6609,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.237.0", + "wasmparser 0.239.0", ] [[package]] diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 3ca75235446..e3214d1ab9c 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -33,3 +33,8 @@ llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts'] # tidy-alphabetical-end + +[build-dependencies] +# tidy-alphabetical-start +rustc_windows_rc = { path = "../rustc_windows_rc" } +# tidy-alphabetical-end diff --git a/compiler/rustc/build.rs b/compiler/rustc/build.rs index 8b7d28d2b8a..9b5def53e3c 100644 --- a/compiler/rustc/build.rs +++ b/compiler/rustc/build.rs @@ -1,4 +1,6 @@ -use std::env; +use std::{env, path}; + +use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file}; fn main() { let target_os = env::var("CARGO_CFG_TARGET_OS"); @@ -13,6 +15,18 @@ fn main() { // Add a manifest file to rustc.exe. fn set_windows_exe_options() { + set_windows_resource(); + set_windows_manifest(); +} + +fn set_windows_resource() { + let stem = path::PathBuf::from("rustc_main_resource"); + let file_description = "rustc"; + let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::App); + println!("cargo:rustc-link-arg={}", res_file.display()); +} + +fn set_windows_manifest() { static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml"; let mut manifest = env::current_dir().unwrap(); diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 802a6fa3249..3e8fddd9954 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2284,6 +2284,54 @@ pub struct FnSig { pub span: Span, } +impl FnSig { + /// Return a span encompassing the header, or where to insert it if empty. + pub fn header_span(&self) -> Span { + match self.header.ext { + Extern::Implicit(span) | Extern::Explicit(_, span) => { + return self.span.with_hi(span.hi()); + } + Extern::None => {} + } + + match self.header.safety { + Safety::Unsafe(span) | Safety::Safe(span) => return self.span.with_hi(span.hi()), + Safety::Default => {} + }; + + if let Some(coroutine_kind) = self.header.coroutine_kind { + return self.span.with_hi(coroutine_kind.span().hi()); + } + + if let Const::Yes(span) = self.header.constness { + return self.span.with_hi(span.hi()); + } + + self.span.shrink_to_lo() + } + + /// The span of the header's safety, or where to insert it if empty. + pub fn safety_span(&self) -> Span { + match self.header.safety { + Safety::Unsafe(span) | Safety::Safe(span) => span, + Safety::Default => { + // Insert after the `coroutine_kind` if available. + if let Some(extern_span) = self.header.ext.span() { + return extern_span.shrink_to_lo(); + } + + // Insert right at the front of the signature. + self.header_span().shrink_to_hi() + } + } + } + + /// The span of the header's extern, or where to insert it if empty. + pub fn extern_span(&self) -> Span { + self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi()) + } +} + /// A constraint on an associated item. /// /// ### Examples @@ -3526,6 +3574,13 @@ impl Extern { None => Extern::Implicit(span), } } + + pub fn span(self) -> Option<Span> { + match self { + Extern::None => None, + Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), + } + } } /// A function header. @@ -3534,12 +3589,12 @@ impl Extern { /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). #[derive(Clone, Copy, Encodable, Decodable, Debug, Walkable)] pub struct FnHeader { - /// Whether this is `unsafe`, or has a default safety. - pub safety: Safety, - /// Whether this is `async`, `gen`, or nothing. - pub coroutine_kind: Option<CoroutineKind>, /// The `const` keyword, if any pub constness: Const, + /// Whether this is `async`, `gen`, or nothing. + pub coroutine_kind: Option<CoroutineKind>, + /// Whether this is `unsafe`, or has a default safety. + pub safety: Safety, /// The `extern` keyword and corresponding ABI string, if any. pub ext: Extern, } @@ -3553,38 +3608,6 @@ impl FnHeader { || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } - - /// Return a span encompassing the header, or none if all options are default. - pub fn span(&self) -> Option<Span> { - fn append(a: &mut Option<Span>, b: Span) { - *a = match a { - None => Some(b), - Some(x) => Some(x.to(b)), - } - } - - let mut full_span = None; - - match self.safety { - Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span), - Safety::Default => {} - }; - - if let Some(coroutine_kind) = self.coroutine_kind { - append(&mut full_span, coroutine_kind.span()); - } - - if let Const::Yes(span) = self.constness { - append(&mut full_span, span); - } - - match self.ext { - Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span), - Extern::None => {} - } - - full_span - } } impl Default for FnHeader { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3674814b796..bb6b25baf01 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::LangItem::Range } } - (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, + (None, Some(..), Closed) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeToInclusiveCopy + } else { + hir::LangItem::RangeToInclusive + } + } (Some(e1), Some(e2), Closed) => { if self.tcx.features().new_range() { hir::LangItem::RangeInclusiveCopy @@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let fields = self.arena.alloc_from_iter( - e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map( - |(s, e)| { + e1.iter() + .map(|e| (sym::start, e)) + .chain(e2.iter().map(|e| { + ( + if matches!( + lang_item, + hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy + ) { + sym::last + } else { + sym::end + }, + e, + ) + })) + .map(|(s, e)| { let expr = self.lower_expr(e); let ident = Ident::new(s, self.lower_span(e.span)); self.expr_field(ident, expr, e.span) - }, - ), + }), ); hir::ExprKind::Struct( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bb559bd8921..53351f91c46 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,9 @@ use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, Target, find_attr}; +use rustc_hir::{ + self as hir, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr, +}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; @@ -1117,20 +1119,31 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; + let span = self.lower_span(i.span); let item = hir::ImplItem { owner_id: hir_id.expect_owner(), ident: self.lower_ident(ident), generics, + impl_kind: if is_in_trait_impl { + ImplItemImplKind::Trait { + defaultness, + trait_item_def_id: self + .resolver + .get_partial_res(i.id) + .and_then(|r| r.expect_full_res().opt_def_id()) + .ok_or_else(|| { + self.dcx().span_delayed_bug( + span, + "could not resolve trait item being implemented", + ) + }), + } + } else { + ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) } + }, kind, - vis_span: self.lower_span(i.vis.span), - span: self.lower_span(i.span), - defaultness, + span, has_delayed_lints: !self.delayed_lints.is_empty(), - trait_item_def_id: self - .resolver - .get_partial_res(i.id) - .map(|r| r.expect_full_res().opt_def_id()) - .unwrap_or(None), }; self.arena.alloc(item) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 72f20a95ff0..4e2243e8787 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2101,17 +2101,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { return; } - if self.tcx.features().more_maybe_bounds() { - return; - } } RelaxedBoundPolicy::Forbidden(reason) => { - if self.tcx.features().more_maybe_bounds() { - return; - } - match reason { RelaxedBoundForbiddenReason::TraitObjectTy => { + if self.tcx.features().more_maybe_bounds() { + return; + } + self.dcx().span_err( span, "relaxed bounds are not permitted in trait object types", @@ -2119,6 +2116,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return; } RelaxedBoundForbiddenReason::SuperTrait => { + if self.tcx.features().more_maybe_bounds() { + return; + } + let mut diag = self.dcx().struct_span_err( span, "relaxed bounds are not permitted in supertrait bounds", diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index e5f1fcdc4b4..e5405a7ad91 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body .invalid = the invalid body @@ -66,6 +64,19 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect +ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list + +ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions + .label = `extern "{$abi}"` because of this + .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + +ast_passes_c_variadic_must_be_unsafe = + functions with a C variable argument list must be unsafe + .suggestion = add the `unsafe` keyword to this definition + +ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions + .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this @@ -84,6 +95,10 @@ ast_passes_const_without_body = ast_passes_constraint_on_negative_bound = associated type constraints not allowed on negative bounds +ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic + .const = `{$coroutine_kind}` because of this + .variadic = C-variadic because of this + ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses .label = not supported .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax @@ -201,6 +216,10 @@ ast_passes_match_arm_with_no_body = .suggestion = add a body after the pattern ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe + .suggestion = needs `unsafe` before the extern keyword + +ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe + .suggestion = needs `unsafe` before the extern keyword ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name .help = consider using the `#[path]` attribute to specify filesystem path diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 538918a890d..dc221c2fb1a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -492,7 +492,7 @@ impl<'a> AstValidator<'a> { } if !spans.is_empty() { - let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo()); + let header_span = sig.header_span(); let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); let padding = if header_span.is_empty() { "" } else { " " }; @@ -685,22 +685,53 @@ impl<'a> AstValidator<'a> { }); } + if let Some(coroutine_kind) = sig.header.coroutine_kind { + self.dcx().emit_err(errors::CoroutineAndCVariadic { + spans: vec![coroutine_kind.span(), variadic_param.span], + coroutine_kind: coroutine_kind.as_str(), + coroutine_span: coroutine_kind.span(), + variadic_span: variadic_param.span, + }); + } + match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free => match sig.header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) - | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _) - | Extern::Implicit(_) - if matches!(sig.header.safety, Safety::Unsafe(_)) => - { - return; + Extern::Implicit(_) => { + if !matches!(sig.header.safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + span: variadic_param.span, + unsafe_span: sig.safety_span(), + }); + } } - _ => {} - }, - FnCtxt::Assoc(_) => {} - }; + Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => { + if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) { + self.dcx().emit_err(errors::CVariadicBadExtern { + span: variadic_param.span, + abi: symbol_unescaped, + extern_span: sig.extern_span(), + }); + } - self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span }); + if !matches!(sig.header.safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + span: variadic_param.span, + unsafe_span: sig.safety_span(), + }); + } + } + Extern::None => { + let err = errors::CVariadicNoExtern { span: variadic_param.span }; + self.dcx().emit_err(err); + } + }, + FnCtxt::Assoc(_) => { + // For now, C variable argument lists are unsupported in associated functions. + let err = errors::CVariadicAssociatedFunction { span: variadic_param.span }; + self.dcx().emit_err(err); + } + } } fn check_item_named(&self, ident: Ident, kind: &str) { @@ -1100,7 +1131,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { MISSING_UNSAFE_ON_EXTERN, item.id, item.span, - BuiltinLintDiag::MissingUnsafeOnExtern { + errors::MissingUnsafeOnExternLint { suggestion: item.span.shrink_to_lo(), }, ); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 476ed27a10e..e09ca5b81c8 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -319,13 +319,47 @@ pub(crate) struct ExternItemAscii { } #[derive(Diagnostic)] -#[diag(ast_passes_bad_c_variadic)] -pub(crate) struct BadCVariadic { +#[diag(ast_passes_c_variadic_associated_function)] +pub(crate) struct CVariadicAssociatedFunction { #[primary_span] pub span: Span, } #[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_no_extern)] +#[help] +pub(crate) struct CVariadicNoExtern { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_must_be_unsafe)] +pub(crate) struct CVariadicMustBeUnsafe { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_bad_extern)] +#[help] +pub(crate) struct CVariadicBadExtern { + #[primary_span] + pub span: Span, + pub abi: Symbol, + #[label] + pub extern_span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_item_underscore)] pub(crate) struct ItemUnderscore<'a> { #[primary_span] @@ -489,6 +523,13 @@ pub(crate) struct MissingUnsafeOnExtern { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(ast_passes_missing_unsafe_on_extern_lint)] +pub(crate) struct MissingUnsafeOnExternLint { + #[suggestion(code = "unsafe ", applicability = "machine-applicable")] + pub suggestion: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_fieldless_union)] pub(crate) struct FieldlessUnion { @@ -660,6 +701,18 @@ pub(crate) struct ConstAndCVariadic { } #[derive(Diagnostic)] +#[diag(ast_passes_coroutine_and_c_variadic)] +pub(crate) struct CoroutineAndCVariadic { + #[primary_span] + pub spans: Vec<Span>, + pub coroutine_kind: &'static str, + #[label(ast_passes_const)] + pub coroutine_span: Span, + #[label(ast_passes_variadic)] + pub variadic_span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_pattern_in_foreign, code = E0130)] // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) pub(crate) struct PatternInForeign { diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 7fa1293463c..839a5d23c3b 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -247,3 +247,7 @@ attr_parsing_raw_dylib_only_windows = attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind + +attr_parsing_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ffdacff7152..d5d51f2e79a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser { sym::rustc_std_internal_symbol, // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity sym::rustc_align, + sym::rustc_align_static, // obviously compatible with self sym::naked, // documentation diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 2fed09b85e8..4611de44459 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,6 +1,40 @@ -use rustc_feature::AttributeType; +use std::num::IntErrorKind; + +use rustc_hir::limit::Limit; use super::prelude::*; +use crate::session_diagnostics::LimitInvalid; + +impl<S: Stage> AcceptContext<'_, '_, S> { + fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> { + let Some(limit) = nv.value_as_str() else { + self.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let error_str = match limit.as_str().parse() { + Ok(i) => return Some(Limit::new(i)), + Err(e) => match e.kind() { + IntErrorKind::PosOverflow => "`limit` is too large", + IntErrorKind::Empty => "`limit` must be a non-negative integer", + IntErrorKind::InvalidDigit => "not a valid integer", + IntErrorKind::NegOverflow => { + panic!( + "`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead" + ) + } + IntErrorKind::Zero => { + panic!("zero is a valid `limit` so should have returned Ok() when parsing") + } + kind => panic!("unimplemented IntErrorKind variant: {:?}", kind), + }, + }; + + self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str }); + + None + } +} pub(crate) struct CrateNameParser; @@ -9,11 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); - const TYPE: AttributeType = AttributeType::CrateLevel; - - // FIXME: crate name is allowed on all targets and ignored, - // even though it should only be valid on crates of course - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { let ArgParser::NameValue(n) = args else { @@ -34,3 +64,113 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser { }) } } + +pub(crate) struct RecursionLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser { + const PATH: &[Symbol] = &[sym::recursion_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::RecursionLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct MoveSizeLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser { + const PATH: &[Symbol] = &[sym::move_size_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::MoveSizeLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct TypeLengthLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser { + const PATH: &[Symbol] = &[sym::type_length_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::TypeLengthLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct PatternComplexityLimitParser; + +impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser { + const PATH: &[Symbol] = &[sym::pattern_complexity_limit]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let ArgParser::NameValue(nv) = args else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + + Some(AttributeKind::PatternComplexityLimit { + limit: cx.parse_limit_int(nv)?, + attr_span: cx.attr_span, + limit_span: nv.value_span, + }) + } +} + +pub(crate) struct NoCoreParser; + +impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser { + const PATH: &[Symbol] = &[sym::no_core]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore; +} + +pub(crate) struct NoStdParser; + +impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser { + const PATH: &[Symbol] = &[sym::no_std]; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd; +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 043bc925eac..4ed13d239b9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -12,15 +12,11 @@ //! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the //! contents of attributes, if an attribute appear multiple times in a list //! -//! By default, attributes are allowed anywhere. When adding an attribute that should only be used -//! at the crate root, consider setting the `TYPE` in the parser trait to -//! [`AttributeType::CrateLevel`](rustc_feature::AttributeType::CrateLevel). -//! //! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed. use std::marker::PhantomData; -use rustc_feature::{AttributeTemplate, AttributeType, template}; +use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -89,11 +85,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static { /// /// If an attribute has this symbol, the `accept` function will be called on it. const ATTRIBUTES: AcceptMapping<Self, S>; - const ALLOWED_TARGETS: AllowedTargets; - const TYPE: AttributeType = AttributeType::Normal; - /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. /// @@ -135,8 +128,6 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static { /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; - const TYPE: AttributeType = AttributeType::Normal; - /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>; } @@ -183,8 +174,6 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> )]; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; - const TYPE: AttributeType = T::TYPE; - fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { Some(self.1?.0) } @@ -269,7 +258,6 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static { const PATH: &[Symbol]; const ON_DUPLICATE: OnDuplicate<S>; const ALLOWED_TARGETS: AllowedTargets; - const TYPE: AttributeType = AttributeType::Normal; /// Create the [`AttributeKind`] given attribute's [`Span`]. const CREATE: fn(Span) -> AttributeKind; @@ -289,7 +277,6 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; const TEMPLATE: AttributeTemplate = template!(Word); - const TYPE: AttributeType = T::TYPE; fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { if let Err(span) = args.no_args() { @@ -323,8 +310,6 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static { /// The template this attribute parser should implement. Used for diagnostics. const TEMPLATE: AttributeTemplate; - const TYPE: AttributeType = AttributeType::Normal; - /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -360,7 +345,6 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S group.items.extend(T::extend(cx, args)) })]; const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS; - const TYPE: AttributeType = T::TYPE; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(first_span) = self.first_span { diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs index 6aef7e7a67b..980366b5c37 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -1,7 +1,6 @@ -// templates +// data structures #[doc(hidden)] pub(super) use rustc_feature::{AttributeTemplate, template}; -// data structures #[doc(hidden)] pub(super) use rustc_hir::attrs::AttributeKind; #[doc(hidden)] diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 23aabd15597..0330e2515c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser { Some(AttributeKind::Align { align, span }) } } + +#[derive(Default)] +pub(crate) struct AlignStaticParser(AlignParser); + +impl AlignStaticParser { + const PATH: &'static [Symbol] = &[sym::rustc_align_static]; + const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; + + fn parse<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + self.0.parse(cx, args) + } +} + +impl<S: Stage> AttributeParser<S> for AlignStaticParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + let (align, span) = self.0.0?; + Some(AttributeKind::Align { align, span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index fbd9a480fbb..c756bce96e2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -1,7 +1,5 @@ use std::mem; -use rustc_feature::AttributeType; - use super::prelude::*; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, @@ -155,8 +153,7 @@ pub(crate) struct CoherenceIsCoreParser; impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser { const PATH: &[Symbol] = &[sym::rustc_coherence_is_core]; const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); - const TYPE: AttributeType = AttributeType::CrateLevel; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore; } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 7f5b810f244..d7998048be5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -6,7 +6,7 @@ use std::sync::LazyLock; use private::Sealed; use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId}; use rustc_errors::{Diag, Diagnostic, Level}; -use rustc_feature::{AttributeTemplate, AttributeType}; +use rustc_feature::AttributeTemplate; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId}; @@ -24,7 +24,10 @@ use crate::attributes::codegen_attrs::{ UsedParser, }; use crate::attributes::confusables::ConfusablesParser; -use crate::attributes::crate_level::CrateNameParser; +use crate::attributes::crate_level::{ + CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, + RecursionLimitParser, TypeLengthLimitParser, +}; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::dummy::DummyParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -47,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; use crate::attributes::prototype::CustomMirParser; -use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, RustcObjectLifetimeDefaultParser, @@ -80,7 +83,6 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> { pub(super) template: AttributeTemplate, pub(super) accept_fn: AcceptFn<S>, pub(super) allowed_targets: AllowedTargets, - pub(super) attribute_type: AttributeType, } type AcceptFn<S> = @@ -130,7 +132,6 @@ macro_rules! attribute_parsers { }) }), allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS, - attribute_type: <$names as crate::attributes::AttributeParser<$stage>>::TYPE, }); } @@ -149,6 +150,7 @@ attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start AlignParser, + AlignStaticParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, @@ -181,10 +183,13 @@ attribute_parsers!( Single<LinkOrdinalParser>, Single<LinkSectionParser>, Single<LinkageParser>, + Single<MoveSizeLimitParser>, Single<MustUseParser>, Single<OptimizeParser>, Single<PathAttributeParser>, + Single<PatternComplexityLimitParser>, Single<ProcMacroDeriveParser>, + Single<RecursionLimitParser>, Single<RustcBuiltinMacroParser>, Single<RustcForceInlineParser>, Single<RustcLayoutScalarValidRangeEnd>, @@ -194,6 +199,7 @@ attribute_parsers!( Single<ShouldPanicParser>, Single<SkipDuringMethodDispatchParser>, Single<TransparencyParser>, + Single<TypeLengthLimitParser>, Single<WithoutArgs<AllowIncoherentImplParser>>, Single<WithoutArgs<AllowInternalUnsafeParser>>, Single<WithoutArgs<AsPtrParser>>, @@ -215,8 +221,10 @@ attribute_parsers!( Single<WithoutArgs<MacroEscapeParser>>, Single<WithoutArgs<MarkerParser>>, Single<WithoutArgs<MayDangleParser>>, + Single<WithoutArgs<NoCoreParser>>, Single<WithoutArgs<NoImplicitPreludeParser>>, Single<WithoutArgs<NoMangleParser>>, + Single<WithoutArgs<NoStdParser>>, Single<WithoutArgs<NonExhaustiveParser>>, Single<WithoutArgs<ParenSugarParser>>, Single<WithoutArgs<PassByValueParser>>, @@ -346,7 +354,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { - if matches!(self.stage.should_emit(), ShouldEmit::Nothing) { + if !matches!( + self.stage.should_emit(), + ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true } + ) { return; } let id = self.target_id; @@ -670,20 +681,20 @@ pub enum ShouldEmit { /// /// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`. /// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible. - EarlyFatal, + EarlyFatal { also_emit_lints: bool }, /// The operation will emit errors and lints. /// This is usually what you need. ErrorsAndLints, /// The operation will emit *not* errors and lints. - /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`. + /// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`. Nothing, } impl ShouldEmit { pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed { match self { - ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(), - ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(), + ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(), + ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(), ShouldEmit::ErrorsAndLints => diag.emit(), ShouldEmit::Nothing => diag.delay_as_bug(), } diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 0fe3c209421..8f2de4af14e 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -272,7 +272,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { (accept.accept_fn)(&mut cx, args); if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) { - Self::check_type(accept.attribute_type, target, &mut cx); Self::check_target(&accept.allowed_targets, target, &mut cx); } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index a9dee23bf6a..32ea9005a97 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -930,3 +930,13 @@ pub(crate) struct ImportNameTypeRaw { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(attr_parsing_limit_invalid)] +pub(crate) struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index edc496b460c..c52253699b5 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_ast::AttrStyle; use rustc_errors::DiagArgValue; -use rustc_feature::{AttributeType, Features}; +use rustc_feature::Features; use rustc_hir::lints::AttributeLintKind; use rustc_hir::{MethodKind, Target}; @@ -14,6 +14,11 @@ use crate::session_diagnostics::InvalidTarget; pub(crate) enum AllowedTargets { AllowList(&'static [Policy]), AllowListWarnRest(&'static [Policy]), + /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`. + /// For crate-level attributes we emit a specific set of lints to warn + /// people about accidentally not using them on the crate. + /// Only use this for attributes that are *exclusively* valid at the crate level. + CrateLevel, } pub(crate) enum AllowedResult { @@ -43,6 +48,7 @@ impl AllowedTargets { AllowedResult::Warn } } + AllowedTargets::CrateLevel => AllowedResult::Allowed, } } @@ -50,6 +56,7 @@ impl AllowedTargets { match self { AllowedTargets::AllowList(list) => list, AllowedTargets::AllowListWarnRest(list) => list, + AllowedTargets::CrateLevel => ALL_TARGETS, } .iter() .filter_map(|target| match target { @@ -74,6 +81,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { + Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx); + match allowed_targets.is_allowed(target) { AllowedResult::Allowed => {} AllowedResult::Warn => { @@ -109,7 +118,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } pub(crate) fn check_type( - attribute_type: AttributeType, + crate_level: bool, target: Target, cx: &mut AcceptContext<'_, 'sess, S>, ) { @@ -119,7 +128,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { return; } - if attribute_type != AttributeType::CrateLevel { + if !crate_level { return; } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index ea264c8064a..6d69040c711 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -716,7 +716,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { return (false, false, None); }; - let implemented_trait_item = self.infcx.tcx.associated_item(my_def).trait_item_def_id; + let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def); ( true, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 9990f4cb3f2..f57456949bb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -615,7 +615,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Type-test failed. Report the error. - let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind); + let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind); // Skip duplicate-ish errors. if deduplicate_errors.insert(( diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index 95c5366a6c8..0af636aa734 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -341,7 +341,7 @@ fn compute_concrete_types_from_defining_uses<'tcx>( // // FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again. if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert( - rcx.infcx.tcx.erase_regions(opaque_type_key), + rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key), (opaque_type_key, hidden_type.span), ) && let Some((arg1, arg2)) = std::iter::zip( prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 02be78f90b0..8c5447fe1e9 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1892,7 +1892,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if is_diverging { // The signature in this call can reference region variables, // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); + let output_ty = self.tcx().erase_and_anonymize_regions(sig.output()); if !output_ty .is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env)) { @@ -1986,7 +1986,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) + ConstraintCategory::CallArgument(Some( + self.infcx.tcx.erase_and_anonymize_regions(func_ty), + )) } else { ConstraintCategory::Boring }; @@ -2120,7 +2122,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(ty); + let erased_ty = tcx.erase_and_anonymize_regions(ty); // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) { // in current MIR construction, all non-control-flow rvalue diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 358c0d3db46..7c1a5f44e16 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -64,6 +64,11 @@ builtin_macros_autodiff_ty_activity = {$act} can not be used for this type builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}` builtin_macros_autodiff_width = autodiff width must fit u32, but is {$width} + +builtin_macros_avoid_att_syntax = avoid using `.att_syntax`, prefer using `options(att_syntax)` instead + +builtin_macros_avoid_intel_syntax = avoid using `.intel_syntax`, Intel syntax is the default + builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s .label = not applicable here .label2 = not a `struct`, `enum` or `union` @@ -138,6 +143,8 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value +builtin_macros_duplicate_macro_attribute = duplicated attribute + builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time @@ -231,6 +238,8 @@ builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struc builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field +builtin_macros_incomplete_include = include macro expected single expression in source + builtin_macros_multiple_default_attrs = multiple `#[default]` attributes .note = only one `#[default]` attribute is needed .label = `#[default]` used here @@ -294,3 +303,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal .label = not a trait .str_lit = try using `#[derive({$sym})]` .other = for example, write `#[derive(Debug)]` for `Debug` + +builtin_macros_unnameable_test_items = cannot test inner items diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 86b8e1ff8db..ae62b5ea2a0 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -1,4 +1,3 @@ -use lint::BuiltinLintDiag; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AsmMacro, token}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -352,7 +351,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".intel_syntax"), ecx.current_expansion.lint_node_id, - BuiltinLintDiag::AvoidUsingIntelSyntax, + errors::AvoidIntelSyntax, ); } if template_str.contains(".att_syntax") { @@ -360,7 +359,7 @@ fn expand_preparsed_asm( lint::builtin::BAD_ASM_STYLE, find_span(".att_syntax"), ecx.current_expansion.lint_node_id, - BuiltinLintDiag::AvoidUsingAttSyntax, + errors::AvoidAttSyntax, ); } } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 013258a1b4e..855da5caa31 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -1,8 +1,8 @@ mod context; -use rustc_ast::token::{self, Delimiter}; +use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment}; +use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token}; use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; @@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>( // `core::panic` and `std::panic` are different macros, so we use call-site // context to pick up whichever is currently in scope. - let call_site_span = cx.with_call_site_ctxt(cond_expr.span); + let call_site_span = cx.with_call_site_ctxt(span); let panic_path = || { if use_panic_2021(span) { @@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>( }), })), ); - assert_cond_check(cx, call_site_span, cond_expr, then) + expr_if_not(cx, call_site_span, cond_expr, then, None) } // If `generic_assert` is enabled, generates rich captured outputs // @@ -88,33 +88,26 @@ pub(crate) fn expand_assert<'cx>( )), )], ); - assert_cond_check(cx, call_site_span, cond_expr, then) + expr_if_not(cx, call_site_span, cond_expr, then, None) }; ExpandResult::Ready(MacEager::expr(expr)) } -/// `assert!($cond_expr, $custom_message)` struct Assert { cond_expr: Box<Expr>, custom_message: Option<TokenStream>, } -/// `match <cond> { true => {} _ => <then> }` -fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box<Expr>, then: Box<Expr>) -> Box<Expr> { - // Instead of expanding to `if !<cond> { <then> }`, we expand to - // `match <cond> { true => {} _ => <then> }`. - // This allows us to always complain about mismatched types instead of "cannot apply unary - // operator `!` to type `X`" when passing an invalid `<cond>`, while also allowing `<cond>` to - // be `&true`. - let els = cx.expr_block(cx.block(span, thin_vec![])); - let mut arms = thin_vec![]; - arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els)); - arms.push(cx.arm(span, cx.pat_wild(span), then)); - - // We wrap the `match` in a statement to limit the length of any borrows introduced in the - // condition. - cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into())) +// if !{ ... } { ... } else { ... } +fn expr_if_not( + cx: &ExtCtxt<'_>, + span: Span, + cond: Box<Expr>, + then: Box<Expr>, + els: Option<Box<Expr>>, +) -> Box<Expr> { + cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els) } fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 54e8f750337..0993fdc5be4 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -3,9 +3,29 @@ use rustc_errors::{ Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans, Subdiagnostic, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; +#[derive(LintDiagnostic)] +#[diag(builtin_macros_avoid_intel_syntax)] +pub(crate) struct AvoidIntelSyntax; + +#[derive(LintDiagnostic)] +#[diag(builtin_macros_avoid_att_syntax)] +pub(crate) struct AvoidAttSyntax; + +#[derive(LintDiagnostic)] +#[diag(builtin_macros_incomplete_include)] +pub(crate) struct IncompleteInclude; + +#[derive(LintDiagnostic)] +#[diag(builtin_macros_unnameable_test_items)] +pub(crate) struct UnnameableTestItems; + +#[derive(LintDiagnostic)] +#[diag(builtin_macros_duplicate_macro_attribute)] +pub(crate) struct DuplicateMacroAttribute; + #[derive(Diagnostic)] #[diag(builtin_macros_requires_cfg_pattern)] pub(crate) struct RequiresCfgPattern { diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6415e55e0b0..d70888205a5 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -565,9 +565,11 @@ fn make_format_args( &used, &args, &pieces, + &invalid_refs, detect_foreign_fmt, str_style, fmt_str, + uncooked_fmt_str.1.as_str(), fmt_span, ); } @@ -645,9 +647,11 @@ fn report_missing_placeholders( used: &[bool], args: &FormatArguments, pieces: &[parse::Piece<'_>], + invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)], detect_foreign_fmt: bool, str_style: Option<usize>, fmt_str: &str, + uncooked_fmt_str: &str, fmt_span: Span, ) { let mut diag = if let &[(span, named)] = &unused[..] { @@ -762,6 +766,35 @@ fn report_missing_placeholders( diag.span_label(fmt_span, "formatting specifier missing"); } + if !found_foreign && invalid_refs.is_empty() { + // Show example if user didn't use any format specifiers + let show_example = used.iter().all(|used| !used); + + if !show_example { + if unused.len() > 1 { + diag.note(format!("consider adding {} format specifiers", unused.len())); + } + } else { + let msg = if unused.len() == 1 { + "a format specifier".to_string() + } else { + format!("{} format specifiers", unused.len()) + }; + + let sugg = match str_style { + None => format!("\"{}{}\"", uncooked_fmt_str, "{}".repeat(unused.len())), + Some(n_hashes) => format!( + "r{hashes}\"{uncooked_fmt_str}{fmt_specifiers}\"{hashes}", + hashes = "#".repeat(n_hashes), + fmt_specifiers = "{}".repeat(unused.len()) + ), + }; + let msg = format!("format specifiers use curly braces, consider adding {msg}"); + + diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect); + } + } + diag.emit(); } diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 37bab5be542..16adaab15c5 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,3 +1,5 @@ +//! The implementation of built-in macros which relate to the file system. + use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; @@ -10,10 +12,11 @@ use rustc_expand::base::{ DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path, }; use rustc_expand::module::DirOwnership; -use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::lexer::StripTokens; +use rustc_parse::parser::ForceCollect; use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; +use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::{ByteSymbol, Pos, Span, Symbol}; use smallvec::SmallVec; @@ -23,11 +26,7 @@ use crate::util::{ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, }; -// These macros all relate to the file system; they either return -// the column/row/filename of the expression, or they include -// a given file into the current one. - -/// line!(): expands to the current line number +/// Expand `line!()` to the current line number. pub(crate) fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, @@ -42,7 +41,7 @@ pub(crate) fn expand_line( ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32))) } -/* column!(): expands to the current column number */ +/// Expand `column!()` to the current column number. pub(crate) fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, @@ -57,9 +56,7 @@ pub(crate) fn expand_column( ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))) } -/// file!(): expands to the current filename */ -/// The source_file (`loc.file`) contains a bunch more information we could spit -/// out if we wanted. +/// Expand `file!()` to the current filename. pub(crate) fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, @@ -81,6 +78,7 @@ pub(crate) fn expand_file( ))) } +/// Expand `stringify!($input)`. pub(crate) fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, @@ -91,6 +89,7 @@ pub(crate) fn expand_stringify( ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))) } +/// Expand `module_path!()` to (a textual representation of) the current module path. pub(crate) fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, @@ -104,9 +103,9 @@ pub(crate) fn expand_mod( ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) } -/// include! : parse the given file as an expr -/// This is generally a bad idea because it's going to behave -/// unhygienically. +/// Expand `include!($input)`. +/// +/// This works in item and expression position. Notably, it doesn't work in pattern position. pub(crate) fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -116,64 +115,76 @@ pub(crate) fn expand_include<'cx>( let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else { return ExpandResult::Retry(()); }; - let file = match mac { - Ok(file) => file, + let path = match mac { + Ok(path) => path, Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; // The file will be added to the code map by the parser - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, + let path = match resolve_path(&cx.sess, path.as_str(), sp) { + Ok(path) => path, Err(err) => { let guar = err.emit(); return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, - // then the path of `bar.rs` should be relative to the directory of `file`. + // then the path of `bar.rs` should be relative to the directory of `path`. // See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion. // `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained. - let dir_path = file.parent().unwrap_or(&file).to_owned(); + let dir_path = path.parent().unwrap_or(&path).to_owned(); cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path)); cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None }; struct ExpandInclude<'a> { - p: Parser<'a>, + psess: &'a ParseSess, + path: PathBuf, node_id: ast::NodeId, + span: Span, } impl<'a> MacResult for ExpandInclude<'a> { - fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> { - let expr = parse_expr(&mut self.p).ok()?; - if self.p.token != token::Eof { - self.p.psess.buffer_lint( + fn make_expr(self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> { + let mut p = unwrap_or_emit_fatal(new_parser_from_file( + self.psess, + &self.path, + // Don't strip frontmatter for backward compatibility, `---` may be the start of a + // manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either. + StripTokens::Shebang, + Some(self.span), + )); + let expr = parse_expr(&mut p).ok()?; + if p.token != token::Eof { + p.psess.buffer_lint( INCOMPLETE_INCLUDE, - self.p.token.span, + p.token.span, self.node_id, - BuiltinLintDiag::IncompleteInclude, + errors::IncompleteInclude, ); } Some(expr) } - fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { + fn make_items(self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { + let mut p = unwrap_or_emit_fatal(new_parser_from_file( + self.psess, + &self.path, + StripTokens::ShebangAndFrontmatter, + Some(self.span), + )); let mut ret = SmallVec::new(); loop { - match self.p.parse_item(ForceCollect::No) { + match p.parse_item(ForceCollect::No) { Err(err) => { err.emit(); break; } Ok(Some(item)) => ret.push(item), Ok(None) => { - if self.p.token != token::Eof { - self.p - .dcx() - .create_err(errors::ExpectedItem { - span: self.p.token.span, - token: &pprust::token_to_string(&self.p.token), - }) - .emit(); + if p.token != token::Eof { + p.dcx().emit_err(errors::ExpectedItem { + span: p.token.span, + token: &pprust::token_to_string(&p.token), + }); } break; @@ -184,10 +195,17 @@ pub(crate) fn expand_include<'cx>( } } - ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id })) + ExpandResult::Ready(Box::new(ExpandInclude { + psess: cx.psess(), + path, + node_id: cx.current_expansion.lint_node_id, + span: sp, + })) } -/// `include_str!`: read the given file, insert it as a literal string expr +/// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal. +/// +/// This works in expression, pattern and statement position. pub(crate) fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, @@ -206,6 +224,7 @@ pub(crate) fn expand_include_str( Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); + // MacEager converts the expr into a pat if need be. MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } Err(utf8err) => { @@ -218,6 +237,9 @@ pub(crate) fn expand_include_str( }) } +/// Expand `include_bytes!($input)` to the content of the file given by path `$input`. +/// +/// This works in expression, pattern and statement position. pub(crate) fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, @@ -237,6 +259,7 @@ pub(crate) fn expand_include_bytes( // Don't care about getting the span for the raw bytes, // because the console can't really show them anyway. let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes))); + // MacEager converts the expr into a pat if need be. MacEager::expr(expr) } Err(dummy) => dummy, diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a9d91f77560..51089e5a1d3 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -11,7 +11,6 @@ use rustc_errors::DiagCtxtHandle; use rustc_expand::base::{ExtCtxt, ResolverExpand}; use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; -use rustc_lint_defs::BuiltinLintDiag; use rustc_session::Session; use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; @@ -165,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> { UNNAMEABLE_TEST_ITEMS, attr.span, i.id, - BuiltinLintDiag::UnnameableTestItems, + errors::UnnameableTestItems, ); } } diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 3a4585d5be9..e26f31dce67 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -5,7 +5,6 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; -use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; use rustc_parse::{exp, parser}; use rustc_session::errors::report_lit_error; @@ -49,7 +48,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, DUPLICATE_MACRO_ATTRIBUTES, attr.span, ecx.current_expansion.lint_node_id, - BuiltinLintDiag::DuplicateMacroAttribute, + errors::DuplicateMacroAttribute, ); } } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 619277eba8b..7fe8fc122b3 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { if global.to_rvalue().get_type() != val_llty { global.to_rvalue().set_type(val_llty); } + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, global, alloc.align); global.global_set_initializer_rvalue(value); diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 093f902bc3d..93202483eed 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -240,7 +240,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(self.ty); + let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty); let mut defer = None; let ty = if self.ty != normal_ty { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 9ec7b0f80ae..dc9bb743560 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> { self.statics_to_rauw.borrow_mut().push((g, new_g)); new_g }; + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, g, alloc.align); llvm::set_initializer(g, v); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index caa3369f413..dc3a84b6a15 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -103,16 +103,17 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, unique_type_id: UniqueTypeId<'tcx>, array_type: Ty<'tcx>, + span: Span, ) -> DINodeCreationResult<'ll> { let ty::Array(element_type, len) = array_type.kind() else { bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type) }; - let element_type_di_node = type_di_node(cx, *element_type); + let element_type_di_node = spanned_type_di_node(cx, *element_type, span); return_if_di_node_created_in_meantime!(cx, unique_type_id); - let (size, align) = cx.size_and_align_of(array_type); + let (size, align) = cx.spanned_size_and_align_of(array_type, span); let upper_bound = len .try_to_target_usize(cx.tcx) @@ -447,7 +448,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>( build_basic_type_di_node(cx, t) } ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t), - ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t), + ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span), ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id), ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id), ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id), @@ -1435,7 +1436,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>( let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); - let trait_ref = tcx.erase_regions(trait_ref); + let trait_ref = tcx.erase_and_anonymize_regions(trait_ref); tcx.vtable_entries(trait_ref) } else { @@ -1562,7 +1563,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( // Unwrap potential addrspacecast let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); - let trait_ref_self = cx.tcx.erase_regions(trait_ref_self); + let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self); let trait_def_id = trait_ref_self.def_id; let trait_vis = cx.tcx.visibility(trait_def_id); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 4e7096da502..84998b5499b 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -7,6 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt}; +use rustc_span::{DUMMY_SP, Span}; use tracing::debug; use crate::common::*; @@ -149,7 +150,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { } pub(crate) fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) { - let layout = self.layout_of(ty); + self.spanned_size_and_align_of(ty, DUMMY_SP) + } + + pub(crate) fn spanned_size_and_align_of(&self, ty: Ty<'tcx>, span: Span) -> (Size, Align) { + let layout = self.spanned_layout_of(ty, span); (layout.size, layout.align.abi) } } @@ -226,7 +231,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(self.ty); + let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty); let mut defer = None; let llty = if self.ty != normal_ty { diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 7eb5d302058..ab08125217f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -908,6 +908,21 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( ) } "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty), + "arm" => { + // Types wider than 16 bytes are not currently supported. Clang has special logic for + // such types, but `VaArgSafe` is not implemented for any type that is this large. + assert!(bx.cx.size_of(target_ty).bytes() <= 16); + + emit_ptr_va_arg( + bx, + addr, + target_ty, + PassMode::Direct, + SlotSize::Bytes4, + AllowHigherAlign::Yes, + ForceRightAdjust::No, + ) + } "s390x" => emit_s390x_va_arg(bx, addr, target_ty), "powerpc" => emit_powerpc_va_arg(bx, addr, target_ty), "powerpc64" | "powerpc64le" => emit_ptr_va_arg( diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 2dfbc581643..5462163f4ff 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -9,7 +9,7 @@ ar_archive_writer = "0.5" bitflags = "2.4.1" bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version -# per crate", so if you change this, you need to also change it in `rustc_llvm`. +# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_windows_rc`. cc = "=1.2.16" itertools = "0.12" pathdiff = "0.2.0" diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index dd688b8b345..1dd65d38a2b 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -31,7 +31,7 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} codegen_ssa_dlltool_fail_import_library = - Dlltool could not create import library with {$dlltool_path} {$dlltool_args}: + dlltool could not create import library with {$dlltool_path} {$dlltool_args}: {$stdout} {$stderr} diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 05351bd6ca3..7420f18aacb 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -109,7 +109,7 @@ impl Command { } Program::Lld(ref p, flavor) => { let mut c = process::Command::new(p); - c.arg("-flavor").arg(flavor.as_str()); + c.arg("-flavor").arg(flavor.desc()); c } }; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 008340e614d..dc500c363f4 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -562,15 +562,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs } -/// If the provided DefId is a method in a trait impl, return the DefId of the method prototype. -fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { - let impl_item = tcx.opt_associated_item(def_id)?; - match impl_item.container { - ty::AssocItemContainer::Impl => impl_item.trait_item_def_id, - _ => None, - } -} - fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet { // Backtrack to the crate root. let mut disabled = match tcx.opt_local_parent(did) { @@ -600,14 +591,15 @@ fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet { /// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let Some(trait_item) = opt_trait_item(tcx, def_id) else { return false }; - tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER) + tcx.trait_item_of(def_id).is_some_and(|id| { + tcx.codegen_fn_attrs(id).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER) + }) } /// If the provided DefId is a method in a trait impl, return the value of the `#[align]` /// attribute on the method prototype (if any). fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> { - tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment + tcx.codegen_fn_attrs(tcx.trait_item_of(def_id)?).alignment } /// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 5f6976f5d00..6492ef73956 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -520,7 +520,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Place(va_list) => { bx.va_end(va_list.val.llval); - // Explicitly end the lifetime of the `va_list`, this matters for LLVM. + // Explicitly end the lifetime of the `va_list`, improves LLVM codegen. bx.lifetime_end(va_list.val.llval, va_list.layout.size); } _ => bug!("C-variadic function must have a `VaList` place"), diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 06873313e2e..6b109e8b8e2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -438,6 +438,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + + // Explicitly start the lifetime of the `va_list`, improves LLVM codegen. + bx.lifetime_start(va_list.val.llval, va_list.layout.size); + bx.va_start(va_list.val.llval); return LocalRef::Place(va_list); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 9681d89ce35..91ed71ac3e5 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,6 +4,7 @@ use either::{Left, Right}; use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::DefId; +use rustc_hir::limit::Limit; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ @@ -12,7 +13,6 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance}; use rustc_middle::{mir, span_bug}; -use rustc_session::Limit; use rustc_span::Span; use rustc_target::callconv::FnAbi; use tracing::{debug, trace}; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 2c1e5087e1c..ebcdb9461d0 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { + // NOTE: `static` alignment from attributes has already been applied to the allocation. let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { @@ -1501,8 +1502,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `get_bytes_mut` will clear the provenance, which is correct, // since we don't want to keep any provenance at the target. // This will also error if copying partial provenance is not supported. - let provenance = - src_alloc.provenance().prepare_copy(src_range, dest_offset, num_copies, self); + let provenance = src_alloc + .provenance() + .prepare_copy(src_range, dest_offset, num_copies, self) + .map_err(|e| e.to_interp_error(src_alloc_id))?; // Prepare a copy of the initialization mask. let init = src_alloc.init_mask().prepare_copy(src_range); diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index e4b5c82853a..870f9a396ae 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -23,7 +23,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { trace!("get_vtable(ty={ty:?}, dyn_ty={dyn_ty:?})"); - let (ty, dyn_ty) = self.tcx.erase_regions((ty, dyn_ty)); + let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty)); // All vtables must be monomorphic, bail out otherwise. ensure_monomorphic_enough(*self.tcx, ty)?; @@ -53,8 +53,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> &'tcx [VtblEntry<'tcx>] { if let Some(trait_) = trait_ { let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty); - let trait_ref = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); + let trait_ref = self.tcx.erase_and_anonymize_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_ref), + ); self.tcx.vtable_entries(trait_ref) } else { TyCtxt::COMMON_VTABLE_ENTRIES diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 72bee345406..f667823723c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; +use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; use tracing::debug; @@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>( static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?; + // Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating + // the alignment attribute logic. + let (size, align) = + GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env); + assert_eq!(size, layout.size); + assert!(align >= layout.align.abi); + + let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 2ae6655901b..5bcf96abd8c 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -168,10 +168,11 @@ impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> { // Bound regions are always printed (as `'_`), which gives some idea that they are special, // even though the `for` is omitted by the pretty printer. // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)". + let kind = region.kind(); match region.kind() { - ty::ReErased | ty::ReEarlyParam(_) => false, + ty::ReErased | ty::ReEarlyParam(_) | ty::ReStatic => false, ty::ReBound(..) => true, - _ => unreachable!(), + _ => panic!("type_name unhandled region: {kind:?}"), } } diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index e3ee8351295..51909719827 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -10,3 +10,8 @@ crate-type = ["dylib"] # tidy-alphabetical-start rustc_driver_impl = { path = "../rustc_driver_impl" } # tidy-alphabetical-end + +[build-dependencies] +# tidy-alphabetical-start +rustc_windows_rc = { path = "../rustc_windows_rc" } +# tidy-alphabetical-end diff --git a/compiler/rustc_driver/build.rs b/compiler/rustc_driver/build.rs new file mode 100644 index 00000000000..ba44fe7a86e --- /dev/null +++ b/compiler/rustc_driver/build.rs @@ -0,0 +1,21 @@ +use std::{env, path}; + +use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file}; + +fn main() { + let target_os = env::var("CARGO_CFG_TARGET_OS"); + let target_env = env::var("CARGO_CFG_TARGET_ENV"); + if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() { + set_windows_dll_options(); + } else { + // Avoid rerunning the build script every time. + println!("cargo:rerun-if-changed=build.rs"); + } +} + +fn set_windows_dll_options() { + let stem = path::PathBuf::from("rustc_driver_resource"); + let file_description = "rustc_driver"; + let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::Dll); + println!("cargo:rustc-link-arg={}", res_file.display()); +} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index f3ed6042105..4f875cf99ec 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -51,6 +51,7 @@ use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; use rustc_middle::ty::TyCtxt; +use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot, @@ -667,6 +668,10 @@ fn print_crate_info( TargetSpecJson => { println_info!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap()); } + TargetSpecJsonSchema => { + let schema = rustc_target::spec::json_schema(); + println_info!("{}", serde_json::to_string_pretty(&schema).unwrap()); + } AllTargetSpecsJson => { let mut targets = BTreeMap::new(); for name in rustc_target::spec::TARGETS { @@ -1288,10 +1293,15 @@ fn warn_on_confusing_output_filename_flag( fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { - Input::File(file) => new_parser_from_file(&sess.psess, file, None), - Input::Str { name, input } => { - new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) + Input::File(file) => { + new_parser_from_file(&sess.psess, file, StripTokens::ShebangAndFrontmatter, None) } + Input::Str { name, input } => new_parser_from_source_str( + &sess.psess, + name.clone(), + input.clone(), + StripTokens::ShebangAndFrontmatter, + ), }); parser.parse_inner_attributes() } diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 61ba716d082..47c00bff5c9 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -3,6 +3,8 @@ expand_attributes_on_expressions_experimental = .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//` .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !` +expand_cfg_attr_no_attributes = `#[cfg_attr]` does not expand to any attributes + expand_collapse_debuginfo_illegal = illegal value for attribute #[collapse_debuginfo(no|external|yes)] @@ -78,6 +80,10 @@ expand_macro_body_stability = .label = invalid body stability attribute .label2 = body stability attribute affects this macro +expand_macro_call_unused_doc_comment = unused doc comment + .label = rustdoc does not generate documentation for macro invocations + .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion + expand_macro_const_stability = macros cannot have const stability attributes .label = invalid const stability attribute @@ -89,6 +95,13 @@ expand_malformed_feature_attribute = malformed `feature` attribute input .expected = expected just one word +expand_metavar_still_repeating = variable `{$ident}` is still repeating at this depth + .label = expected repetition + +expand_metavariable_wrong_operator = meta-variable repeats with different Kleene operator + .binder_label = expected repetition + .occurrence_label = conflicting repetition + expand_meta_var_dif_seq_matchers = {$msg} expand_missing_fragment_specifier = missing fragment specifier @@ -147,6 +160,9 @@ expand_mve_unrecognized_var = expand_non_inline_modules_in_proc_macro_input_are_unstable = non-inline modules in proc macro input are unstable +expand_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro + .suggestion = use pat_param to preserve semantics + expand_proc_macro_back_compat = using an old version of `{$crate_name}` .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives @@ -176,11 +192,18 @@ expand_resolve_relative_path = expand_trace_macro = trace_macro +expand_trailing_semi_macro = trailing semicolon in macro used in expression position + .note1 = macro invocations at the end of a block are treated as expressions + .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` + +expand_unknown_macro_variable = unknown macro variable `{$name}` + +expand_unused_builtin_attribute = unused attribute `{$attr_name}` + .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}` + .suggestion = remove the attribute + expand_unsupported_key_value = key-value macro attributes are not supported -expand_var_still_repeating = - variable `{$ident}` is still repeating at this depth - expand_wrong_fragment_kind = non-{$kind} macro in {$kind} position: {$name} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 8ff21509f4a..88f88f30a8c 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -18,13 +18,14 @@ use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; use rustc_hir::def::MacroKinds; +use rustc_hir::limit::Limit; use rustc_hir::{Stability, find_attr}; use rustc_lint_defs::RegisteredTools; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_session::Session; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; -use rustc_session::{Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 15419ab7423..2925e337071 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -21,7 +21,6 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; -use rustc_lint_defs::BuiltinLintDiag; use rustc_session::Session; use rustc_session::parse::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; @@ -315,7 +314,7 @@ impl<'a> StripUnconfigured<'a> { rustc_lint_defs::builtin::UNUSED_ATTRIBUTES, cfg_attr.span, ast::CRATE_NODE_ID, - BuiltinLintDiag::CfgAttrNoAttributes, + crate::errors::CfgAttrNoAttributes, ); } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index ba9d76970f0..c37c2d88d9c 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -2,10 +2,14 @@ use std::borrow::Cow; use rustc_ast::ast; use rustc_errors::codes::*; -use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_session::Limit; +use rustc_hir::limit::Limit; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; +#[derive(LintDiagnostic)] +#[diag(expand_cfg_attr_no_attributes)] +pub(crate) struct CfgAttrNoAttributes; + #[derive(Diagnostic)] #[diag(expand_expr_repeat_no_syntax_vars)] pub(crate) struct NoSyntaxVarsExprRepeat { @@ -28,13 +32,30 @@ pub(crate) struct CountRepetitionMisplaced { } #[derive(Diagnostic)] -#[diag(expand_var_still_repeating)] -pub(crate) struct VarStillRepeating { +#[diag(expand_metavar_still_repeating)] +pub(crate) struct MacroVarStillRepeating { #[primary_span] pub span: Span, pub ident: MacroRulesNormalizedIdent, } +#[derive(LintDiagnostic)] +#[diag(expand_metavar_still_repeating)] +pub(crate) struct MetaVarStillRepeatingLint { + #[label] + pub label: Span, + pub ident: MacroRulesNormalizedIdent, +} + +#[derive(LintDiagnostic)] +#[diag(expand_metavariable_wrong_operator)] +pub(crate) struct MetaVariableWrongOperator { + #[label(expand_binder_label)] + pub binder: Span, + #[label(expand_occurrence_label)] + pub occurrence: Span, +} + #[derive(Diagnostic)] #[diag(expand_meta_var_dif_seq_matchers)] pub(crate) struct MetaVarsDifSeqMatchers { @@ -43,6 +64,12 @@ pub(crate) struct MetaVarsDifSeqMatchers { pub msg: String, } +#[derive(LintDiagnostic)] +#[diag(expand_unknown_macro_variable)] +pub(crate) struct UnknownMacroVariable { + pub name: MacroRulesNormalizedIdent, +} + #[derive(Diagnostic)] #[diag(expand_resolve_relative_path)] pub(crate) struct ResolveRelativePath { @@ -345,6 +372,15 @@ pub(crate) struct DuplicateMatcherBinding { pub prev: Span, } +#[derive(LintDiagnostic)] +#[diag(expand_duplicate_matcher_binding)] +pub(crate) struct DuplicateMatcherBindingLint { + #[label] + pub span: Span, + #[label(expand_label2)] + pub prev: Span, +} + #[derive(Diagnostic)] #[diag(expand_missing_fragment_specifier)] #[note] @@ -501,3 +537,39 @@ pub(crate) struct MacroArgsBadDelimSugg { #[suggestion_part(code = ")")] pub close: Span, } + +#[derive(LintDiagnostic)] +#[diag(expand_macro_call_unused_doc_comment)] +#[help] +pub(crate) struct MacroCallUnusedDocComment { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(expand_or_patterns_back_compat)] +pub(crate) struct OrPatternsBackCompat { + #[suggestion(code = "{suggestion}", applicability = "machine-applicable")] + pub span: Span, + pub suggestion: String, +} + +#[derive(LintDiagnostic)] +#[diag(expand_trailing_semi_macro)] +pub(crate) struct TrailingMacro { + #[note(expand_note1)] + #[note(expand_note2)] + pub is_trailing: bool, + pub name: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(expand_unused_builtin_attribute)] +pub(crate) struct UnusedBuiltinAttribute { + #[note] + pub invoc_span: Span, + pub attr_name: Symbol, + pub macro_name: String, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub attr_span: Span, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index dbb4a9de9e0..4c0e0bbfe26 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -19,14 +19,14 @@ use rustc_errors::PResult; use rustc_feature::Features; use rustc_hir::Target; use rustc_hir::def::MacroKinds; +use rustc_hir::limit::Limit; use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, token_descr, }; -use rustc_session::lint::BuiltinLintDiag; +use rustc_session::Session; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; use rustc_session::parse::feature_err; -use rustc_session::{Limit, Session}; use rustc_span::hygiene::SyntaxContext; use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym}; use smallvec::SmallVec; @@ -2182,7 +2182,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { UNUSED_DOC_COMMENTS, current_span, self.cx.current_expansion.lint_node_id, - BuiltinLintDiag::UnusedDocComment(attr.span), + crate::errors::MacroCallUnusedDocComment { span: attr.span }, ); } else if rustc_attr_parsing::is_builtin_attr(attr) && !AttributeParser::<Early>::is_parsed_attribute(&attr.path()) @@ -2195,7 +2195,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { UNUSED_ATTRIBUTES, attr.span, self.cx.current_expansion.lint_node_id, - BuiltinLintDiag::UnusedBuiltinAttribute { + crate::errors::UnusedBuiltinAttribute { attr_name, macro_name: pprust::path_to_string(&call.path), invoc_span: call.path.span, @@ -2529,6 +2529,7 @@ impl ExpansionConfig<'_> { ExpansionConfig { crate_name, features, + // FIXME should this limit be configurable? recursion_limit: Limit::new(1024), trace_mac: false, should_test: false, diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index faeae1f494e..ebd6e887f7d 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -108,8 +108,7 @@ use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind}; use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::MultiSpan; -use rustc_lint_defs::BuiltinLintDiag; +use rustc_errors::DecorateDiagCompat; use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw}; @@ -245,9 +244,12 @@ fn check_binders( // There are 3 possibilities: if let Some(prev_info) = binders.get(&name) { // 1. The meta-variable is already bound in the current LHS: This is an error. - let mut span = MultiSpan::from_span(span); - span.push_span_label(prev_info.span, "previous declaration"); - buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding); + buffer_lint( + psess, + span, + node_id, + errors::DuplicateMatcherBindingLint { span, prev: prev_info.span }, + ); } else if get_binder_info(macros, binders, name).is_none() { // 2. The meta-variable is free: This is a binder. binders.insert(name, BinderInfo { span, ops: ops.into() }); @@ -579,7 +581,7 @@ fn check_ops_is_prefix( return; } } - buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name)); + buffer_lint(psess, span, node_id, errors::UnknownMacroVariable { name }); } /// Returns whether `binder_ops` is a prefix of `occurrence_ops`. @@ -604,29 +606,42 @@ fn ops_is_prefix( psess: &ParseSess, node_id: NodeId, span: Span, - name: MacroRulesNormalizedIdent, + ident: MacroRulesNormalizedIdent, binder_ops: &[KleeneToken], occurrence_ops: &[KleeneToken], ) { for (i, binder) in binder_ops.iter().enumerate() { if i >= occurrence_ops.len() { - let mut span = MultiSpan::from_span(span); - span.push_span_label(binder.span, "expected repetition"); - buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name)); + buffer_lint( + psess, + span, + node_id, + errors::MetaVarStillRepeatingLint { label: binder.span, ident }, + ); return; } let occurrence = &occurrence_ops[i]; if occurrence.op != binder.op { - let mut span = MultiSpan::from_span(span); - span.push_span_label(binder.span, "expected repetition"); - span.push_span_label(occurrence.span, "conflicting repetition"); - buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator); + buffer_lint( + psess, + span, + node_id, + errors::MetaVariableWrongOperator { + binder: binder.span, + occurrence: occurrence.span, + }, + ); return; } } } -fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) { +fn buffer_lint( + psess: &ParseSess, + span: Span, + node_id: NodeId, + diag: impl Into<DecorateDiagCompat>, +) { // Macros loaded from other crates have dummy node ids. if node_id != DUMMY_NODE_ID { psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 8b43f852b26..946265eba8b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -17,7 +17,6 @@ use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::MacroKinds; use rustc_hir::find_attr; -use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, }; @@ -90,7 +89,7 @@ impl<'a> ParserAnyMacro<'a> { SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, parser.token.span, lint_node_id, - BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident), + errors::TrailingMacro { is_trailing: is_trailing_mac, name: macro_ident }, ); } parser.bump(); @@ -1425,7 +1424,7 @@ fn check_matcher_core<'tt>( RUST_2021_INCOMPATIBLE_OR_PATTERNS, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::OrPatternsBackCompat(span, suggestion), + errors::OrPatternsBackCompat { span, suggestion }, ); } match is_in_follow(next_token, kind) { diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index e4e4866b64c..6a3f1f62c91 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -17,8 +17,8 @@ use rustc_span::{ use smallvec::{SmallVec, smallvec}; use crate::errors::{ - CountRepetitionMisplaced, MetaVarsDifSeqMatchers, MustRepeatOnce, MveUnrecognizedVar, - NoSyntaxVarsExprRepeat, VarStillRepeating, + CountRepetitionMisplaced, MacroVarStillRepeating, MetaVarsDifSeqMatchers, MustRepeatOnce, + MveUnrecognizedVar, NoSyntaxVarsExprRepeat, }; use crate::mbe::macro_parser::NamedMatch; use crate::mbe::macro_parser::NamedMatch::*; @@ -483,7 +483,7 @@ fn transcribe_metavar<'tx>( } MatchedSeq(..) => { // We were unable to descend far enough. This is an error. - return Err(dcx.create_err(VarStillRepeating { span: sp, ident })); + return Err(dcx.create_err(MacroVarStillRepeating { span: sp, ident })); } }; @@ -940,11 +940,27 @@ fn extract_symbol_from_pnr<'a>( { Ok(*symbol) } + ParseNtResult::Literal(expr) + if let ExprKind::Lit(lit @ Lit { kind: LitKind::Integer, symbol, suffix }) = + &expr.kind => + { + if lit.is_semantic_float() { + Err(dcx + .struct_err("floats are not supported as metavariables of `${concat(..)}`") + .with_span(span_err)) + } else if suffix.is_none() { + Ok(*symbol) + } else { + Err(dcx + .struct_err("integer metavariables of `${concat(..)}` must not be suffixed") + .with_span(span_err)) + } + } _ => Err(dcx .struct_err( "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`", ) - .with_note("currently only string literals are supported") + .with_note("currently only string and integer literals are supported") .with_span(span_err)), } } diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 19f3cdbc549..79ab3cab22c 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -4,6 +4,7 @@ use std::path::{self, Path, PathBuf}; use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_attr_parsing::validate_attr; use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_parse::lexer::StripTokens; use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::Session; use rustc_session::parse::ParseSess; @@ -67,8 +68,12 @@ pub(crate) fn parse_external_mod( } // Actually parse the external file as a module. - let mut parser = - unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span))); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file( + &sess.psess, + &mp.file_path, + StripTokens::ShebangAndFrontmatter, + Some(span), + )); let (inner_attrs, items, inner_span) = parser.parse_mod(exp!(Eof)).map_err(|err| ModError::ParserError(err))?; attrs.extend(inner_attrs); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5b1d3d6d35b..295573f4492 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; -use rustc_parse::lexer::nfc_normalize; +use rustc_parse::lexer::{StripTokens, nfc_normalize}; use rustc_parse::parser::Parser; use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_proc_macro::bridge::{ @@ -485,8 +485,13 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = - unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned())); + + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( + self.psess(), + name, + s.to_owned(), + StripTokens::Nothing, + )); let first_span = parser.token.span.data(); let minus_present = parser.eat(exp!(Minus)); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e81003b1897..129ab7eccb5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)), + gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)), ungated!( unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4f35bf63a1a..93e5588146e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -632,6 +632,8 @@ declare_features! ( (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), + /// Allows using `#[rustc_align_static(...)]` on static items. + (unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)), /// Allows attributes on expressions and non-item statements. (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index dd5565d6f90..ea11a99efbc 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -14,6 +14,7 @@ pub use rustc_target::spec::SanitizerSet; use thin_vec::ThinVec; use crate::attrs::pretty_printing::PrintAttribute; +use crate::limit::Limit; use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] @@ -565,6 +566,9 @@ pub enum AttributeKind { /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). MayDangle(Span), + /// Represents `#[move_size_limit]` + MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[must_use]`. MustUse { span: Span, @@ -575,12 +579,18 @@ pub enum AttributeKind { /// Represents `#[naked]` Naked(Span), + /// Represents `#[no_core]` + NoCore(Span), + /// Represents `#[no_implicit_prelude]` NoImplicitPrelude(Span), /// Represents `#[no_mangle]` NoMangle(Span), + /// Represents `#[no_std]` + NoStd(Span), + /// Represents `#[non_exhaustive]` NonExhaustive(Span), @@ -596,6 +606,9 @@ pub enum AttributeKind { /// Represents `#[path]` Path(Symbol, Span), + /// Represents `#[pattern_complexity_limit]` + PatternComplexityLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[pointee]` Pointee(Span), @@ -611,6 +624,9 @@ pub enum AttributeKind { /// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint). PubTransparent(Span), + /// Represents [`#[recursion_limit]`](https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute) + RecursionLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span }, @@ -661,6 +677,9 @@ pub enum AttributeKind { /// Represents `#[type_const]`. TypeConst(Span), + /// Represents `#[type_length_limit]` + TypeLengthLimit { attr_span: Span, limit_span: Span, limit: Limit }, + /// Represents `#[rustc_unsafe_specialization_marker]`. UnsafeSpecializationMarker(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 3810bb6d003..55521c15854 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -61,20 +61,25 @@ impl AttributeKind { MacroUse { .. } => No, Marker(..) => No, MayDangle(..) => No, + MoveSizeLimit { .. } => No, MustUse { .. } => Yes, Naked(..) => No, + NoCore(..) => No, NoImplicitPrelude(..) => No, - NoMangle(..) => Yes, // Needed for rustdoc + NoMangle(..) => Yes, // Needed for rustdoc + NoStd(..) => No, NonExhaustive(..) => Yes, // Needed for rustdoc Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, Path(..) => No, + PatternComplexityLimit { .. } => No, Pointee(..) => No, ProcMacro(..) => No, ProcMacroAttribute(..) => No, ProcMacroDerive { .. } => No, PubTransparent(..) => Yes, + RecursionLimit { .. } => No, Repr { .. } => No, RustcBuiltinMacro { .. } => Yes, RustcLayoutScalarValidRangeEnd(..) => Yes, @@ -89,6 +94,7 @@ impl AttributeKind { TargetFeature { .. } => No, TrackCaller(..) => Yes, TypeConst(..) => Yes, + TypeLengthLimit { .. } => No, UnsafeSpecializationMarker(..) => No, UnstableFeatureBound(..) => No, Used { .. } => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index e65de25b451..d13cd3fd1da 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -9,6 +9,8 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; use rustc_target::spec::SanitizerSet; use thin_vec::ThinVec; +use crate::limit::Limit; + /// This trait is used to print attributes in `rustc_hir_pretty`. /// /// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. @@ -146,7 +148,7 @@ macro_rules! print_tup { print_tup!(A B C D E F G H); print_skip!(Span, (), ErrorGuaranteed); -print_disp!(u16, bool, NonZero<u32>); +print_disp!(u16, bool, NonZero<u32>, Limit); print_debug!( Symbol, Ident, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 8af4740f376..95abe5c40dd 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -440,6 +440,43 @@ impl DefKind { | DefKind::ExternCrate => false, } } + + /// Returns `true` if `self` is a kind of definition that does not have its own + /// type-checking context, i.e. closure, coroutine or inline const. + #[inline] + pub fn is_typeck_child(self) -> bool { + match self { + DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => true, + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Fn + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static { .. } + | DefKind::Ctor(_, _) + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Impl { .. } => false, + } + } } /// The resolution of a path or export. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ae03121e5f7..493236718a8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2616,6 +2616,18 @@ impl Expr<'_> { ) | ( ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val2], + StructTailExpr::None, + ), + ) + | ( + ExprKind::Struct( QPath::LangItem(LangItem::RangeFrom, _), [val1], StructTailExpr::None, @@ -2705,7 +2717,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { | LangItem::RangeToInclusive | LangItem::RangeCopy | LangItem::RangeFromCopy - | LangItem::RangeInclusiveCopy, + | LangItem::RangeInclusiveCopy + | LangItem::RangeToInclusiveCopy, .. ) ), @@ -3207,12 +3220,21 @@ pub struct ImplItem<'hir> { pub owner_id: OwnerId, pub generics: &'hir Generics<'hir>, pub kind: ImplItemKind<'hir>, - pub defaultness: Defaultness, + pub impl_kind: ImplItemImplKind, pub span: Span, - pub vis_span: Span, pub has_delayed_lints: bool, - /// When we are in a trait impl, link to the trait-item's id. - pub trait_item_def_id: Option<DefId>, +} + +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum ImplItemImplKind { + Inherent { + vis_span: Span, + }, + Trait { + defaultness: Defaultness, + /// Item in the trait that this item implements + trait_item_def_id: Result<DefId, ErrorGuaranteed>, + }, } impl<'hir> ImplItem<'hir> { @@ -3226,6 +3248,13 @@ impl<'hir> ImplItem<'hir> { ImplItemId { owner_id: self.owner_id } } + pub fn vis_span(&self) -> Option<Span> { + match self.impl_kind { + ImplItemImplKind::Trait { .. } => None, + ImplItemImplKind::Inherent { vis_span, .. } => Some(vis_span), + } + } + expect_methods_self_kind! { expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body); expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body); @@ -4972,7 +5001,7 @@ mod size_asserts { static_assert_size!(GenericBound<'_>, 64); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 40); - static_assert_size!(ImplItem<'_>, 96); + static_assert_size!(ImplItem<'_>, 88); static_assert_size!(ImplItemKind<'_>, 40); static_assert_size!(Item<'_>, 88); static_assert_size!(ItemKind<'_>, 64); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 25a7ae239f3..eb682f32111 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1257,18 +1257,21 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( owner_id: _, ident, ref generics, + ref impl_kind, ref kind, - ref defaultness, span: _, - vis_span: _, has_delayed_lints: _, - trait_item_def_id: _, } = *impl_item; try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_defaultness(defaultness)); try_visit!(visitor.visit_id(impl_item.hir_id())); + match impl_kind { + ImplItemImplKind::Inherent { vis_span: _ } => {} + ImplItemImplKind::Trait { defaultness, trait_item_def_id: _ } => { + try_visit!(visitor.visit_defaultness(defaultness)); + } + } match *kind { ImplItemKind::Const(ref ty, body) => { try_visit!(visitor.visit_ty_unambig(ty)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 0464665b41f..67d2f15d414 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -422,6 +422,7 @@ language_item_table! { RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None; RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None; RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None; + RangeToInclusiveCopy, sym::RangeToInclusiveCopy, range_to_inclusive_copy_struct, Target::Struct, GenericRequirement::None; String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 78fc63753a2..eb630fc8018 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -25,6 +25,7 @@ mod hir; pub use rustc_hir_id::{self as hir_id, *}; pub mod intravisit; pub mod lang_items; +pub mod limit; pub mod lints; pub mod pat_util; mod stability; diff --git a/compiler/rustc_hir/src/limit.rs b/compiler/rustc_hir/src/limit.rs new file mode 100644 index 00000000000..7e6d23f51bd --- /dev/null +++ b/compiler/rustc_hir/src/limit.rs @@ -0,0 +1,63 @@ +use std::fmt; +use std::ops::{Div, Mul}; + +use rustc_error_messages::{DiagArgValue, IntoDiagArg}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; + +/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against +/// limits are consistent throughout the compiler. +#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct Limit(pub usize); + +impl Limit { + /// Create a new limit from a `usize`. + pub fn new(value: usize) -> Self { + Limit(value) + } + + /// Create a new unlimited limit. + pub fn unlimited() -> Self { + Limit(usize::MAX) + } + + /// Check that `value` is within the limit. Ensures that the same comparisons are used + /// throughout the compiler, as mismatches can cause ICEs, see #72540. + #[inline] + pub fn value_within_limit(&self, value: usize) -> bool { + value <= self.0 + } +} + +impl From<usize> for Limit { + fn from(value: usize) -> Self { + Self::new(value) + } +} + +impl fmt::Display for Limit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +impl Div<usize> for Limit { + type Output = Limit; + + fn div(self, rhs: usize) -> Self::Output { + Limit::new(self.0 / rhs) + } +} + +impl Mul<usize> for Limit { + type Output = Limit; + + fn mul(self, rhs: usize) -> Self::Output { + Limit::new(self.0 * rhs) + } +} + +impl IntoDiagArg for Limit { + fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue { + self.to_string().into_diag_arg(&mut None) + } +} diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index e27e68d3662..e8237471e1b 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -1,7 +1,7 @@ +use rustc_hir::limit::Limit; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::PredicateObligations; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_session::Limit; use rustc_span::def_id::{LOCAL_CRATE, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::ObligationCtxt; diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 08b344638dd..886ebddc75c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1009,8 +1009,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), res = res.and(check_associated_item(tcx, def_id)); let assoc_item = tcx.associated_item(def_id); match assoc_item.container { - ty::AssocItemContainer::Impl => {} - ty::AssocItemContainer::Trait => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {} + ty::AssocContainer::Trait => { res = res.and(check_trait_item(tcx, def_id)); } } @@ -1026,8 +1026,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), res = res.and(check_associated_item(tcx, def_id)); let assoc_item = tcx.associated_item(def_id); match assoc_item.container { - ty::AssocItemContainer::Impl => {} - ty::AssocItemContainer::Trait => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {} + ty::AssocContainer::Trait => { res = res.and(check_trait_item(tcx, def_id)); } } @@ -1043,8 +1043,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), let assoc_item = tcx.associated_item(def_id); let has_type = match assoc_item.container { - ty::AssocItemContainer::Impl => true, - ty::AssocItemContainer::Trait => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, + ty::AssocContainer::Trait => { tcx.ensure_ok().explicit_item_bounds(def_id); tcx.ensure_ok().explicit_item_self_bounds(def_id); if tcx.is_conditionally_const(def_id) { @@ -1177,12 +1177,9 @@ fn check_impl_items_against_trait<'tcx>( for &impl_item in impl_item_refs { let ty_impl_item = tcx.associated_item(impl_item); - let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { - tcx.associated_item(trait_item_id) - } else { - // Checked in `associated_item`. - tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait"); - continue; + let ty_trait_item = match ty_impl_item.expect_trait_impl() { + Ok(trait_item_id) => tcx.associated_item(trait_item_id), + Err(ErrorGuaranteed { .. }) => continue, }; let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local()); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e4827256193..946c4936bb6 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -37,7 +37,7 @@ pub(super) fn compare_impl_item( impl_item_def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { let impl_item = tcx.associated_item(impl_item_def_id); - let trait_item = tcx.associated_item(impl_item.trait_item_def_id.unwrap()); + let trait_item = tcx.associated_item(impl_item.expect_trait_impl()?); let impl_trait_ref = tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap().instantiate_identity(); debug!(?impl_trait_ref); @@ -298,14 +298,9 @@ fn compare_method_predicate_entailment<'tcx>( // compatible with that of the trait method. We do this by // checking that `impl_fty <: trait_fty`. // - // FIXME. Unfortunately, this doesn't quite work right now because - // associated type normalization is not integrated into subtype - // checks. For the comparison to be valid, we need to - // normalize the associated types in the impl/trait methods - // first. However, because function types bind regions, just - // calling `FnCtxt::normalize` would have no effect on - // any associated types appearing in the fn arguments or return - // type. + // FIXME: We manually instantiate the trait method here as we need + // to manually compute its implied bounds. Otherwise this could just + // be `ocx.sub(impl_sig, trait_sig)`. let mut wf_tys = FxIndexSet::default(); @@ -446,7 +441,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( impl_m_def_id: LocalDefId, ) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> { let impl_m = tcx.associated_item(impl_m_def_id.to_def_id()); - let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap()); + let trait_m = tcx.associated_item(impl_m.expect_trait_impl()?); let impl_trait_ref = tcx.impl_trait_ref(tcx.parent(impl_m_def_id.to_def_id())).unwrap().instantiate_identity(); // First, check a few of the same things as `compare_impl_method`, @@ -1449,8 +1444,10 @@ fn compare_self_type<'tcx>( let self_string = |method: ty::AssocItem| { let untransformed_self_ty = match method.container { - ty::AssocItemContainer::Impl => impl_trait_ref.self_ty(), - ty::AssocItemContainer::Trait => tcx.types.self_param, + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { + impl_trait_ref.self_ty() + } + ty::AssocContainer::Trait => tcx.types.self_param, }; let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0); let (infcx, param_env) = tcx @@ -2458,8 +2455,12 @@ fn param_env_with_gat_bounds<'tcx>( for impl_ty in impl_tys_to_install { let trait_ty = match impl_ty.container { - ty::AssocItemContainer::Trait => impl_ty, - ty::AssocItemContainer::Impl => tcx.associated_item(impl_ty.trait_item_def_id.unwrap()), + ty::AssocContainer::InherentImpl => bug!(), + ty::AssocContainer::Trait => impl_ty, + ty::AssocContainer::TraitImpl(Err(_)) => continue, + ty::AssocContainer::TraitImpl(Ok(trait_item_def_id)) => { + tcx.associated_item(trait_item_def_id) + } }; let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b5c0ca4727c..63d0f400aef 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,9 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, +}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -233,8 +235,7 @@ fn missing_items_err( }; // Obtain the level of indentation ending in `sugg_sp`. - let padding = - tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = (Vec::new(), Vec::new(), Vec::new()); @@ -331,6 +332,7 @@ fn default_body_is_unstable( fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, + assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default(); let mut projections = vec![]; @@ -354,34 +356,50 @@ fn bounds_from_generic_predicates<'tcx>( } let mut where_clauses = vec![]; - let mut types_str = vec![]; - for (ty, bounds) in types { - if let ty::Param(_) = ty.kind() { - let mut bounds_str = vec![]; - for bound in bounds { - let mut projections_str = vec![]; - for projection in &projections { - let p = projection.skip_binder(); - if bound == tcx.parent(p.projection_term.def_id) - && p.projection_term.self_ty() == ty - { - let name = tcx.item_name(p.projection_term.def_id); - projections_str.push(format!("{} = {}", name, p.term)); + let generics = tcx.generics_of(assoc.def_id); + let types_str = generics + .own_params + .iter() + .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) + .map(|p| { + // we just checked that it's a type, so the unwrap can't fail + let ty = tcx.mk_param_from_def(p).as_type().unwrap(); + if let Some(bounds) = types.get(&ty) { + let mut bounds_str = vec![]; + for bound in bounds.iter().copied() { + let mut projections_str = vec![]; + for projection in &projections { + let p = projection.skip_binder(); + if bound == tcx.parent(p.projection_term.def_id) + && p.projection_term.self_ty() == ty + { + let name = tcx.item_name(p.projection_term.def_id); + projections_str.push(format!("{} = {}", name, p.term)); + } + } + let bound_def_path = tcx.def_path_str(bound); + if projections_str.is_empty() { + where_clauses.push(format!("{}: {}", ty, bound_def_path)); + } else { + bounds_str.push(format!( + "{}<{}>", + bound_def_path, + projections_str.join(", ") + )); } } - let bound_def_path = tcx.def_path_str(bound); - if projections_str.is_empty() { - where_clauses.push(format!("{}: {}", ty, bound_def_path)); + if bounds_str.is_empty() { + ty.to_string() } else { - bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", "))); + format!("{}: {}", ty, bounds_str.join(" + ")) } - } - if bounds_str.is_empty() { - types_str.push(ty.to_string()); } else { - types_str.push(format!("{}: {}", ty, bounds_str.join(" + "))); + ty.to_string() } - } else { + }) + .collect::<Vec<_>>(); + for (ty, bounds) in types.into_iter() { + if !matches!(ty.kind(), ty::Param(_)) { // Avoid suggesting the following: // fn foo<T, <T as Trait>::Bar>(_: T) where T: Trait, <T as Trait>::Bar: Other {} where_clauses.extend( @@ -473,10 +491,10 @@ fn fn_sig_suggestion<'tcx>( let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let safety = sig.safety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc); // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed + // not be present in the `fn` definition, nor will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. @@ -512,6 +530,7 @@ fn suggestion_signature<'tcx>( let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), + assoc, ); format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e6a1f6d8d8b..d33f1f3e12a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -944,12 +944,11 @@ pub(crate) fn check_associated_item( // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure_ok() - .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?; + tcx.ensure_ok().coherent_trait(tcx.parent(item.trait_item_or_self()?))?; let self_ty = match item.container { - ty::AssocItemContainer::Trait => tcx.types.self_param, - ty::AssocItemContainer::Impl => { + ty::AssocContainer::Trait => tcx.types.self_param, + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { tcx.type_of(item.container_id(tcx)).instantiate_identity() } }; @@ -978,7 +977,7 @@ pub(crate) fn check_associated_item( check_method_receiver(wfcx, hir_sig, item, self_ty) } ty::AssocKind::Type { .. } => { - if let ty::AssocItemContainer::Trait = item.container { + if let ty::AssocContainer::Trait = item.container { check_associated_type_bounds(wfcx, item, span) } if item.defaultness(tcx).has_value() { @@ -1047,7 +1046,7 @@ fn check_type_defn<'tcx>( let needs_drop_copy = || { packed && { let ty = tcx.type_of(variant.tail().did).instantiate_identity(); - let ty = tcx.erase_regions(ty); + let ty = tcx.erase_and_anonymize_regions(ty); assert!(!ty.has_infer()); ty.needs_drop(tcx, wfcx.infcx.typing_env(wfcx.param_env)) } diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index f707196c816..621431ae234 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -404,7 +404,7 @@ fn emit_orphan_check_error<'tcx>( of_trait.trait_ref.path.span }; - ty = tcx.erase_regions(ty); + ty = tcx.erase_and_anonymize_regions(ty); let is_foreign = !trait_ref.def_id.is_local() && matches!(is_target_ty, IsFirstInputType::No); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b59dc4bd132..dd3590f9ac5 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -111,9 +111,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } Some(ImplTraitInTraitData::Impl { fn_def_id }) => { - let assoc_item = tcx.associated_item(def_id); - let trait_assoc_predicates = - tcx.explicit_predicates_of(assoc_item.trait_item_def_id.unwrap()); + let trait_item_def_id = tcx.trait_item_of(def_id).unwrap(); + let trait_assoc_predicates = tcx.explicit_predicates_of(trait_item_def_id); let impl_assoc_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); let impl_def_id = tcx.parent(fn_def_id); @@ -174,12 +173,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } }; - if let Node::TraitItem(item) = node { - let mut bounds = Vec::new(); - icx.lowerer().add_default_trait_item_bounds(item, &mut bounds); - predicates.extend(bounds); - } - let generics = tcx.generics_of(def_id); // Below we'll consider the bounds on the type parameters (including `Self`) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 62125c99d80..8cbf17162e3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -125,8 +125,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ Some(ty::ImplTraitInTraitData::Impl { fn_def_id }) => { match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) { Ok(map) => { - let assoc_item = tcx.associated_item(def_id); - return map[&assoc_item.trait_item_def_id.unwrap()]; + let trait_item_def_id = tcx.trait_item_of(def_id).unwrap(); + return map[&trait_item_def_id]; } Err(_) => { return ty::EarlyBinder::bind(Ty::new_error_with_message( @@ -198,7 +198,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } } ImplItemKind::Type(ty) => { - if tcx.impl_trait_ref(tcx.hir_get_parent_item(hir_id)).is_none() { + if let ImplItemImplKind::Inherent { .. } = item.impl_kind { check_feature_inherent_assoc_ty(tcx, item.span); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 6565ad7cf53..3b6367219b7 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -6,6 +6,7 @@ use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, }; +use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{Ident, Span, Symbol}; @@ -557,7 +558,7 @@ pub(crate) struct AutoDerefReachedRecursionLimit<'a> { #[label] pub span: Span, pub ty: Ty<'a>, - pub suggested_limit: rustc_session::Limit, + pub suggested_limit: Limit, pub crate_name: Symbol, } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index d14aef8ace4..99dc8e6e522 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,12 +1,13 @@ +use std::assert_matches::assert_matches; use std::ops::ControlFlow; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{AmbigArg, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -230,122 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds - /// or associated items. - /// - /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds - /// should be added everywhere, including super bounds. However this causes a huge performance - /// costs. For optimization purposes instead of adding default supertraits, bounds - /// are added to the associated items: - /// - /// ```ignore(illustrative) - /// // Default bounds are generated in the following way: - /// trait Trait { - /// fn foo(&self) where Self: Leak {} - /// } - /// - /// // instead of this: - /// trait Trait: Leak { - /// fn foo(&self) {} - /// } - /// ``` - /// It is not always possible to do this because of backward compatibility: - /// - /// ```ignore(illustrative) - /// pub trait Trait<Rhs = Self> {} - /// pub trait Trait1 : Trait {} - /// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait` - /// ``` - /// - /// or: - /// - /// ```ignore(illustrative) - /// trait Trait { - /// type Type where Self: Sized; - /// } - /// trait Trait2<T> : Trait<Type = T> {} - /// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type` - /// ``` - /// - /// Therefore, `experimental_default_bounds` are still being added to supertraits if - /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. - fn requires_default_supertraits( - &self, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], - hir_generics: &'tcx hir::Generics<'tcx>, - ) -> bool { - struct TraitInfoCollector; - - impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector { - type Result = ControlFlow<()>; - - fn visit_assoc_item_constraint( - &mut self, - _constraint: &'tcx hir::AssocItemConstraint<'tcx>, - ) -> Self::Result { - ControlFlow::Break(()) - } - - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result { - if matches!( - &t.kind, - hir::TyKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. }, - )) - ) { - return ControlFlow::Break(()); - } - hir::intravisit::walk_ty(self, t) - } - } - - let mut found = false; - for bound in hir_bounds { - found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break(); - } - found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break(); - found - } - - /// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if - /// they are not added as super trait bounds to the trait itself. See - /// `requires_default_supertraits` for more information. - pub(crate) fn add_default_trait_item_bounds( - &self, - trait_item: &hir::TraitItem<'tcx>, - bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - ) { - let tcx = self.tcx(); - if !tcx.sess.opts.unstable_opts.experimental_default_bounds { - return; - } - - let parent = tcx.local_parent(trait_item.hir_id().owner.def_id); - let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { - unreachable!(); - }; - - let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), - _ => unreachable!(), - }; - - if !self.requires_default_supertraits(trait_bounds, trait_generics) { - let self_ty_where_predicates = (parent, trait_item.generics.predicates); - self.add_default_traits( - bounds, - tcx.types.self_param, - &[], - Some(self_ty_where_predicates), - trait_item.span, - ); - } - } - - /// Lazily sets `experimental_default_bounds` to true on trait super bounds. - /// See `requires_default_supertraits` for more information. + /// Adds `experimental_default_bounds` bounds to the supertrait bounds. pub(crate) fn add_default_super_traits( &self, trait_def_id: LocalDefId, @@ -354,21 +240,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_generics: &'tcx hir::Generics<'tcx>, span: Span, ) { - if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias); + + // Supertraits for auto trait are unsound according to the unstable book: + // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits + if self.tcx().trait_is_auto(trait_def_id.to_def_id()) { return; } - assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); - if self.requires_default_supertraits(hir_bounds, hir_generics) { - let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); - self.add_default_traits( - bounds, - self.tcx().types.self_param, - hir_bounds, - Some(self_ty_where_predicates), - span, - ); - } + self.add_default_traits( + bounds, + self.tcx().types.self_param, + hir_bounds, + Some((trait_def_id, hir_generics.predicates)), + span, + ); } pub(crate) fn add_default_traits( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 93b82acf621..0cf9cb7193f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -482,7 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|header| header.trait_ref.instantiate_identity().self_ty()) // We don't care about blanket impls. .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .map(|self_ty| tcx.erase_and_anonymize_regions(self_ty).to_string()) .collect() }; // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 2562ab7542a..6659aff7111 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -238,7 +238,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) { _ => (), } // Skip `AnonConst`s because we feed their `type_of`. - if !matches!(def_kind, DefKind::AnonConst) { + // Also skip items for which typeck forwards to parent typeck. + if !(matches!(def_kind, DefKind::AnonConst) || def_kind.is_typeck_child()) { tcx.ensure_ok().typeck(item_def_id); } // Ensure we generate the new `DefId` before finishing `check_crate`. diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 3eeb0eac023..27540fd1a43 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -851,8 +851,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}"); // ptr-ptr cast. metadata must match. - let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?); - let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?); + let src_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_src.ty, self.span)?); + let dst_kind = fcx.tcx.erase_and_anonymize_regions(fcx.pointer_kind(m_dst.ty, self.span)?); // We can't cast if target pointer kind is unknown let Some(dst_kind) = dst_kind else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0b3d50ff219..7370124e800 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1021,7 +1021,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let container_id = assoc_item.container_id(tcx); debug!(?def_id, ?container, ?container_id); match container { - ty::AssocItemContainer::Trait => { + ty::AssocContainer::Trait => { if let Err(e) = callee::check_legal_trait_for_method_call( tcx, path_span, @@ -1033,7 +1033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(e); } } - ty::AssocItemContainer::Impl => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { if segments.len() == 1 { // `<T>::assoc` will end up here, and so // can `T::assoc`. If this came from an diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 94b635c41b4..44a6084ebd5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2354,7 +2354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We want it to always point to the trait item. // If we're pointing at an inherent function, we don't need to do anything, // so we fetch the parent and verify if it's a trait item. - && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) + && let Ok(maybe_trait_item_def_id) = assoc_item.trait_item_or_self() && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 74f27e85cba..7a060cafeab 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -21,7 +21,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; use rustc_trait_selection::error_reporting::TypeErrCtxt; -use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; use rustc_trait_selection::traits::{ self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, }; @@ -188,14 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { - let mut sub_relations = SubRelations::default(); - sub_relations.add_constraints( - self, - self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate), - ); TypeErrCtxt { infcx: &self.infcx, - sub_relations: RefCell::new(sub_relations), typeck_results: Some(self.typeck_results.borrow()), fallback_has_occurred: self.fallback_has_occurred.get(), normalize_fn_sig: Box::new(|fn_sig| { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 84ea2ec0f8a..1998a1884b7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1358,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .infcx .type_implements_trait( clone_trait_def, - [self.tcx.erase_regions(expected_ty)], + [self.tcx.erase_and_anonymize_regions(expected_ty)], self.param_env, ) .must_apply_modulo_regions() @@ -1882,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if segment.ident.name == sym::clone && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| { let assoc_item = self.tcx.associated_item(did); - assoc_item.container == ty::AssocItemContainer::Trait + assoc_item.container == ty::AssocContainer::Trait && assoc_item.container_id(self.tcx) == clone_trait_did }) // If that clone call hasn't already dereferenced the self type (i.e. don't give this diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index b59c1752c25..c0cd23be690 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if ty.has_non_region_infer() { Ty::new_misc_error(self.tcx()) } else { - self.tcx().erase_regions(ty) + self.tcx().erase_and_anonymize_regions(ty) } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 129de32fd4a..7f5397a7926 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -278,8 +278,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti { if let Some(item) = tcx.opt_associated_item(def_id.into()) && let ty::AssocKind::Const { .. } = item.kind - && let ty::AssocItemContainer::Impl = item.container - && let Some(trait_item_def_id) = item.trait_item_def_id + && let ty::AssocContainer::TraitImpl(Ok(trait_item_def_id)) = item.container { let impl_def_id = item.container_id(tcx); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index ab584eb7c90..4185f7f6996 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -18,8 +18,8 @@ use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; use rustc_middle::ty::{ - self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, - ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt, Upcast, + self, AssocContainer, AssocItem, GenericArgs, GenericArgsRef, GenericParamDefKind, ParamEnvAnd, + Ty, TyCtxt, TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -403,15 +403,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // special handling for this "trivial case" is a good idea. let infcx = &self.infcx; - let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) = + let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) = infcx.instantiate_canonical(span, &query_input.canonical); debug!(?self_ty, ?query_input, "probe_op: Mode::Path"); MethodAutoderefStepsResult { steps: infcx.tcx.arena.alloc_from_iter([CandidateStep { - self_ty: self.make_query_response_ignoring_pending_obligations( - canonical_inference_vars, - self_ty, - ), + self_ty: self + .make_query_response_ignoring_pending_obligations(var_values, self_ty), autoderefs: 0, from_unsafe_deref: false, unsize: false, @@ -530,7 +528,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ProbeScope::Single(def_id) => { let item = self.tcx.associated_item(def_id); // FIXME(fn_delegation): Delegation to inherent methods is not yet supported. - assert_eq!(item.container, AssocItemContainer::Trait); + assert_eq!(item.container, AssocContainer::Trait); let trait_def_id = self.tcx.parent(def_id); let trait_span = self.tcx.def_span(trait_def_id); @@ -1661,7 +1659,7 @@ impl<'tcx> Pick<'tcx> { /// Do not use for type checking. pub(crate) fn differs_from(&self, other: &Self) -> bool { let Self { - item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ }, + item: AssocItem { def_id, kind: _, container: _ }, kind: _, import_ids: _, autoderefs: _, @@ -1704,7 +1702,7 @@ impl<'tcx> Pick<'tcx> { tcx.def_path_str(self.item.def_id), )); } - (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => { + (ty::AssocKind::Const { name }, ty::AssocContainer::Trait) => { let def_id = self.item.container_id(tcx); lint.span_suggestion( span, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index d75bc9edab2..90301d1b391 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -802,7 +802,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { format!("unexpected inference variable after writeback: {predicate:?}"), ); } else { - let predicate = self.tcx().erase_regions(predicate); + let predicate = self.tcx().erase_and_anonymize_regions(predicate); if cause.has_infer() || cause.has_placeholders() { // We can't use the the obligation cause as it references // information local to this query. @@ -984,8 +984,8 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { // borrowck, and specifically region constraints will be populated during // MIR typeck which is run on the new body. // - // We're not using `tcx.erase_regions` as that also anonymizes bound variables, - // regressing borrowck diagnostics. + // We're not using `tcx.erase_and_anonymize_regions` as that also + // anonymizes bound variables, regressing borrowck diagnostics. value = fold_regions(tcx, value, |_, _| tcx.lifetimes.re_erased); // Normalize consts in writeback, because GCE doesn't normalize eagerly. diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 33f406e2113..9cd7134659c 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -130,7 +130,22 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> { impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> { type Output = core::range::RangeInclusive<usize>; #[inline] + #[cfg(bootstrap)] fn into_slice_idx(self) -> Self::Output { core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } } + #[inline] + #[cfg(not(bootstrap))] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeInclusive { start: self.start.index(), last: self.last.index() } + } +} + +#[cfg(all(feature = "nightly", not(bootstrap)))] +impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> { + type Output = core::range::RangeToInclusive<usize>; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeToInclusive { last: self.last.index() } + } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 3ad14dc79d5..3c5e4a91c98 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -6,6 +6,7 @@ //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sso::SsoHashMap; use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::ty::{ @@ -17,7 +18,7 @@ use tracing::debug; use crate::infer::InferCtxt; use crate::infer::canonical::{ - Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues, + Canonical, CanonicalQueryInput, CanonicalVarKind, OriginalQueryValues, }; impl<'tcx> InferCtxt<'tcx> { @@ -293,6 +294,13 @@ struct Canonicalizer<'cx, 'tcx> { // Note that indices is only used once `var_values` is big enough to be // heap-allocated. indices: FxHashMap<GenericArg<'tcx>, BoundVar>, + /// Maps each `sub_unification_table_root_var` to the index of the first + /// variable which used it. + /// + /// This means in case two type variables have the same sub relations root, + /// we set the `sub_root` of the second variable to the position of the first. + /// Otherwise the `sub_root` of each type variable is just its own position. + sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>, canonicalize_mode: &'cx dyn CanonicalizeMode, needs_canonical_flags: TypeFlags, @@ -361,10 +369,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { // FIXME: perf problem described in #55921. ui = ty::UniverseIndex::ROOT; } - self.canonicalize_ty_var( - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), - t, - ) + let sub_root = self.get_or_insert_sub_root(vid); + self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t) } } } @@ -374,7 +380,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { if nt != t { return self.fold_ty(nt); } else { - self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t) + self.canonicalize_ty_var(CanonicalVarKind::Int, t) } } ty::Infer(ty::FloatVar(vid)) => { @@ -382,7 +388,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { if nt != t { return self.fold_ty(nt); } else { - self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t) + self.canonicalize_ty_var(CanonicalVarKind::Float, t) } } @@ -562,6 +568,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { variables: SmallVec::from_slice(base.variables), query_state, indices: FxHashMap::default(), + sub_root_lookup_table: Default::default(), binder_index: ty::INNERMOST, }; if canonicalizer.query_state.var_values.spilled() { @@ -660,6 +667,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { } } + fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar { + let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid); + let idx = + *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len()); + ty::BoundVar::from(idx) + } + /// Replaces the universe indexes used in `var_values` with their index in /// `query_state.universe_map`. This minimizes the maximum universe used in /// the canonicalized value. @@ -679,11 +693,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { self.variables .iter() .map(|&kind| match kind { - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { + CanonicalVarKind::Int | CanonicalVarKind::Float => { return kind; } - CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u])) + CanonicalVarKind::Ty { ui, sub_root } => { + CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root } } CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]), CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 79a2aa54ef8..f99f228e19d 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,7 +24,7 @@ pub use instantiate::CanonicalExt; use rustc_index::IndexVec; pub use rustc_middle::infer::canonical::*; -use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use crate::infer::{InferCtxt, RegionVariableOrigin}; @@ -67,30 +67,12 @@ impl<'tcx> InferCtxt<'tcx> { .chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe())) .collect(); - let canonical_inference_vars = - self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]); - let result = canonical.instantiate(self.tcx, &canonical_inference_vars); - (result, canonical_inference_vars) - } - - /// Given the "infos" about the canonical variables from some - /// canonical, creates fresh variables with the same - /// characteristics (see `instantiate_canonical_var` for - /// details). You can then use `instantiate` to instantiate the - /// canonical variable with these inference variables. - fn instantiate_canonical_vars( - &self, - span: Span, - variables: &List<CanonicalVarKind<'tcx>>, - universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, - ) -> CanonicalVarValues<'tcx> { - CanonicalVarValues { - var_values: self.tcx.mk_args_from_iter( - variables - .iter() - .map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)), - ), - } + let var_values = + CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| { + self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui]) + }); + let result = canonical.instantiate(self.tcx, &var_values); + (result, var_values) } /// Given the "info" about a canonical variable, creates a fresh @@ -105,21 +87,27 @@ impl<'tcx> InferCtxt<'tcx> { &self, span: Span, kind: CanonicalVarKind<'tcx>, + previous_var_values: &[GenericArg<'tcx>], universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> GenericArg<'tcx> { match kind { - CanonicalVarKind::Ty(ty_kind) => { - let ty = match ty_kind { - CanonicalTyVarKind::General(ui) => { - self.next_ty_var_in_universe(span, universe_map(ui)) + CanonicalVarKind::Ty { ui, sub_root } => { + let vid = self.next_ty_vid_in_universe(span, universe_map(ui)); + // If this inference variable is related to an earlier variable + // via subtyping, we need to add that info to the inference context. + if let Some(prev) = previous_var_values.get(sub_root.as_usize()) { + if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() { + self.sub_unify_ty_vids_raw(vid, sub_root); + } else { + unreachable!() } + } + Ty::new_var(self.tcx, vid).into() + } - CanonicalTyVarKind::Int => self.next_int_var(), + CanonicalVarKind::Int => self.next_int_var().into(), - CanonicalTyVarKind::Float => self.next_float_var(), - }; - ty.into() - } + CanonicalVarKind::Float => self.next_float_var().into(), CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => { let universe_mapped = universe_map(universe); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 09578598114..5d1b4be9e57 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -13,6 +13,7 @@ use std::iter; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::bug; +use rustc_middle::infer::canonical::CanonicalVarKind; use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use tracing::{debug, instrument}; @@ -413,26 +414,27 @@ impl<'tcx> InferCtxt<'tcx> { let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> = IndexVec::from_elem_n(None, query_response.variables.len()); - // In terms of our example above, we are iterating over pairs like: - // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)] for (original_value, result_value) in iter::zip(&original_values.var_values, result_values) { match result_value.kind() { GenericArgKind::Type(result_value) => { - // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(debruijn, b) = *result_value.kind() { - // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. - + // We disable the instantiation guess for inference variables + // and only use it for placeholders. We need to handle the + // `sub_root` of type inference variables which would make this + // more involved. They are also a lot rarer than region variables. + if let ty::Bound(debruijn, b) = *result_value.kind() + && !matches!( + query_response.variables[b.var.as_usize()], + CanonicalVarKind::Ty { .. } + ) + { // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); } } GenericArgKind::Lifetime(result_value) => { - // e.g., here `result_value` might be `'?1` in the example above... if let ty::ReBound(debruijn, b) = result_value.kind() { - // ... in which case we would set `canonical_vars[0]` to `Some('static)`. - // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); @@ -440,8 +442,6 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Const(result_value) => { if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { - // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. - // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); @@ -453,39 +453,36 @@ impl<'tcx> InferCtxt<'tcx> { // Create result arguments: if we found a value for a // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. - let result_args = CanonicalVarValues { - var_values: self.tcx.mk_args_from_iter( - query_response.variables.iter().enumerate().map(|(index, var_kind)| { - if var_kind.universe() != ty::UniverseIndex::ROOT { - // A variable from inside a binder of the query. While ideally these shouldn't - // exist at all, we have to deal with them for now. - self.instantiate_canonical_var(cause.span, var_kind, |u| { - universe_map[u.as_usize()] - }) - } else if var_kind.is_existential() { - match opt_values[BoundVar::new(index)] { - Some(k) => k, - None => self.instantiate_canonical_var(cause.span, var_kind, |u| { - universe_map[u.as_usize()] - }), - } - } else { - // For placeholders which were already part of the input, we simply map this - // universal bound variable back the placeholder of the input. - opt_values[BoundVar::new(index)].expect( - "expected placeholder to be unified with itself during response", - ) - } - }), - ), - }; + let tcx = self.tcx; + let variables = query_response.variables; + let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| { + if kind.universe() != ty::UniverseIndex::ROOT { + // A variable from inside a binder of the query. While ideally these shouldn't + // exist at all, we have to deal with them for now. + self.instantiate_canonical_var(cause.span, kind, &var_values, |u| { + universe_map[u.as_usize()] + }) + } else if kind.is_existential() { + match opt_values[BoundVar::new(var_values.len())] { + Some(k) => k, + None => self.instantiate_canonical_var(cause.span, kind, &var_values, |u| { + universe_map[u.as_usize()] + }), + } + } else { + // For placeholders which were already part of the input, we simply map this + // universal bound variable back the placeholder of the input. + opt_values[BoundVar::new(var_values.len())] + .expect("expected placeholder to be unified with itself during response") + } + }); let mut obligations = PredicateObligations::new(); // Carry all newly resolved opaque types to the caller's scope for &(a, b) in &query_response.value.opaque_types { - let a = instantiate_value(self.tcx, &result_args, a); - let b = instantiate_value(self.tcx, &result_args, b); + let a = instantiate_value(self.tcx, &var_values, a); + let b = instantiate_value(self.tcx, &var_values, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the // opaque type's hidden value directly, because the hidden type may have been an inference @@ -502,7 +499,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } - Ok(InferOk { value: result_args, obligations }) + Ok(InferOk { value: var_values, obligations }) } /// Given a "guess" at the values for the canonical variables in diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 8265fccabc9..14cc590720a 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -59,6 +59,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.root_var(var) } + fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid { + self.sub_unification_table_root_var(var) + } + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { self.root_const_var(var) } @@ -179,6 +183,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().equate(a, b); } + fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { + self.sub_unify_ty_vids_raw(a, b); + } + fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) { self.inner.borrow_mut().int_unification_table().union(a, b); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d105d24bed7..9d3886aff1c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -764,6 +764,7 @@ impl<'tcx> InferCtxt<'tcx> { let r_b = self.shallow_resolve(predicate.skip_binder().b); match (r_a.kind(), r_b.kind()) { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { + self.sub_unify_ty_vids_raw(a_vid, b_vid); return Err((a_vid, b_vid)); } _ => {} @@ -1128,6 +1129,14 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().root_var(var) } + pub fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { + self.inner.borrow_mut().type_variables().sub_unify(a, b); + } + + pub fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid { + self.inner.borrow_mut().type_variables().sub_unification_table_root_var(var) + } + pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { self.inner.borrow_mut().const_unification_table().find(var).vid } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index bfdd282d7e1..f06eb58a371 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -76,7 +76,7 @@ pub(super) fn can_match_erased_ty<'tcx>( erased_ty: Ty<'tcx>, ) -> bool { assert!(!outlives_predicate.has_escaping_bound_vars()); - let erased_outlives_predicate = tcx.erase_regions(outlives_predicate); + let erased_outlives_predicate = tcx.erase_and_anonymize_regions(outlives_predicate); let outlives_ty = erased_outlives_predicate.skip_binder().0; if outlives_ty == erased_ty { // pointless micro-optimization diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 69feecfe30a..f67b99cb3f8 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -96,7 +96,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { &self, alias_ty: ty::AliasTy<'tcx>, ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> { - let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx)); + let erased_alias_ty = self.tcx.erase_and_anonymize_regions(alias_ty.to_ty(self.tcx)); self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty) } @@ -241,7 +241,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } let p_ty = p.to_ty(tcx); - let erased_p_ty = self.tcx.erase_regions(p_ty); + let erased_p_ty = self.tcx.erase_and_anonymize_regions(p_ty); (erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r))) })); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index a000bb1123c..cc41957c110 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -6,8 +6,8 @@ use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ - self, AliasRelationDirection, InferConst, MaxUniverse, Term, Ty, TyCtxt, TypeVisitable, - TypeVisitableExt, TypingMode, + self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, TypingMode, }; use rustc_span::Span; use tracing::{debug, instrument, warn}; @@ -290,6 +290,45 @@ impl<'tcx> InferCtxt<'tcx> { } } +/// Finds the max universe present +struct MaxUniverse { + max_universe: ty::UniverseIndex, +} + +impl MaxUniverse { + fn new() -> Self { + MaxUniverse { max_universe: ty::UniverseIndex::ROOT } + } + + fn max_universe(self) -> ty::UniverseIndex { + self.max_universe + } +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse { + fn visit_ty(&mut self, t: Ty<'tcx>) { + if let ty::Placeholder(placeholder) = t.kind() { + self.max_universe = self.max_universe.max(placeholder.universe); + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: ty::Const<'tcx>) { + if let ty::ConstKind::Placeholder(placeholder) = c.kind() { + self.max_universe = self.max_universe.max(placeholder.universe); + } + + c.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) { + if let ty::RePlaceholder(placeholder) = r.kind() { + self.max_universe = self.max_universe.max(placeholder.universe); + } + } +} + /// The "generalizer" is used when handling inference variables. /// /// The basic strategy for handling a constraint like `?A <: B` is to @@ -519,6 +558,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { let origin = inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); + // Record that `vid` and `new_var_id` have to be subtypes + // of each other. This is currently only used for diagnostics. + // To see why, see the docs in the `type_variables` module. + inner.type_variables().sub_unify(vid, new_var_id); // If we're in the new solver and create a new inference // variable inside of an alias we eagerly constrain that // inference variable to prevent unexpected ambiguity errors. diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index fcc0ab3af41..22c815fb87c 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> { pub(crate) enum UndoLog<'tcx> { DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>), - TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>), + TypeVariables(type_variable::UndoLog<'tcx>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), @@ -49,6 +49,8 @@ impl_from! { RegionConstraintCollector(region_constraints::UndoLog<'tcx>), TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>), + TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidSubKey>>), + TypeVariables(type_variable::UndoLog<'tcx>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 6f6791804d3..65f77fe8e25 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -13,12 +13,48 @@ use tracing::debug; use crate::infer::InferCtxtUndoLogs; +/// Represents a single undo-able action that affects a type inference variable. +#[derive(Clone)] +pub(crate) enum UndoLog<'tcx> { + EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>), + SubRelation(sv::UndoLog<ut::Delegate<TyVidSubKey>>), +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self { + UndoLog::EqRelation(l) + } +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog<ut::Delegate<TyVidSubKey>>) -> Self { + UndoLog::SubRelation(l) + } +} + impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> { fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) { self.eq_relations.reverse(undo) } } +impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidSubKey>>) { + self.sub_unification_table.reverse(undo) + } +} + +impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), + UndoLog::SubRelation(undo) => self.sub_unification_table.reverse(undo), + } + } +} + #[derive(Clone, Default)] pub(crate) struct TypeVariableStorage<'tcx> { /// The origins of each type variable. @@ -27,6 +63,25 @@ pub(crate) struct TypeVariableStorage<'tcx> { /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>, + /// Only used by `-Znext-solver` and for diagnostics. Tracks whether + /// type variables are related via subtyping at all, ignoring which of + /// the two is the subtype. + /// + /// When reporting ambiguity errors, we sometimes want to + /// treat all inference vars which are subtypes of each + /// others as if they are equal. For this case we compute + /// the transitive closure of our subtype obligations here. + /// + /// E.g. when encountering ambiguity errors, we want to suggest + /// specifying some method argument or to add a type annotation + /// to a local variable. Because subtyping cannot change the + /// shape of a type, it's fine if the cause of the ambiguity error + /// is only related to the suggested variable via subtyping. + /// + /// Even for something like `let x = returns_arg(); x.method();` the + /// type of `x` is only a supertype of the argument of `returns_arg`. We + /// still want to suggest specifying the type of the argument. + sub_unification_table: ut::UnificationTableStorage<TyVidSubKey>, } pub(crate) struct TypeVariableTable<'a, 'tcx> { @@ -102,13 +157,24 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.storage.values[vid].origin } - /// Records that `a == b`, depending on `dir`. + /// Records that `a == b`. /// /// Precondition: neither `a` nor `b` are known. pub(crate) fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); self.eq_relations().union(a, b); + self.sub_unification_table().union(a, b); + } + + /// Records that `a` and `b` are related via subtyping. We don't track + /// which of the two is the subtype. + /// + /// Precondition: neither `a` nor `b` are known. + pub(crate) fn sub_unify(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_unknown()); + debug_assert!(self.probe(b).is_unknown()); + self.sub_unification_table().union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -142,6 +208,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); + + let sub_key = self.sub_unification_table().new_key(()); + debug_assert_eq!(eq_key.vid, sub_key.vid); + let index = self.storage.values.push(TypeVariableData { origin }); debug_assert_eq!(eq_key.vid, index); @@ -164,6 +234,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.eq_relations().find(vid).vid } + /// Returns the "root" variable of `vid` in the `sub_unification_table` + /// equivalence table. All type variables that have been are related via + /// equality or subtyping will yield the same root variable (per the + /// union-find algorithm), so `sub_unification_table_root_var(a) + /// == sub_unification_table_root_var(b)` implies that: + /// ```text + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + /// ``` + pub(crate) fn sub_unification_table_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.sub_unification_table().find(vid).vid + } + /// Retrieves the type to which `vid` has been instantiated, if /// any. pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { @@ -181,6 +263,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { self.storage.eq_relations.with_log(self.undo_log) } + #[inline] + fn sub_unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidSubKey> { + self.storage.sub_unification_table.with_log(self.undo_log) + } + /// Returns a range of the type variables created during the snapshot. pub(crate) fn vars_since_snapshot( &mut self, @@ -243,6 +330,33 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) struct TyVidSubKey { + vid: ty::TyVid, +} + +impl From<ty::TyVid> for TyVidSubKey { + #[inline] // make this function eligible for inlining - it is quite hot. + fn from(vid: ty::TyVid) -> Self { + TyVidSubKey { vid } + } +} + +impl ut::UnifyKey for TyVidSubKey { + type Value = (); + #[inline] + fn index(&self) -> u32 { + self.vid.as_u32() + } + #[inline] + fn from_index(i: u32) -> TyVidSubKey { + TyVidSubKey { vid: ty::TyVid::from_u32(i) } + } + fn tag() -> &'static str { + "TyVidSubKey" + } +} + impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { type Error = ut::NoError; diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl index 4b9c71d7172..6f6666f8c76 100644 --- a/compiler/rustc_interface/messages.ftl +++ b/compiler/rustc_interface/messages.ftl @@ -30,9 +30,8 @@ interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag interface_input_file_would_be_overwritten = the input file "{$path}" would be overwritten by the generated executable -interface_limit_invalid = - `limit` must be a non-negative integer - .label = {$error_str} +interface_invalid_crate_type_value = invalid `crate_type` value + .suggestion = did you mean interface_mixed_bin_crate = cannot mix `bin` crate type with others diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 6b39b4f1891..727e09c7562 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -1,7 +1,7 @@ use std::io; use std::path::Path; -use rustc_macros::Diagnostic; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] @@ -109,12 +109,17 @@ pub(crate) struct AbiRequiredTargetFeature<'a> { pub enabled: &'a str, } -#[derive(Diagnostic)] -#[diag(interface_limit_invalid)] -pub(crate) struct LimitInvalid<'a> { +#[derive(LintDiagnostic)] +#[diag(interface_invalid_crate_type_value)] +pub(crate) struct UnknownCrateTypes { + #[subdiagnostic] + pub sugg: Option<UnknownCrateTypesSub>, +} + +#[derive(Subdiagnostic)] +#[suggestion(interface_suggestion, code = r#""{snippet}""#, applicability = "maybe-incorrect")] +pub(crate) struct UnknownCrateTypesSub { #[primary_span] pub span: Span, - #[label] - pub value_span: Span, - pub error_str: &'a str, + pub snippet: Symbol, } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 4c820b8877b..b52c5b4cd66 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -13,7 +13,8 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::new_parser_from_simple_source_str; +use rustc_parse::lexer::StripTokens; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; @@ -68,7 +69,8 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg { }; } - match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { + match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing) + { Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,13 +168,15 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { - Ok(parser) => parser, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - expected_error(); - } - }; + let mut parser = + match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing) + { + Ok(parser) => parser, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + expected_error(); + } + }; let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => meta_item, diff --git a/compiler/rustc_interface/src/limits.rs b/compiler/rustc_interface/src/limits.rs index 8f01edec09f..10e58f32256 100644 --- a/compiler/rustc_interface/src/limits.rs +++ b/compiler/rustc_interface/src/limits.rs @@ -8,78 +8,32 @@ //! Users can override these limits via an attribute on the crate like //! `#![recursion_limit="22"]`. This pass just looks for those attributes. -use std::num::IntErrorKind; - -use rustc_ast::attr::AttributeExt; -use rustc_middle::bug; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::limit::Limit; +use rustc_hir::{Attribute, find_attr}; use rustc_middle::query::Providers; -use rustc_session::{Limit, Limits, Session}; -use rustc_span::{Symbol, sym}; - -use crate::errors::LimitInvalid; +use rustc_session::Limits; pub(crate) fn provide(providers: &mut Providers) { - providers.limits = |tcx, ()| Limits { - recursion_limit: get_recursion_limit(tcx.hir_krate_attrs(), tcx.sess), - move_size_limit: get_limit( - tcx.hir_krate_attrs(), - tcx.sess, - sym::move_size_limit, - Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0)), - ), - type_length_limit: get_limit( - tcx.hir_krate_attrs(), - tcx.sess, - sym::type_length_limit, - Limit::new(2usize.pow(24)), - ), - pattern_complexity_limit: get_limit( - tcx.hir_krate_attrs(), - tcx.sess, - sym::pattern_complexity_limit, - Limit::unlimited(), - ), + providers.limits = |tcx, ()| { + let attrs = tcx.hir_krate_attrs(); + Limits { + recursion_limit: get_recursion_limit(tcx.hir_krate_attrs()), + move_size_limit: + find_attr!(attrs, AttributeKind::MoveSizeLimit { limit, .. } => *limit) + .unwrap_or(Limit::new(tcx.sess.opts.unstable_opts.move_size_limit.unwrap_or(0))), + type_length_limit: + find_attr!(attrs, AttributeKind::TypeLengthLimit { limit, .. } => *limit) + .unwrap_or(Limit::new(2usize.pow(24))), + pattern_complexity_limit: + find_attr!(attrs, AttributeKind::PatternComplexityLimit { limit, .. } => *limit) + .unwrap_or(Limit::unlimited()), + } } } // This one is separate because it must be read prior to macro expansion. -pub(crate) fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit { - get_limit(krate_attrs, sess, sym::recursion_limit, Limit::new(128)) -} - -fn get_limit( - krate_attrs: &[impl AttributeExt], - sess: &Session, - name: Symbol, - default: Limit, -) -> Limit { - for attr in krate_attrs { - if !attr.has_name(name) { - continue; - } - - if let Some(sym) = attr.value_str() { - match sym.as_str().parse() { - Ok(n) => return Limit::new(n), - Err(e) => { - let error_str = match e.kind() { - IntErrorKind::PosOverflow => "`limit` is too large", - IntErrorKind::Empty => "`limit` must be a non-negative integer", - IntErrorKind::InvalidDigit => "not a valid integer", - IntErrorKind::NegOverflow => { - bug!("`limit` should never negatively overflow") - } - IntErrorKind::Zero => bug!("zero is a valid `limit`"), - kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), - }; - sess.dcx().emit_err(LimitInvalid { - span: attr.span(), - value_span: attr.value_span().unwrap(), - error_str, - }); - } - } - } - } - default +pub(crate) fn get_recursion_limit(attrs: &[Attribute]) -> Limit { + find_attr!(attrs, AttributeKind::RecursionLimit { limit, .. } => *limit) + .unwrap_or(Limit::new(128)) } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ca8c10311fb..d39219bfd66 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; use rustc_ast as ast; -use rustc_attr_parsing::{AttributeParser, ShouldEmit, validate_attr}; +use rustc_attr_parsing::{AttributeParser, ShouldEmit}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; @@ -19,6 +19,7 @@ use rustc_fs_util::try_canonicalize; use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; +use rustc_hir::limit::Limit; use rustc_incremental::setup_dep_graph; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; use rustc_metadata::EncodedMetadata; @@ -27,15 +28,16 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepsType; use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; +use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; +use rustc_session::Session; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input}; use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; -use rustc_session::{Limit, Session}; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, @@ -51,10 +53,18 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate { let mut krate = sess .time("parse_crate", || { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { - Input::File(file) => new_parser_from_file(&sess.psess, file, None), - Input::Str { input, name } => { - new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) - } + Input::File(file) => new_parser_from_file( + &sess.psess, + file, + StripTokens::ShebangAndFrontmatter, + None, + ), + Input::Str { input, name } => new_parser_from_source_str( + &sess.psess, + name.clone(), + input.clone(), + StripTokens::ShebangAndFrontmatter, + ), }); parser.parse_crate_mod() }) @@ -1246,7 +1256,8 @@ pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol // in all code paths that require the crate name very early on, namely before // macro expansion. - let attr_crate_name = parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal); + let attr_crate_name = + parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal { also_emit_lints: true }); let validate = |name, span| { rustc_session::output::validate_crate_name(sess, name, span); @@ -1307,36 +1318,18 @@ pub(crate) fn parse_crate_name( } fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { - // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`]) - // because that would require expanding this while in the middle of expansion, which needs to - // know the limit before expanding. - let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs); - crate::limits::get_recursion_limit(krate_attrs, sess) -} - -/// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find. -/// -/// This validator is intended for built-in attributes whose value needs to be known very early -/// during compilation (namely, before macro expansion) and it mainly exists to reject macro calls -/// inside of the attributes, such as in `#![name = expand!()]`. Normal attribute validation happens -/// during semantic analysis via [`TyCtxt::check_mod_attrs`] which happens *after* macro expansion -/// when such macro calls (here: `expand`) have already been expanded and we can no longer check for -/// their presence. -/// -/// [value-str]: ast::Attribute::value_str -fn validate_and_find_value_str_builtin_attr( - name: Symbol, - sess: &Session, - krate_attrs: &[ast::Attribute], -) -> Option<(Symbol, Span)> { - let mut result = None; - // Validate *all* relevant attributes, not just the first occurrence. - for attr in ast::attr::filter_by_name(krate_attrs, name) { - let Some(value) = attr.value_str() else { - validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, attr, name) - }; - // Choose the first occurrence as our result. - result.get_or_insert((value, attr.span)); - } - result + let attr = AttributeParser::parse_limited_should_emit( + sess, + &krate_attrs, + sym::recursion_limit, + DUMMY_SP, + rustc_ast::node_id::CRATE_NODE_ID, + None, + // errors are fatal here, but lints aren't. + // If things aren't fatal we continue, and will parse this again. + // That makes the same lint trigger again. + // So, no lints here to avoid duplicates. + ShouldEmit::EarlyFatal { also_emit_lints: false }, + ); + crate::limits::get_recursion_limit(attr.as_slice()) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 04006f3e446..061c764e619 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -13,9 +13,8 @@ use rustc_errors::LintBuffer; use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple}; -use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; -use rustc_session::{EarlyDiagCtxt, Session, filesearch}; +use rustc_session::{EarlyDiagCtxt, Session, filesearch, lint}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMapInputs; @@ -468,7 +467,10 @@ pub(crate) fn check_attr_crate_type( lint::builtin::UNKNOWN_CRATE_TYPES, ast::CRATE_NODE_ID, span, - BuiltinLintDiag::UnknownCrateTypes { span, candidate }, + errors::UnknownCrateTypes { + sugg: candidate + .map(|cand| errors::UnknownCrateTypesSub { span, snippet: cand }), + }, ); } } else { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 417e5a97069..5b98c9fafaa 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -40,12 +40,6 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` -lint_avoid_att_syntax = - avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - -lint_avoid_intel_syntax = - avoid using `.intel_syntax`, Intel syntax is the default - lint_bad_attribute_argument = bad attribute argument lint_bad_opt_access = {$msg} @@ -187,12 +181,6 @@ lint_builtin_unused_doc_comment = unused doc comment lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}` .suggestion = use `loop` -lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait - .help = consider implementing the trait by hand, or remove the `packed` attribute - -lint_cfg_attr_no_attributes = - `#[cfg_attr]` does not expand to any attributes - lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}` lint_closure_returning_async_block = closure returning async block can be made into an async closure @@ -249,11 +237,6 @@ lint_dropping_copy_types = calls to `std::mem::drop` with a value that implement lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing .label = argument has type `{$arg_ty}` -lint_duplicate_macro_attribute = - duplicated attribute - -lint_duplicate_matcher_binding = duplicate matcher binding - lint_enum_intrinsics_mem_discriminant = the return value of `mem::discriminant` is unspecified when called with a non-enum type .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum @@ -409,9 +392,6 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive -lint_incomplete_include = - include macro expected single expression in source - lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly .label = use a different label that doesn't start with `0` or `1` .help = start numbering with `2` instead @@ -427,9 +407,6 @@ lint_invalid_asm_label_named = avoid using named labels in inline assembly .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information lint_invalid_asm_label_no_span = the label may be declared in the expansion of a macro -lint_invalid_crate_type_value = invalid `crate_type` value - .suggestion = did you mean - # FIXME: we should ordinalize $valid_up_to when we add support for doing so lint_invalid_from_utf8_checked = calls to `{$method}` with an invalid literal always return an error .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes @@ -470,15 +447,9 @@ lint_int_to_ptr_transmutes = transmuting an integer to a pointer creates a point .suggestion_with_exposed_provenance = use `std::ptr::with_exposed_provenance{$suffix}` instead to use a previously exposed provenance .suggestion_without_provenance_mut = if you truly mean to create a pointer without provenance, use `std::ptr::without_provenance_mut` -lint_legacy_derive_helpers = derive helper attribute is used before it is introduced - .label = the attribute is introduced here - lint_lintpass_by_hand = implementing `LintPass` by hand .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead -lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths - .note = the macro is defined here - lint_macro_expr_fragment_specifier_2024_migration = the `expr` fragment specifier will accept more expressions in the 2024 edition .suggestion = to keep the existing behavior, use the `expr_2021` fragment specifier @@ -486,10 +457,6 @@ lint_macro_is_private = macro `{$ident}` is private lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used -lint_macro_use_deprecated = - applying the `#[macro_use]` attribute to an `extern crate` item is deprecated - .help = remove it and import macros at use sites with a `use` item instead - lint_malformed_attribute = malformed lint attribute input lint_map_unit_fn = `Iterator::map` call that discard the iterator's values @@ -499,10 +466,6 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items .suggestion = you might have meant to use `Iterator::for_each` -lint_metavariable_still_repeating = variable `{$name}` is still repeating at this depth - -lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator - lint_mismatched_lifetime_syntaxes_eliding_while_named = eliding a lifetime that's named elsewhere is confusing @@ -548,9 +511,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_mixed = lint_mismatched_lifetime_syntaxes_suggestion_mixed_only_paths = use `'_` for type paths -lint_missing_unsafe_on_extern = extern blocks should be unsafe - .suggestion = needs `unsafe` before the extern keyword - lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} @@ -674,9 +634,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass lint_opaque_hidden_inferred_bound_sugg = add this bound -lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro - .suggestion = use pat_param to preserve semantics - lint_out_of_scope_macro_calls = cannot find macro `{$path}` in the current scope when looking from {$location} .label = not found from {$location} .help = import `macro_rules` with `use` to make it callable above its definition @@ -719,9 +676,6 @@ lint_pattern_in_foreign = patterns aren't allowed in foreign function declaratio lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported .suggestion = consider making the `extern crate` item publicly accessible -lint_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope - .label = names from parent modules are not accessible without an explicit import - lint_query_instability = using `{$query}` can result in unstable query results .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale @@ -762,9 +716,6 @@ lint_redundant_semicolons_suggestion = remove {$multiple_semicolons -> *[false] this semicolon } -lint_reexport_private_dependency = - {$kind} `{$name}` from private dependency '{$krate}' is re-exported - lint_remove_mut_from_pattern = remove `mut` from the parameter lint_removed_lint = lint `{$name}` has been removed: {$reason} @@ -826,10 +777,6 @@ lint_symbol_intern_string_literal = using `Symbol::intern` on a string literal lint_too_large_char_cast = value exceeds maximum `char` value .note = maximum valid `char` value is `0x10FFFF` -lint_trailing_semi_macro = trailing semicolon in macro used in expression position - .note1 = macro invocations at the end of a block are treated as expressions - .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}` - lint_ty_qualified = usage of qualified `ty::{$ty}` .suggestion = try importing it and using it unqualified @@ -935,13 +882,9 @@ lint_unknown_lint = *[false] did you mean: `{$replace}` } -lint_unknown_macro_variable = unknown macro variable `{$name}` - lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}` .help = add `#![register_tool({$tool_name})]` to the crate root -lint_unnameable_test_items = cannot test inner items - lint_unnecessary_qualification = unnecessary qualification .suggestion = remove the unnecessary path segments @@ -964,10 +907,6 @@ lint_untranslatable_diag = diagnostics should be created using translatable mess lint_unused_allocation = unnecessary allocation, use `&` instead lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead -lint_unused_builtin_attribute = unused attribute `{$attr_name}` - .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}` - .suggestion = remove the attribute - lint_unused_closure = unused {$pre}{$count -> [one] closure @@ -993,14 +932,6 @@ lint_unused_def = unused {$pre}`{$def}`{$post} that must be used lint_unused_delim = unnecessary {$delim} around {$item} .suggestion = remove these {$delim} -lint_unused_doc_comment = unused doc comment - .label = rustdoc does not generate documentation for macro invocations - .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion - -lint_unused_extern_crate = unused extern crate - .label = unused - .suggestion = remove the unused `extern crate` - lint_unused_import_braces = braces around {$node} is unnecessary lint_unused_imports = {$num_snippets -> @@ -1014,15 +945,11 @@ lint_unused_imports = {$num_snippets -> } .help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module -lint_unused_label = unused label - lint_unused_lifetime = lifetime parameter `{$ident}` never used .suggestion = elide the unused lifetime lint_unused_macro_definition = unused macro definition: `{$name}` -lint_unused_macro_use = unused `#[macro_use]` import - lint_unused_op = unused {$op} that must be used .label = the {$op} produces a value .suggestion = use `let _ = ...` to ignore the resulting value diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c3c0a34df71..75a0f89321b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -29,12 +29,12 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, PatKind, PredicateOrigin, find_attr}; +use rustc_hir::{Body, FnDecl, ImplItemImplKind, PatKind, PredicateOrigin, find_attr}; use rustc_middle::bug; use rustc_middle::lint::LevelAndSource; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; +use rustc_middle::ty::{self, AssocContainer, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; use rustc_session::lint::FutureIncompatibilityReason; // hardwired lints from rustc_lint_defs pub use rustc_session::lint::builtin::*; @@ -61,7 +61,6 @@ use crate::lints::{ BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel, }; -use crate::nonstandard_style::{MethodLateContext, method_context}; use crate::{ EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, fluent_generated as fluent, @@ -469,14 +468,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { - let context = method_context(cx, impl_item.owner_id.def_id); + let container = cx.tcx.associated_item(impl_item.owner_id.def_id).container; - match context { + match container { // If the method is an impl for a trait, don't doc. - MethodLateContext::TraitImpl => return, - MethodLateContext::TraitAutoImpl => {} + AssocContainer::TraitImpl(_) => return, + AssocContainer::Trait => {} // If the method is an impl for an item with docs_hidden, don't doc. - MethodLateContext::PlainImpl => { + AssocContainer::InherentImpl => { let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()); let impl_ty = cx.tcx.type_of(parent).instantiate_identity(); let outerdef = match impl_ty.kind() { @@ -1321,9 +1320,8 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { - // Only lint inherent impl items. - if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() { - self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false); + if let ImplItemImplKind::Inherent { vis_span } = impl_item.impl_kind { + self.perform_lint(cx, "item", impl_item.owner_id.def_id, vis_span, false); } } } diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 943fcc0801b..e1c51ff8299 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { { // erase regions in self type for better diagnostic presentation let (self_ty, target_principal, supertrait_principal) = - tcx.erase_regions((self_ty, target_principal, supertrait_principal)); + tcx.erase_and_anonymize_regions((self_ty, target_principal, supertrait_principal)); let label2 = tcx .associated_items(item.owner_id) .find_by_ident_and_kind( diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 7300490b838..9029ee04471 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -64,17 +64,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::ProcMacroDeriveResolutionFallback { - span: macro_span, - ns_descr, - ident, - } => lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns_descr, ident } - .decorate_lint(diag), - BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => { - lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def } - .decorate_lint(diag) - } - BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { lints::ElidedLifetimesInPaths { subdiag: elided_lifetime_in_path_suggestion( @@ -87,10 +76,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::UnknownCrateTypes { span, candidate } => { - let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate }); - lints::UnknownCrateTypes { sugg }.decorate_lint(diag); - } BuiltinLintDiag::UnusedImports { remove_whole_use, num_to_remove, @@ -146,9 +131,6 @@ pub fn decorate_builtin_lint( stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } .decorate_lint(diag); } - BuiltinLintDiag::UnusedDocComment(attr_span) => { - lints::UnusedDocComment { span: attr_span }.decorate_lint(diag); - } BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; if is_foreign { @@ -158,12 +140,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { - lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); - } - BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => { - lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag); - } BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { lints::ReservedPrefix { label: label_span, @@ -183,18 +159,6 @@ pub fn decorate_builtin_lint( lints::ReservedMultihash { suggestion }.decorate_lint(diag); } } - BuiltinLintDiag::UnusedBuiltinAttribute { - attr_name, - macro_name, - invoc_span, - attr_span, - } => { - lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name, attr_span } - .decorate_lint(diag); - } - BuiltinLintDiag::TrailingMacro(is_trailing, name) => { - lints::TrailingMacro { is_trailing, name }.decorate_lint(diag); - } BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { lints::BreakWithLabelAndLoop { sub: lints::BreakWithLabelAndLoopSub { @@ -221,9 +185,6 @@ pub fn decorate_builtin_lint( }; lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } - BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => { - lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag); - } BuiltinLintDiag::SingleUseLifetime { param_span, use_span: Some((use_span, elide)), @@ -253,7 +214,6 @@ pub fn decorate_builtin_lint( .decorate_lint(diag); } BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - debug!(?deletion_span); lints::UnusedLifetime { deletion_span, ident }.decorate_lint(diag); } BuiltinLintDiag::NamedArgumentUsedPositionally { @@ -291,12 +251,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => { - lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag); - } - BuiltinLintDiag::UnusedExternCrate { span, removal_span } => { - lints::UnusedExternCrate { span, removal_span }.decorate_lint(diag); - } BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => { let suggestion_span = vis_span.between(ident_span); let code = if vis_span.is_empty() { "use " } else { " use " }; @@ -335,9 +289,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::ReexportPrivateDependency { name, kind, krate } => { - lints::ReexportPrivateDependency { name, kind, krate }.decorate_lint(diag); - } BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } @@ -377,15 +328,10 @@ pub fn decorate_builtin_lint( }); lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag); } - BuiltinLintDiag::MacroUseDeprecated => { - lints::MacroUseDeprecated.decorate_lint(diag); - } - BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag), BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => { lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } .decorate_lint(diag); } - BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag), BuiltinLintDiag::MacroIsPrivate(ident) => { lints::MacroIsPrivate { ident }.decorate_lint(diag); } @@ -398,36 +344,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::UnstableFeature(msg) => { lints::UnstableFeature { msg }.decorate_lint(diag); } - BuiltinLintDiag::AvoidUsingIntelSyntax => { - lints::AvoidIntelSyntax.decorate_lint(diag); - } - BuiltinLintDiag::AvoidUsingAttSyntax => { - lints::AvoidAttSyntax.decorate_lint(diag); - } - BuiltinLintDiag::IncompleteInclude => { - lints::IncompleteInclude.decorate_lint(diag); - } - BuiltinLintDiag::UnnameableTestItems => { - lints::UnnameableTestItems.decorate_lint(diag); - } - BuiltinLintDiag::DuplicateMacroAttribute => { - lints::DuplicateMacroAttribute.decorate_lint(diag); - } - BuiltinLintDiag::CfgAttrNoAttributes => { - lints::CfgAttrNoAttributes.decorate_lint(diag); - } - BuiltinLintDiag::MetaVariableStillRepeating(name) => { - lints::MetaVariableStillRepeating { name }.decorate_lint(diag); - } - BuiltinLintDiag::MetaVariableWrongOperator => { - lints::MetaVariableWrongOperator.decorate_lint(diag); - } - BuiltinLintDiag::DuplicateMatcherBinding => { - lints::DuplicateMatcherBinding.decorate_lint(diag); - } - BuiltinLintDiag::UnknownMacroVariable(name) => { - lints::UnknownMacroVariable { name }.decorate_lint(diag); - } BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a56b753bda7..9e1fc598171 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -176,7 +176,7 @@ fn suggest_question_mark<'tcx>( cause, param_env, // Erase any region vids from the type, which may not be resolved - infcx.tcx.erase_regions(ty), + infcx.tcx.erase_and_anonymize_regions(ty), into_iterator_did, ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 56d65ed08f9..b7312484de5 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::lint::AmbiguityErrorDiag; use rustc_span::edition::Edition; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds}; use crate::errors::{OverruledAttributeSub, RequestedLevel}; @@ -2536,15 +2536,6 @@ pub(crate) mod unexpected_cfg_value { } #[derive(LintDiagnostic)] -#[diag(lint_macro_use_deprecated)] -#[help] -pub(crate) struct MacroUseDeprecated; - -#[derive(LintDiagnostic)] -#[diag(lint_unused_macro_use)] -pub(crate) struct UnusedMacroUse; - -#[derive(LintDiagnostic)] #[diag(lint_private_extern_crate_reexport, code = E0365)] pub(crate) struct PrivateExternCrateReexport { pub ident: Ident, @@ -2553,10 +2544,6 @@ pub(crate) struct PrivateExternCrateReexport { } #[derive(LintDiagnostic)] -#[diag(lint_unused_label)] -pub(crate) struct UnusedLabel; - -#[derive(LintDiagnostic)] #[diag(lint_macro_is_private)] pub(crate) struct MacroIsPrivate { pub ident: Ident, @@ -2586,50 +2573,6 @@ impl<'a> LintDiagnostic<'a, ()> for UnstableFeature { } #[derive(LintDiagnostic)] -#[diag(lint_avoid_intel_syntax)] -pub(crate) struct AvoidIntelSyntax; - -#[derive(LintDiagnostic)] -#[diag(lint_avoid_att_syntax)] -pub(crate) struct AvoidAttSyntax; - -#[derive(LintDiagnostic)] -#[diag(lint_incomplete_include)] -pub(crate) struct IncompleteInclude; - -#[derive(LintDiagnostic)] -#[diag(lint_unnameable_test_items)] -pub(crate) struct UnnameableTestItems; - -#[derive(LintDiagnostic)] -#[diag(lint_duplicate_macro_attribute)] -pub(crate) struct DuplicateMacroAttribute; - -#[derive(LintDiagnostic)] -#[diag(lint_cfg_attr_no_attributes)] -pub(crate) struct CfgAttrNoAttributes; - -#[derive(LintDiagnostic)] -#[diag(lint_metavariable_still_repeating)] -pub(crate) struct MetaVariableStillRepeating { - pub name: MacroRulesNormalizedIdent, -} - -#[derive(LintDiagnostic)] -#[diag(lint_metavariable_wrong_operator)] -pub(crate) struct MetaVariableWrongOperator; - -#[derive(LintDiagnostic)] -#[diag(lint_duplicate_matcher_binding)] -pub(crate) struct DuplicateMatcherBinding; - -#[derive(LintDiagnostic)] -#[diag(lint_unknown_macro_variable)] -pub(crate) struct UnknownMacroVariable { - pub name: MacroRulesNormalizedIdent, -} - -#[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] #[help] pub(crate) struct UnusedCrateDependency { @@ -2715,22 +2658,6 @@ pub(crate) struct AbsPathWithModuleSugg { } #[derive(LintDiagnostic)] -#[diag(lint_proc_macro_derive_resolution_fallback)] -pub(crate) struct ProcMacroDeriveResolutionFallback { - #[label] - pub span: Span, - pub ns_descr: &'static str, - pub ident: Ident, -} - -#[derive(LintDiagnostic)] -#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)] -pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths { - #[note] - pub definition: Span, -} - -#[derive(LintDiagnostic)] #[diag(lint_hidden_lifetime_parameters)] pub(crate) struct ElidedLifetimesInPaths { #[subdiagnostic] @@ -2738,21 +2665,6 @@ pub(crate) struct ElidedLifetimesInPaths { } #[derive(LintDiagnostic)] -#[diag(lint_invalid_crate_type_value)] -pub(crate) struct UnknownCrateTypes { - #[subdiagnostic] - pub sugg: Option<UnknownCrateTypesSub>, -} - -#[derive(Subdiagnostic)] -#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")] -pub(crate) struct UnknownCrateTypesSub { - #[primary_span] - pub span: Span, - pub candidate: Symbol, -} - -#[derive(LintDiagnostic)] #[diag(lint_unused_imports)] pub(crate) struct UnusedImports { #[subdiagnostic] @@ -2810,14 +2722,6 @@ pub(crate) enum RedundantImportSub { } #[derive(LintDiagnostic)] -#[diag(lint_unused_doc_comment)] -#[help] -pub(crate) struct UnusedDocComment { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] pub(crate) enum PatternsInFnsWithoutBody { #[diag(lint_pattern_in_foreign)] Foreign { @@ -2841,21 +2745,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub { } #[derive(LintDiagnostic)] -#[diag(lint_legacy_derive_helpers)] -pub(crate) struct LegacyDeriveHelpers { - #[label] - pub span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(lint_or_patterns_back_compat)] -pub(crate) struct OrPatternsBackCompat { - #[suggestion(code = "{suggestion}", applicability = "machine-applicable")] - pub span: Span, - pub suggestion: String, -} - -#[derive(LintDiagnostic)] #[diag(lint_reserved_prefix)] pub(crate) struct ReservedPrefix { #[label] @@ -2876,27 +2765,6 @@ pub(crate) struct RawPrefix { } #[derive(LintDiagnostic)] -#[diag(lint_unused_builtin_attribute)] -pub(crate) struct UnusedBuiltinAttribute { - #[note] - pub invoc_span: Span, - pub attr_name: Symbol, - pub macro_name: String, - #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] - pub attr_span: Span, -} - -#[derive(LintDiagnostic)] -#[diag(lint_trailing_semi_macro)] -pub(crate) struct TrailingMacro { - #[note(lint_note1)] - #[note(lint_note2)] - pub is_trailing: bool, - - pub name: Ident, -} - -#[derive(LintDiagnostic)] #[diag(lint_break_with_label_and_loop)] pub(crate) struct BreakWithLabelAndLoop { #[subdiagnostic] @@ -2939,13 +2807,6 @@ pub(crate) enum DeprecatedWhereClauseLocationSugg { } #[derive(LintDiagnostic)] -#[diag(lint_missing_unsafe_on_extern)] -pub(crate) struct MissingUnsafeOnExtern { - #[suggestion(code = "unsafe ", applicability = "machine-applicable")] - pub suggestion: Span, -} - -#[derive(LintDiagnostic)] #[diag(lint_single_use_lifetime)] pub(crate) struct SingleUseLifetime { #[label(lint_label_param)] @@ -2993,23 +2854,6 @@ pub(crate) struct NamedArgumentUsedPositionally { } #[derive(LintDiagnostic)] -#[diag(lint_byte_slice_in_packed_struct_with_derive)] -#[help] -pub(crate) struct ByteSliceInPackedStructWithDerive { - // FIXME: make this translatable - pub ty: String, -} - -#[derive(LintDiagnostic)] -#[diag(lint_unused_extern_crate)] -pub(crate) struct UnusedExternCrate { - #[label] - pub span: Span, - #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] - pub removal_span: Span, -} - -#[derive(LintDiagnostic)] #[diag(lint_extern_crate_not_idiomatic)] pub(crate) struct ExternCrateNotIdiomatic { #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")] @@ -3057,14 +2901,6 @@ pub(crate) struct HiddenGlobReexports { } #[derive(LintDiagnostic)] -#[diag(lint_reexport_private_dependency)] -pub(crate) struct ReexportPrivateDependency { - pub name: String, - pub kind: String, - pub krate: Symbol, -} - -#[derive(LintDiagnostic)] #[diag(lint_unnecessary_qualification)] pub(crate) struct UnusedQualifications { #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 5513c703f1d..93f067d0983 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .explicit_super_predicates_of(def_id) .iter_identity_copied() .filter_map(|(pred, _)| pred.as_trait_clause()) - .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized)); + .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized)) + .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 65075cfecfa..7f643a551bb 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::{Attribute, GenericParamKind, PatExprKind, PatKind, find_attr}; use rustc_middle::hir::nested_filter::All; -use rustc_middle::ty; +use rustc_middle::ty::AssocContainer; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; @@ -20,29 +20,6 @@ use crate::lints::{ }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; -#[derive(PartialEq)] -pub(crate) enum MethodLateContext { - TraitAutoImpl, - TraitImpl, - PlainImpl, -} - -pub(crate) fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext { - let item = cx.tcx.associated_item(id); - match item.container { - ty::AssocItemContainer::Trait => MethodLateContext::TraitAutoImpl, - ty::AssocItemContainer::Impl => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) { - Some(_) => MethodLateContext::TraitImpl, - None => MethodLateContext::PlainImpl, - }, - } -} - -fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool { - let item = cx.tcx.associated_item(ii.owner_id); - item.trait_item_def_id.is_some() -} - declare_lint! { /// The `non_camel_case_types` lint detects types, variants, traits and /// type parameters that don't have camel case names. @@ -389,8 +366,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { id: LocalDefId, ) { match &fk { - FnKind::Method(ident, sig, ..) => match method_context(cx, id) { - MethodLateContext::PlainImpl => { + FnKind::Method(ident, sig, ..) => match cx.tcx.associated_item(id).container { + AssocContainer::InherentImpl => { if sig.header.abi != ExternAbi::Rust && find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..)) { @@ -398,10 +375,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } self.check_snake_case(cx, "method", ident); } - MethodLateContext::TraitAutoImpl => { + AssocContainer::Trait => { self.check_snake_case(cx, "trait method", ident); } - _ => (), + AssocContainer::TraitImpl(_) => {} }, FnKind::ItemFn(ident, _, header) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) @@ -602,7 +579,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { if let hir::ImplItemKind::Const(..) = ii.kind - && !assoc_item_in_trait_impl(cx, ii) + && let hir::ImplItemImplKind::Inherent { .. } = ii.impl_kind { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", None, &ii.ident); } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a72b802eb5d..88527fa2e6e 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -935,7 +935,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { if let hir::ItemKind::Enum(_, _, ref enum_definition) = it.kind { let t = cx.tcx.type_of(it.owner_id).instantiate_identity(); - let ty = cx.tcx.erase_regions(t); + let ty = cx.tcx.erase_and_anonymize_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, variants, .. } = &layout.variants diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 2e84233e5a5..40a818a3c9d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -11,7 +11,7 @@ use rustc_hir_id::{HashStableContext, HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::def_id::DefPathHash; pub use rustc_span::edition::Edition; -use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use serde::{Deserialize, Serialize}; pub use self::Level::*; @@ -620,17 +620,7 @@ pub enum DeprecatedSinceKind { #[derive(Debug)] pub enum BuiltinLintDiag { AbsPathWithModule(Span), - ProcMacroDeriveResolutionFallback { - span: Span, - ns_descr: &'static str, - ident: Ident, - }, - MacroExpandedMacroExportsAccessedByAbsolutePaths(Span), ElidedLifetimesInPaths(usize, Span, bool, Span), - UnknownCrateTypes { - span: Span, - candidate: Option<Symbol>, - }, UnusedImports { remove_whole_use: bool, num_to_remove: usize, @@ -646,20 +636,11 @@ pub enum BuiltinLintDiag { path: String, since_kind: DeprecatedSinceKind, }, - UnusedDocComment(Span), - UnusedBuiltinAttribute { - attr_name: Symbol, - macro_name: String, - invoc_span: Span, - attr_span: Span, - }, PatternsInFnsWithoutBody { span: Span, ident: Ident, is_foreign: bool, }, - LegacyDeriveHelpers(Span), - OrPatternsBackCompat(Span, String), ReservedPrefix(Span, String), /// `'r#` in edition < 2021. RawPrefix(Span), @@ -668,15 +649,11 @@ pub enum BuiltinLintDiag { is_string: bool, suggestion: Span, }, - TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), - MissingUnsafeOnExtern { - suggestion: Span, - }, SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, @@ -701,14 +678,6 @@ pub enum BuiltinLintDiag { /// Indicates if the named argument is used as a width/precision for formatting is_formatting_arg: bool, }, - ByteSliceInPackedStructWithDerive { - // FIXME: enum of byte/string - ty: String, - }, - UnusedExternCrate { - span: Span, - removal_span: Span, - }, ExternCrateNotIdiomatic { vis_span: Span, ident_span: Span, @@ -736,11 +705,6 @@ pub enum BuiltinLintDiag { /// The local binding that shadows the glob reexport. private_item_span: Span, }, - ReexportPrivateDependency { - name: String, - kind: String, - krate: Symbol, - }, UnusedQualifications { /// The span of the unnecessarily-qualified path to remove. removal_span: Span, @@ -763,27 +727,14 @@ pub enum BuiltinLintDiag { span: Span, typo_name: Option<Symbol>, }, - MacroUseDeprecated, - UnusedMacroUse, PrivateExternCrateReexport { source: Ident, extern_crate_span: Span, }, - UnusedLabel, MacroIsPrivate(Ident), UnusedMacroDefinition(Symbol), MacroRuleNeverUsed(usize, Symbol), UnstableFeature(DiagMessage), - AvoidUsingIntelSyntax, - AvoidUsingAttSyntax, - IncompleteInclude, - UnnameableTestItems, - DuplicateMacroAttribute, - CfgAttrNoAttributes, - MetaVariableStillRepeating(MacroRulesNormalizedIdent), - MetaVariableWrongOperator, - DuplicateMatcherBinding, - UnknownMacroVariable(MacroRulesNormalizedIdent), UnusedCrateDependency { extern_crate: Symbol, local_crate: Symbol, diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index cd352ce3d0f..0dfd1b13df5 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -11,7 +11,7 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version -# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`. +# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa` and `rustc_windows_rc`. cc = "=1.2.16" # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 225ab8c846d..9d21d0d22e3 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -254,7 +254,10 @@ fn main() { println!("cargo:rustc-link-lib=kstat"); } - if (target.starts_with("arm") && !target.contains("freebsd") && !target.contains("ohos")) + if (target.starts_with("arm") + && !target.starts_with("arm64") + && !target.contains("freebsd") + && !target.contains("ohos")) || target.starts_with("mips-") || target.starts_with("mipsel-") || target.starts_with("powerpc-") diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index 2332ff9b323..72f68d685cd 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -5,13 +5,12 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -# tracing > 0.1.37 have huge binary size / instructions regression -tracing = "=0.1.37" +tracing = "0.1.41" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.3.1" # tidy-alphabetical-end [features] # tidy-alphabetical-start -max_level_info = ['tracing/max_level_info'] +max_level_info = ['tracing/max_level_info', 'tracing/release_max_level_info'] # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 110b26c62ef..0c8d1f32e99 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1194,10 +1194,6 @@ impl<'a> CrateMetadataRef<'a> { self.root.tables.default_fields.get(self, id).map(|d| d.decode(self)) } - fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> { - self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) - } - fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId { self.root .tables @@ -1359,14 +1355,9 @@ impl<'a> CrateMetadataRef<'a> { } _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; - let container = self.root.tables.assoc_container.get(self, id).unwrap(); + let container = self.root.tables.assoc_container.get(self, id).unwrap().decode(self); - ty::AssocItem { - kind, - def_id: self.local_def_id(id), - trait_item_def_id: self.get_trait_item_def_id(id), - container, - } + ty::AssocItem { kind, def_id: self.local_def_id(id), container } } fn get_ctor(self, node_id: DefIndex) -> Option<(CtorKind, DefId)> { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a7e7e9985f4..db66938457f 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -22,7 +22,7 @@ use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::mir::interpret; use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; -use rustc_middle::ty::AssocItemContainer; +use rustc_middle::ty::AssocContainer; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::{bug, span_bug}; @@ -1254,8 +1254,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> DefKind::AssocTy => { let assoc_item = tcx.associated_item(def_id); match assoc_item.container { - ty::AssocItemContainer::Impl => true, - ty::AssocItemContainer::Trait => assoc_item.defaultness(tcx).has_value(), + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, + ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), } } DefKind::TyParam => { @@ -1725,24 +1725,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let item = tcx.associated_item(def_id); - self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx)); - self.tables.assoc_container.set_some(def_id.index, item.container); - - match item.container { - AssocItemContainer::Trait => { - if item.is_type() { - self.encode_explicit_item_bounds(def_id); - self.encode_explicit_item_self_bounds(def_id); - if tcx.is_conditionally_const(def_id) { - record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] - <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder()); - } - } - } - AssocItemContainer::Impl => { - if let Some(trait_item_def_id) = item.trait_item_def_id { - self.tables.trait_item_def_id.set_some(def_id.index, trait_item_def_id.into()); - } + if matches!(item.container, AssocContainer::Trait | AssocContainer::TraitImpl(_)) { + self.tables.defaultness.set_some(def_id.index, item.defaultness(tcx)); + } + + record!(self.tables.assoc_container[def_id] <- item.container); + + if let AssocContainer::Trait = item.container + && item.is_type() + { + self.encode_explicit_item_bounds(def_id); + self.encode_explicit_item_self_bounds(def_id); + if tcx.is_conditionally_const(def_id) { + record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id] + <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder()); } } if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 1f7d142d330..720970bbaf9 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -447,7 +447,6 @@ define_tables! { coroutine_by_move_body_def_id: Table<DefIndex, RawDefId>, eval_static_initializer: Table<DefIndex, LazyValue<mir::interpret::ConstAllocation<'static>>>, trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, - trait_item_def_id: Table<DefIndex, RawDefId>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, default_fields: Table<DefIndex, LazyValue<DefId>>, params_in_repr: Table<DefIndex, LazyValue<DenseBitSet<u32>>>, @@ -459,7 +458,7 @@ define_tables! { def_keys: Table<DefIndex, LazyValue<DefKey>>, proc_macro_quoted_spans: Table<usize, LazyValue<Span>>, variant_data: Table<DefIndex, LazyValue<VariantData>>, - assoc_container: Table<DefIndex, ty::AssocItemContainer>, + assoc_container: Table<DefIndex, LazyValue<ty::AssocContainer>>, macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>, proc_macro: Table<DefIndex, MacroKind>, deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>, diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index 34180001f80..4b2dc2c814e 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -102,7 +102,7 @@ trivially_parameterized_over_tcx! { rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault, rustc_middle::mir::ConstQualifs, rustc_middle::ty::AnonConstKind, - rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::AssocContainer, rustc_middle::ty::AsyncDestructor, rustc_middle::ty::Asyncness, rustc_middle::ty::DeducedParamAttrs, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 2cb07a28a8a..a882ee4f2b9 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -222,13 +222,6 @@ fixed_size_enum! { } fixed_size_enum! { - ty::AssocItemContainer { - ( Trait ) - ( Impl ) - } -} - -fixed_size_enum! { MacroKind { ( Attr ) ( Bang ) diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 7520bc262c6..dad402ec696 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -72,7 +72,7 @@ pub enum TypeMismatchReason { #[help] pub(crate) struct RecursionLimitReached<'tcx> { pub ty: Ty<'tcx>, - pub suggested_limit: rustc_session::Limit, + pub suggested_limit: rustc_hir::limit::Limit, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 4fe4c2dadee..153605ee7f8 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -27,7 +27,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; pub use rustc_type_ir as ir; -pub use rustc_type_ir::CanonicalTyVarKind; use smallvec::SmallVec; use crate::mir::ConstraintCategory; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2ea92a39d48..67962813ae4 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -724,6 +724,11 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> } // If we get here, we have to check per-byte provenance, and join them together. let prov = 'prov: { + if !Prov::OFFSET_IS_ADDR { + // FIXME(#146291): We need to ensure that we don't mix different pointers with + // the same provenance. + return Err(AllocError::ReadPartialPointer(range.start)); + } // Initialize with first fragment. Must have index 0. let Some((mut joint_prov, 0)) = self.provenance.get_byte(range.start, cx) else { break 'prov None; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index dbbd95408c8..720e58d7aa0 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -11,6 +11,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use tracing::trace; use super::{AllocRange, CtfeProvenance, Provenance, alloc_range}; +use crate::mir::interpret::{AllocError, AllocResult}; /// Stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -137,6 +138,11 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { let Some(bytes) = self.bytes.as_deref_mut() else { return true; }; + if !Prov::OFFSET_IS_ADDR { + // FIXME(#146291): We need to ensure that we don't mix different pointers with + // the same provenance. + return false; + } let ptr_size = cx.data_layout().pointer_size(); while let Some((offset, (prov, _))) = bytes.iter().next().copied() { // Check if this fragment starts a pointer. @@ -285,7 +291,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { dest: Size, count: u64, cx: &impl HasDataLayout, - ) -> ProvenanceCopy<Prov> { + ) -> AllocResult<ProvenanceCopy<Prov>> { let shift_offset = move |idx, offset| { // compute offset for current repetition let dest_offset = dest + src.size * idx; // `Size` operations @@ -363,6 +369,12 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { } trace!("byte provenances: {bytes:?}"); + if !bytes.is_empty() && !Prov::OFFSET_IS_ADDR { + // FIXME(#146291): We need to ensure that we don't mix different pointers with + // the same provenance. + return Err(AllocError::ReadPartialPointer(src.start)); + } + // And again a buffer for the new list on the target side. let mut dest_bytes = Vec::with_capacity(bytes.len() * (count as usize)); for i in 0..count { @@ -373,7 +385,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { dest_bytes_box = Some(dest_bytes.into_boxed_slice()); } - ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box } + Ok(ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box }) } /// Applies a provenance copy. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bed99a4ff2a..9762e0f21da 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> { .expect("statics should not have generic parameters"); let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); assert!(layout.is_sized()); - (layout.size, layout.align.abi) + + // Take over-alignment from attributes into account. + let align = match tcx.codegen_fn_attrs(def_id).alignment { + Some(align_from_attribute) => { + Ord::max(align_from_attribute, layout.align.abi) + } + None => layout.align.abi, + }; + + (layout.size, align) } } GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e25f35c59c2..ecf35d9dd6d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -41,7 +41,7 @@ impl<'tcx> TyCtxt<'tcx> { let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); - let inputs = self.erase_regions(typing_env.as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions(typing_env.as_query_input(cid)); self.eval_to_allocation_raw(inputs) } @@ -172,8 +172,9 @@ impl<'tcx> TyCtxt<'tcx> { ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = - self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions( + typing_env.with_post_analysis_normalized(self).as_query_input(cid), + ); if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) @@ -192,8 +193,9 @@ impl<'tcx> TyCtxt<'tcx> { ) -> ConstToValTreeResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. - let inputs = - self.erase_regions(typing_env.with_post_analysis_normalized(self).as_query_input(cid)); + let inputs = self.erase_and_anonymize_regions( + typing_env.with_post_analysis_normalized(self).as_query_input(cid), + ); debug!(?inputs); let res = if !span.is_dummy() { // The query doesn't know where it is being invoked, so we need to fix the span. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a7d99f513a1..f9d0a5f0a3b 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -78,8 +78,9 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option<Self> { let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir { // see notes on #41697 below - let node_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + let node_path = ty::print::with_no_trimmed_paths!( + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())) + ); filters.split('|').any(|or_filter| { or_filter.split('&').all(|and_filter| { let and_filter_trimmed = and_filter.trim(); @@ -173,9 +174,10 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { // trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`. pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { // see notes on #41697 above - let def_path = ty::print::with_forced_impl_filename_line!( - self.tcx().def_path_str(body.source.def_id()) - ); + let def_path = + ty::print::with_no_trimmed_paths!(ty::print::with_forced_impl_filename_line!( + self.tcx().def_path_str(body.source.def_id()) + )); // ignore-tidy-odd-backticks the literal below is fine write!(w, "// MIR for `{def_path}")?; match body.source.promoted { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index bea2191c560..4c00b769237 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -318,7 +318,7 @@ trivial! { rustc_middle::traits::WellFormedLoc, rustc_middle::ty::adjustment::CoerceUnsizedInfo, rustc_middle::ty::AssocItem, - rustc_middle::ty::AssocItemContainer, + rustc_middle::ty::AssocContainer, rustc_middle::ty::Asyncness, rustc_middle::ty::AsyncDestructor, rustc_middle::ty::BoundVariableKind, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 874cee54c7c..0e645a3aae4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -135,7 +135,7 @@ use crate::traits::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; -use crate::ty::print::{PrintTraitRefExt, describe_as_module}; +use crate::ty::print::PrintTraitRefExt; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{ self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty, @@ -761,9 +761,9 @@ rustc_queries! { } /// Erases regions from `ty` to yield a new type. - /// Normally you would just use `tcx.erase_regions(value)`, + /// Normally you would just use `tcx.erase_and_anonymize_regions(value)`, /// however, which uses this query as a kind of cache. - query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { + query erase_and_anonymize_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it // is not a good candidates for "replay" because it is essentially a // pure function of its input (and hence the expectation is that @@ -1881,6 +1881,7 @@ rustc_queries! { } /// Returns whether the impl or associated function has the `default` keyword. + /// Note: This will ICE on inherent impl items. Consider using `AssocItem::defaultness`. query defaultness(def_id: DefId) -> hir::Defaultness { desc { |tcx| "looking up whether `{}` has `default`", tcx.def_path_str(def_id) } separate_provide_extern @@ -2731,3 +2732,12 @@ rustc_queries! { rustc_with_all_queries! { define_callbacks! } rustc_feedable_queries! { define_feedable! } + +fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String { + let def_id = def_id.into(); + if def_id.is_top_level_module() { + "top-level module".to_string() + } else { + format!("module `{}`", tcx.def_path_str(def_id)) + } +} diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index c9b9ec771b3..463e4c58805 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -55,7 +55,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { Err(e) => ty::Const::new_error(self.tcx, e), Ok(Some(bac)) => { - let args = self.tcx.erase_regions(uv.args); + let args = self.tcx.erase_and_anonymize_regions(uv.args); let bac = bac.instantiate(self.tcx, args); return bac.fold_with(self); } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index a902a8a61e5..768646c7630 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -5,15 +5,17 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_hir::find_attr; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::{Ident, Symbol}; +use rustc_span::{ErrorGuaranteed, Ident, Symbol}; use super::{TyCtxt, Visibility}; use crate::ty; #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)] -pub enum AssocItemContainer { +pub enum AssocContainer { Trait, - Impl, + InherentImpl, + /// The `DefId` points to the trait item being implemented. + TraitImpl(Result<DefId, ErrorGuaranteed>), } /// Information about an associated item @@ -21,11 +23,7 @@ pub enum AssocItemContainer { pub struct AssocItem { pub def_id: DefId, pub kind: AssocKind, - pub container: AssocItemContainer, - - /// If this is an item in an impl of a trait then this is the `DefId` of - /// the associated item on the trait that this implements. - pub trait_item_def_id: Option<DefId>, + pub container: AssocContainer, } impl AssocItem { @@ -55,7 +53,34 @@ impl AssocItem { /// /// [`type_of`]: crate::ty::TyCtxt::type_of pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness { - tcx.defaultness(self.def_id) + match self.container { + AssocContainer::InherentImpl => hir::Defaultness::Final, + AssocContainer::Trait | AssocContainer::TraitImpl(_) => tcx.defaultness(self.def_id), + } + } + + pub fn expect_trait_impl(&self) -> Result<DefId, ErrorGuaranteed> { + let AssocContainer::TraitImpl(trait_item_id) = self.container else { + bug!("expected item to be in a trait impl: {:?}", self.def_id); + }; + trait_item_id + } + + /// If this is a trait impl item, returns the `DefId` of the trait item this implements. + /// Otherwise, returns `DefId` for self. Returns an Err in case the trait item was not + /// resolved successfully. + pub fn trait_item_or_self(&self) -> Result<DefId, ErrorGuaranteed> { + match self.container { + AssocContainer::TraitImpl(id) => id, + AssocContainer::Trait | AssocContainer::InherentImpl => Ok(self.def_id), + } + } + + pub fn trait_item_def_id(&self) -> Option<DefId> { + match self.container { + AssocContainer::TraitImpl(Ok(id)) => Some(id), + _ => None, + } } #[inline] @@ -71,16 +96,18 @@ impl AssocItem { #[inline] pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> { match self.container { - AssocItemContainer::Impl => None, - AssocItemContainer::Trait => Some(tcx.parent(self.def_id)), + AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => None, + AssocContainer::Trait => Some(tcx.parent(self.def_id)), } } #[inline] pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> { match self.container { - AssocItemContainer::Impl => Some(tcx.parent(self.def_id)), - AssocItemContainer::Trait => None, + AssocContainer::InherentImpl | AssocContainer::TraitImpl(_) => { + Some(tcx.parent(self.def_id)) + } + AssocContainer::Trait => None, } } @@ -156,11 +183,11 @@ impl AssocItem { return false; } - let def_id = match (self.container, self.trait_item_def_id) { - (AssocItemContainer::Trait, _) => self.def_id, - (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did, - // Inherent impl but this attr is only applied to trait assoc items. - (AssocItemContainer::Impl, None) => return true, + let def_id = match self.container { + AssocContainer::Trait => self.def_id, + AssocContainer::TraitImpl(Ok(trait_item_did)) => trait_item_did, + AssocContainer::TraitImpl(Err(_)) => return false, + AssocContainer::InherentImpl => return true, }; find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 97c8a0336c2..79700d485c4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -38,6 +38,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; +use rustc_hir::limit::Limit; use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; @@ -45,14 +46,14 @@ use rustc_query_system::cache::WithDepNode; use rustc_query_system::dep_graph::DepNodeIndex; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; +use rustc_session::Session; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; -use rustc_session::{Limit, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_type_ir::TyKind::*; -use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{ CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph, @@ -94,6 +95,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type LocalDefId = LocalDefId; type TraitId = DefId; + type ForeignId = DefId; + type FunctionId = DefId; + type ClosureId = DefId; + type CoroutineClosureId = DefId; + type CoroutineId = DefId; + type AdtId = DefId; + type ImplId = DefId; type Span = Span; type GenericArgs = ty::GenericArgsRef<'tcx>; @@ -492,6 +500,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP) } + fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> DefId { + self.require_lang_item(solver_adt_lang_item_to_lang_item(lang_item), DUMMY_SP) + } + fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool { self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item)) } @@ -500,6 +512,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item)) } + fn is_adt_lang_item(self, def_id: DefId, lang_item: SolverAdtLangItem) -> bool { + self.is_lang_item(def_id, solver_adt_lang_item_to_lang_item(lang_item)) + } + fn is_default_trait(self, def_id: DefId) -> bool { self.is_default_trait(def_id) } @@ -512,6 +528,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?) } + fn as_adt_lang_item(self, def_id: DefId) -> Option<SolverAdtLangItem> { + lang_item_to_solver_adt_lang_item(self.lang_items().from_def_id(def_id)?) + } + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> { self.associated_items(def_id) .in_definition_order() @@ -631,7 +651,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"), } - let trait_impls = tcx.trait_impls_of(trait_def_id); + #[allow(rustc::usage_of_type_ir_traits)] + self.for_each_blanket_impl(trait_def_id, f) + } + fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) { + let trait_impls = self.trait_impls_of(trait_def_id); for &impl_def_id in trait_impls.blanket_impls() { f(impl_def_id); } @@ -783,6 +807,13 @@ bidirectional_lang_item_map! { DynMetadata, FutureOutput, Metadata, +// tidy-alphabetical-end +} + +bidirectional_lang_item_map! { + SolverAdtLangItem, lang_item_to_solver_adt_lang_item, solver_adt_lang_item_to_lang_item; + +// tidy-alphabetical-start Option, Poll, // tidy-alphabetical-end @@ -2245,7 +2276,16 @@ impl<'tcx> TyCtxt<'tcx> { let is_impl_item = match self.hir_node_by_def_id(suitable_region_binding_scope) { Node::Item(..) | Node::TraitItem(..) => false, - Node::ImplItem(..) => self.is_bound_region_in_impl_item(suitable_region_binding_scope), + Node::ImplItem(impl_item) => match impl_item.impl_kind { + // For now, we do not try to target impls of traits. This is + // because this message is going to suggest that the user + // change the fn signature, but they may not be free to do so, + // since the signature must match the trait. + // + // FIXME(#42706) -- in some cases, we could do better here. + hir::ImplItemImplKind::Trait { .. } => true, + _ => false, + }, _ => false, }; @@ -2299,21 +2339,6 @@ impl<'tcx> TyCtxt<'tcx> { None } - /// Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { - let container_id = self.parent(suitable_region_binding_scope.to_def_id()); - if self.impl_trait_ref(container_id).is_some() { - // For now, we do not try to target impls of traits. This is - // because this message is going to suggest that the user - // change the fn signature, but they may not be free to do so, - // since the signature must match the trait. - // - // FIXME(#42706) -- in some cases, we could do better here. - return true; - } - false - } - /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. pub fn has_strict_asm_symbol_naming(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index f4fead7e952..74b4adda7fd 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -6,20 +6,20 @@ use crate::ty::{ }; pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { erase_regions_ty, ..*providers }; + *providers = Providers { erase_and_anonymize_regions_ty, ..*providers }; } -fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { +fn erase_and_anonymize_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { // N.B., use `super_fold_with` here. If we used `fold_with`, it - // could invoke the `erase_regions_ty` query recursively. - ty.super_fold_with(&mut RegionEraserVisitor { tcx }) + // could invoke the `erase_and_anonymize_regions_ty` query recursively. + ty.super_fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx }) } impl<'tcx> TyCtxt<'tcx> { - /// Returns an equivalent value with all free regions removed (note - /// that late-bound regions remain, because they are important for - /// subtyping, but they are anonymized and normalized as well).. - pub fn erase_regions<T>(self, value: T) -> T + /// Returns an equivalent value with all free regions removed and + /// bound regions anonymized. (note that bound regions are important + /// for subtyping and generally type equality so *cannot* be removed) + pub fn erase_and_anonymize_regions<T>(self, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, { @@ -27,18 +27,18 @@ impl<'tcx> TyCtxt<'tcx> { if !value.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { return value; } - debug!("erase_regions({:?})", value); - let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); - debug!("erase_regions = {:?}", value1); + debug!("erase_and_anonymize_regions({:?})", value); + let value1 = value.fold_with(&mut RegionEraserAndAnonymizerVisitor { tcx: self }); + debug!("erase_and_anonymize_regions = {:?}", value1); value1 } } -struct RegionEraserVisitor<'tcx> { +struct RegionEraserAndAnonymizerVisitor<'tcx> { tcx: TyCtxt<'tcx>, } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserAndAnonymizerVisitor<'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -49,7 +49,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> { } else if ty.has_infer() { ty.super_fold_with(self) } else { - self.tcx.erase_regions_ty(ty) + self.tcx.erase_and_anonymize_regions_ty(ty) } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 3f854038651..66542525d28 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -7,6 +7,7 @@ use std::path::PathBuf; use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::limit::Limit; use rustc_macros::extension; pub use rustc_type_ir::error::ExpectedFound; @@ -233,7 +234,7 @@ impl<'tcx> TyCtxt<'tcx> { loop { // Look for the longest properly trimmed path that still fits in length_limit. short = with_forced_trimmed_paths!({ - let mut p = FmtPrinter::new_with_limit(self, ns, rustc_session::Limit(type_limit)); + let mut p = FmtPrinter::new_with_limit(self, ns, Limit(type_limit)); self.lift(t) .expect("could not lift for printing") .print(&mut p) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 3a51f79f121..34ead91b4f6 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -18,8 +18,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::print::{FmtPrinter, Print}; use crate::ty::{ - self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, AssocContainer, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; /// An `InstanceKind` along with the args that are needed to substitute the instance. @@ -544,7 +544,9 @@ impl<'tcx> Instance<'tcx> { // All regions in the result of this query are erased, so it's // fine to erase all of the input regions. - tcx.resolve_instance_raw(tcx.erase_regions(typing_env.as_query_input((def_id, args)))) + tcx.resolve_instance_raw( + tcx.erase_and_anonymize_regions(typing_env.as_query_input((def_id, args))), + ) } pub fn expect_resolve( @@ -609,26 +611,23 @@ impl<'tcx> Instance<'tcx> { debug!(" => fn pointer created for virtual call"); resolved.def = InstanceKind::ReifyShim(def_id, reason); } - // Reify `Trait::method` implementations if KCFI is enabled - // FIXME(maurer) only reify it if it is a vtable-safe function - _ if tcx.sess.is_sanitizer_kcfi_enabled() - && tcx - .opt_associated_item(def_id) - .and_then(|assoc| assoc.trait_item_def_id) - .is_some() => - { - // If this function could also go in a vtable, we need to `ReifyShim` it with - // KCFI because it can only attach one type per function. - resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason) - } - // Reify `::call`-like method implementations if KCFI is enabled - _ if tcx.sess.is_sanitizer_kcfi_enabled() - && tcx.is_closure_like(resolved.def_id()) => - { - // Reroute through a reify via the *unresolved* instance. The resolved one can't - // be directly reified because it's closure-like. The reify can handle the - // unresolved instance. - resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } + _ if tcx.sess.is_sanitizer_kcfi_enabled() => { + // Reify `::call`-like method implementations + if tcx.is_closure_like(resolved.def_id()) { + // Reroute through a reify via the *unresolved* instance. The resolved one can't + // be directly reified because it's closure-like. The reify can handle the + // unresolved instance. + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } + // Reify `Trait::method` implementations + // FIXME(maurer) only reify it if it is a vtable-safe function + } else if let Some(assoc) = tcx.opt_associated_item(def_id) + && let AssocContainer::Trait | AssocContainer::TraitImpl(Ok(_)) = + assoc.container + { + // If this function could also go in a vtable, we need to `ReifyShim` it with + // KCFI because it can only attach one type per function. + resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason) + } } _ => {} } @@ -681,7 +680,7 @@ impl<'tcx> Instance<'tcx> { && !matches!( tcx.opt_associated_item(def), Some(ty::AssocItem { - container: ty::AssocItemContainer::Trait, + container: ty::AssocContainer::Trait, .. }) ); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index aed94f9aa04..2114d080dfa 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -401,7 +401,10 @@ impl<'tcx> SizeSkeleton<'tcx> { match tail.kind() { ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => { debug_assert!(tail.has_non_region_param()); - Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) + Ok(SizeSkeleton::Pointer { + non_zero, + tail: tcx.erase_and_anonymize_regions(tail), + }) } ty::Error(guar) => { // Fixes ICE #124031 diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e567ba05f61..d4c001f625e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -109,7 +109,6 @@ pub use self::typeck_results::{ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, }; -pub use self::visit::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; @@ -1935,6 +1934,11 @@ impl<'tcx> TyCtxt<'tcx> { Some((parent, def_kind)) } + /// Returns the trait item that is implemented by the given item `DefId`. + pub fn trait_item_of(self, def_id: impl IntoQueryParam<DefId>) -> Option<DefId> { + self.opt_associated_item(def_id.into_query_param())?.trait_item_def_id() + } + /// If the given `DefId` is an associated item of a trait, /// returns the `DefId` of the trait; otherwise, returns `None`. pub fn trait_of_assoc(self, def_id: DefId) -> Option<DefId> { @@ -2150,17 +2154,12 @@ impl<'tcx> TyCtxt<'tcx> { let Some(item) = self.opt_associated_item(def_id) else { return false; }; - if item.container != ty::AssocItemContainer::Impl { - return false; - } - let Some(trait_item_def_id) = item.trait_item_def_id else { + let AssocContainer::TraitImpl(Ok(trait_item_def_id)) = item.container else { return false; }; - return !self - .associated_types_for_impl_traits_in_associated_fn(trait_item_def_id) - .is_empty(); + !self.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id).is_empty() } } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index f2a4a5a4ecf..69c1eb9b345 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -51,7 +51,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(value); + let value = self.erase_and_anonymize_regions(value); debug!(?value); if !value.has_aliases() { @@ -83,7 +83,7 @@ impl<'tcx> TyCtxt<'tcx> { // Erase first before we do the real query -- this keeps the // cache from being too polluted. - let value = self.erase_regions(value); + let value = self.erase_and_anonymize_regions(value); debug!(?value); if !value.has_aliases() { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 59e00f85957..69dcca54f46 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -638,21 +638,7 @@ impl<'tcx> Predicate<'tcx> { let predicate = self.kind(); match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(ClauseKind::Projection(..)) - | PredicateKind::Clause(ClauseKind::HostEffect(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) - | PredicateKind::NormalizesTo(..) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::DynCompatible(..) - | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, + _ => None, } } @@ -660,21 +646,7 @@ impl<'tcx> Predicate<'tcx> { let predicate = self.kind(); match predicate.skip_binder() { PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)), - PredicateKind::Clause(ClauseKind::Trait(..)) - | PredicateKind::Clause(ClauseKind::HostEffect(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) - | PredicateKind::NormalizesTo(..) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::DynCompatible(..) - | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, + _ => None, } } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 9e6f277ef77..d636e8ef31f 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,7 +2,7 @@ use hir::def::Namespace; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use tracing::{debug, instrument, trace}; @@ -396,16 +396,6 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { } } -// This is only used by query descriptions -pub fn describe_as_module(def_id: impl Into<LocalDefId>, tcx: TyCtxt<'_>) -> String { - let def_id = def_id.into(); - if def_id.is_top_level_module() { - "top-level module".to_string() - } else { - format!("module `{}`", tcx.def_path_str(def_id)) - } -} - impl<T> rustc_type_ir::ir_print::IrPrint<T> for TyCtxt<'_> where T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 74caee7336a..fc821ffdaa6 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -13,8 +13,8 @@ use rustc_hir::LangItem; use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefIdMap, DefIdSet, LOCAL_CRATE, ModDefId}; use rustc_hir::definitions::{DefKey, DefPathDataName}; +use rustc_hir::limit::Limit; use rustc_macros::{Lift, extension}; -use rustc_session::Limit; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::{FileNameDisplayPreference, Ident, Symbol, kw, sym}; use rustc_type_ir::{Upcast as _, elaborate}; @@ -1436,8 +1436,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // anonymized regions, but the super projections can still // contain named regions. So we erase and anonymize everything // here to compare the types modulo regions below. - let proj = p.tcx().erase_regions(proj); - let super_proj = p.tcx().erase_regions(super_proj); + let proj = p.tcx().erase_and_anonymize_regions(proj); + let super_proj = p.tcx().erase_and_anonymize_regions(super_proj); proj == super_proj }); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index a7d07adf78f..029586a9c55 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -12,9 +12,9 @@ use rustc_hashes::Hash128; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::limit::Limit; use rustc_index::bit_set::GrowableBitSet; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; -use rustc_session::Limit; use rustc_span::sym; use rustc_type_ir::solve::SizedTraitKind; use smallvec::{SmallVec, smallvec}; @@ -131,10 +131,9 @@ impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash128 { - // We want the type_id be independent of the types free regions, so we - // erase them. The erase_regions() call will also anonymize bound - // regions, which is desirable too. - let ty = self.erase_regions(ty); + // We don't have region information, so we erase all free regions. Equal types + // must have the same `TypeId`, so we must anonymize all bound regions as well. + let ty = self.erase_and_anonymize_regions(ty); self.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); @@ -609,10 +608,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if `def_id` refers to a definition that does not have its own /// type-checking context, i.e. closure, coroutine or inline const. pub fn is_typeck_child(self, def_id: DefId) -> bool { - matches!( - self.def_kind(def_id), - DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody - ) + self.def_kind(def_id).is_typeck_child() } /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). @@ -1309,7 +1305,7 @@ impl<'tcx> Ty<'tcx> { debug_assert!(!typing_env.param_env.has_infer()); let query_ty = tcx .try_normalize_erasing_regions(typing_env, query_ty) - .unwrap_or_else(|_| tcx.erase_regions(query_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(query_ty)); tcx.needs_drop_raw(typing_env.as_query_input(query_ty)) } @@ -1346,7 +1342,7 @@ impl<'tcx> Ty<'tcx> { debug_assert!(!typing_env.has_infer()); let query_ty = tcx .try_normalize_erasing_regions(typing_env, query_ty) - .unwrap_or_else(|_| tcx.erase_regions(query_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(query_ty)); tcx.needs_async_drop_raw(typing_env.as_query_input(query_ty)) } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 3853a804a92..f0c47f257cc 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -212,42 +212,3 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector { } } } - -/// Finds the max universe present -pub struct MaxUniverse { - max_universe: ty::UniverseIndex, -} - -impl MaxUniverse { - pub fn new() -> Self { - MaxUniverse { max_universe: ty::UniverseIndex::ROOT } - } - - pub fn max_universe(self) -> ty::UniverseIndex { - self.max_universe - } -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse { - fn visit_ty(&mut self, t: Ty<'tcx>) { - if let ty::Placeholder(placeholder) = t.kind() { - self.max_universe = self.max_universe.max(placeholder.universe); - } - - t.super_visit_with(self) - } - - fn visit_const(&mut self, c: ty::consts::Const<'tcx>) { - if let ty::ConstKind::Placeholder(placeholder) = c.kind() { - self.max_universe = self.max_universe.max(placeholder.universe); - } - - c.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) { - if let ty::RePlaceholder(placeholder) = r.kind() { - self.max_universe = self.max_universe.max(placeholder.universe); - } - } -} diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 6fc19c82342..e2f09fdcb4b 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -89,7 +89,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { let trait_ref = poly_trait_ref.with_self_ty(tcx, ty); - let trait_ref = tcx.erase_regions(trait_ref); + let trait_ref = tcx.erase_and_anonymize_regions(trait_ref); tcx.vtable_entries(trait_ref) } else { diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index e0cbe8519ed..d40c77d145f 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -64,10 +64,10 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { "`become` outside of functions should have been disallowed by hir_typeck" ) }; - // While the `caller_sig` does have its regions erased, it does not have its - // binders anonymized. We call `erase_regions` once again to anonymize any binders + // While the `caller_sig` does have its free regions erased, it does not have its + // binders anonymized. We call `erase_and_anonymize_regions` once again to anonymize any binders // within the signature, such as in function pointer or `dyn Trait` args. - let caller_sig = self.tcx.erase_regions(caller_sig); + let caller_sig = self.tcx.erase_and_anonymize_regions(caller_sig); let ExprKind::Scope { value, .. } = call.kind else { span_bug!(call.span, "expected scope, found: {call:?}") diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 81b0e21a5f5..0b9bc018a09 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -792,10 +792,9 @@ impl<'tcx> ThirBuildCx<'tcx> { let ty = self.typeck_results.node_type(anon_const.hir_id); let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); - let parent_args = tcx.erase_regions(GenericArgs::identity_for_item( - tcx, - typeck_root_def_id, - )); + let parent_args = tcx.erase_and_anonymize_regions( + GenericArgs::identity_for_item(tcx, typeck_root_def_id), + ); let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }) .args; @@ -831,8 +830,10 @@ impl<'tcx> ThirBuildCx<'tcx> { let ty = self.typeck_results.node_type(anon_const.hir_id); let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); - let parent_args = - tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id)); + let parent_args = tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item( + tcx, + typeck_root_def_id, + )); let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args; ExprKind::ConstBlock { did, args } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d46c4678bcf..6316ccf1b8c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -105,9 +105,11 @@ impl<'tcx> ConstToPat<'tcx> { // // FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself // instead of having this logic here - let typing_env = - self.tcx.erase_regions(self.typing_env).with_post_analysis_normalized(self.tcx); - let uv = self.tcx.erase_regions(uv); + let typing_env = self + .tcx + .erase_and_anonymize_regions(self.typing_env) + .with_post_analysis_normalized(self.tcx); + let uv = self.tcx.erase_and_anonymize_regions(uv); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 9a00831dc01..bf5ec8f459e 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -891,7 +891,7 @@ pub fn iter_fields<'tcx>( let field_ty = f_def.ty(tcx, args); let field_ty = tcx .try_normalize_erasing_regions(typing_env, field_ty) - .unwrap_or_else(|_| tcx.erase_regions(field_ty)); + .unwrap_or_else(|_| tcx.erase_and_anonymize_regions(field_ty)); f(variant, f_index.into(), field_ty); } } diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 92ee80eaa35..be4f84d64d0 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -32,8 +32,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); // Not erasing this causes `Free Regions` errors in validator, // when rval is `ReStatic`. - rval_ty = self.tcx.erase_regions(rval_ty); - place_ty = self.tcx.erase_regions(place_ty); + rval_ty = self.tcx.erase_and_anonymize_regions(rval_ty); + place_ty = self.tcx.erase_and_anonymize_regions(place_ty); if place_ty != rval_ty { let temp = self .patcher diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f867c130efb..bf6aa800d20 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1644,6 +1644,11 @@ impl<'tcx> VnState<'_, 'tcx> { let place = Place { local, projection: self.tcx.mk_place_elems(projection.as_slice()) }; return Some(place); + } else if projection.last() == Some(&PlaceElem::Deref) { + // `Deref` can only be the first projection in a place. + // If we are here, we failed to find a local, and we already have a `Deref`. + // Trying to add projections will only result in an ill-formed place. + return None; } else if let Value::Projection(pointer, proj) = *self.get(index) && (allow_complex_projection || proj.is_stable_offset()) && let Some(proj) = self.try_as_place_elem(self.ty(index), proj, loc) diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 7f9234d1dc8..25a9baffe58 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -2,9 +2,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordSet; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::limit::Limit; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt, TypeVisitableExt}; -use rustc_session::Limit; use rustc_span::sym; use tracing::{instrument, trace}; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 462ddfa3dd3..9ea2eb4f25d 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -875,7 +875,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { let mut promoted_operand = |ty, span| { promoted.span = span; promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span); - let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def)); + let args = + tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def)); let uneval = mir::UnevaluatedConst { def, args, promoted: Some(next_promoted_index) }; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index cffeb6f9807..378d71cb1fc 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -217,6 +217,7 @@ use rustc_hir::attrs::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::lang_items::LangItem; +use rustc_hir::limit::Limit; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{CollectionMode, InstantiationMode, MonoItem}; @@ -231,7 +232,6 @@ use rustc_middle::ty::{ }; use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; -use rustc_session::Limit; use rustc_session::config::{DebugInfo, EntryFnType}; use rustc_span::source_map::{Spanned, dummy_spanned, respan}; use rustc_span::{DUMMY_SP, Span}; @@ -1558,7 +1558,7 @@ impl<'v> RootCollector<'_, 'v> { ty::Closure(def_id, args) | ty::Coroutine(def_id, args) | ty::CoroutineClosure(def_id, args) => { - Instance::new_raw(def_id, self.tcx.erase_regions(args)) + Instance::new_raw(def_id, self.tcx.erase_and_anonymize_regions(args)) } _ => unreachable!(), }; diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs index 7251ef478c6..0adf1b089b5 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs @@ -1,10 +1,10 @@ use rustc_abi::Size; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; +use rustc_hir::limit::Limit; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, traversal}; use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable}; -use rustc_session::Limit; use rustc_session::lint::builtin::LARGE_ASSIGNMENTS; use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span, sym}; diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index da05c49756f..a8f2b4e8db6 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -2,9 +2,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ - self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalTyVarKind, CanonicalVarKind, - Flags, InferCtxtLike, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, + self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, Flags, InferCtxtLike, + Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use crate::delegate::SolverDelegate; @@ -68,6 +67,13 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> { variables: &'a mut Vec<I::GenericArg>, var_kinds: Vec<CanonicalVarKind<I>>, variable_lookup_table: HashMap<I::GenericArg, usize>, + /// Maps each `sub_unification_table_root_var` to the index of the first + /// variable which used it. + /// + /// This means in case two type variables have the same sub relations root, + /// we set the `sub_root` of the second variable to the position of the first. + /// Otherwise the `sub_root` of each type variable is just its own position. + sub_root_lookup_table: HashMap<ty::TyVid, usize>, binder_index: ty::DebruijnIndex, /// We only use the debruijn index during lookup. We don't need to @@ -89,6 +95,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variables, variable_lookup_table: Default::default(), + sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), binder_index: ty::INNERMOST, @@ -133,6 +140,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variables: &mut variables, variable_lookup_table: Default::default(), + sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), binder_index: ty::INNERMOST, @@ -140,6 +148,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { }; let param_env = param_env.fold_with(&mut env_canonicalizer); debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); CanonicalParamEnvCacheEntry { param_env, variable_lookup_table: env_canonicalizer.variable_lookup_table, @@ -165,6 +174,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variables, variable_lookup_table: Default::default(), + sub_root_lookup_table: Default::default(), var_kinds: Vec::new(), binder_index: ty::INNERMOST, @@ -172,6 +182,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { }; let param_env = param_env.fold_with(&mut env_canonicalizer); debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) } } @@ -200,6 +211,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { variables, variable_lookup_table, + sub_root_lookup_table: Default::default(), var_kinds, binder_index: ty::INNERMOST, @@ -266,6 +278,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { ty::BoundVar::from(idx) } + fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar { + let root_vid = self.delegate.sub_unification_table_root_var(vid); + let idx = + *self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len()); + ty::BoundVar::from(idx) + } + fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) { let mut var_kinds = self.var_kinds; // See the rustc-dev-guide section about how we deal with universes @@ -313,18 +332,15 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { "ty vid should have been resolved fully before canonicalization" ); - match self.canonicalize_mode { - CanonicalizeMode::Input { .. } => CanonicalVarKind::Ty( - CanonicalTyVarKind::General(ty::UniverseIndex::ROOT), - ), - CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General( - self.delegate.universe_of_ty(vid).unwrap_or_else(|| { - panic!("ty var should have been resolved: {t:?}") - }), - )) - } - } + let sub_root = self.get_or_insert_sub_root(vid); + let ui = match self.canonicalize_mode { + CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT, + CanonicalizeMode::Response { .. } => self + .delegate + .universe_of_ty(vid) + .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")), + }; + CanonicalVarKind::Ty { ui, sub_root } } ty::IntVar(vid) => { debug_assert_eq!( @@ -332,7 +348,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { t, "ty vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + CanonicalVarKind::Int } ty::FloatVar(vid) => { debug_assert_eq!( @@ -340,7 +356,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { t, "ty vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Ty(CanonicalTyVarKind::Float) + CanonicalVarKind::Float } ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { panic!("fresh vars not expected in canonicalization") diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index 79219b34e29..b949deb1192 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -435,7 +435,21 @@ where } } ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Closure(did, ..) | ty::CoroutineClosure(did, ..) | ty::Coroutine(did, ..) => { + ty::Closure(did, ..) => { + if self.def_id_is_local(did) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::CoroutineClosure(did, ..) => { + if self.def_id_is_local(did) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } + ty::Coroutine(did, ..) => { if self.def_id_is_local(did) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) } else { diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 7b932010d49..41c2e5f60ec 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -57,12 +57,14 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized { where V: TypeFoldable<Self::Interner>; - fn instantiate_canonical_var_with_infer( + fn instantiate_canonical_var( &self, kind: ty::CanonicalVarKind<Self::Interner>, span: <Self::Interner as Interner>::Span, + var_values: &[<Self::Interner as Interner>::GenericArg], universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> <Self::Interner as Interner>::GenericArg; + fn add_item_bounds_for_hidden_type( &self, def_id: <Self::Interner as Interner>::DefId, @@ -76,7 +78,7 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized { &self, goal_trait_ref: ty::TraitRef<Self::Interner>, trait_assoc_def_id: <Self::Interner as Interner>::DefId, - impl_def_id: <Self::Interner as Interner>::DefId, + impl_def_id: <Self::Interner as Interner>::ImplId, ) -> Result< Option<<Self::Interner as Interner>::DefId>, <Self::Interner as Interner>::ErrorGuaranteed, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index be7e4dd4cda..fb777496e31 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem; use rustc_type_ir::search_graph::CandidateHeadUsages; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{ - self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate, + self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, + elaborate, }; use tracing::{debug, instrument}; @@ -186,7 +187,8 @@ where fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, + then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution>; /// If the predicate contained an error, we want to avoid emitting unnecessary trait @@ -365,6 +367,15 @@ pub(super) enum AssembleCandidatesFrom { EnvAndBounds, } +impl AssembleCandidatesFrom { + fn should_assemble_impl_candidates(&self) -> bool { + match self { + AssembleCandidatesFrom::All => true, + AssembleCandidatesFrom::EnvAndBounds => false, + } + } +} + /// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv` /// candidates. This is then used to ignore their head usages in case there's another /// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is @@ -397,14 +408,15 @@ where return (candidates, failed_candidate_info); }; + let goal: Goal<I, G> = goal + .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty)); + if normalized_self_ty.is_ty_var() { debug!("self type has been normalized to infer"); - candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity)); + self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates); return (candidates, failed_candidate_info); } - let goal: Goal<I, G> = goal - .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty)); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -484,8 +496,9 @@ where if cx.impl_is_default(impl_def_id) { return; } - - match G::consider_impl_candidate(self, goal, impl_def_id) { + match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { + ecx.evaluate_added_goals_and_make_canonical_response(certainty) + }) { Ok(candidate) => candidates.push(candidate), Err(NoSolution) => (), } @@ -943,6 +956,116 @@ where } } + /// If the self type is the hidden type of an opaque, try to assemble + /// candidates for it by consider its item bounds and by using blanket + /// impls. This is used to incompletely guide type inference when handling + /// non-defining uses in the defining scope. + /// + /// We otherwise just fail fail with ambiguity. Even if we're using an + /// opaque type item bound or a blank impls, we still force its certainty + /// to be `Maybe` so that we properly prove this goal later. + /// + /// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/182> + /// for why this is necessary. + fn try_assemble_bounds_via_registered_opaques<G: GoalKind<D>>( + &mut self, + goal: Goal<I, G>, + assemble_from: AssembleCandidatesFrom, + candidates: &mut Vec<Candidate<I>>, + ) { + let self_ty = goal.predicate.self_ty(); + // If the self type is sub unified with any opaque type, we + // also look at blanket impls for it. + let mut assemble_blanket_impls = false; + for alias_ty in self.opaques_with_sub_unified_hidden_type(self_ty) { + assemble_blanket_impls = true; + debug!("self ty is sub unified with {alias_ty:?}"); + + struct ReplaceOpaque<I: Interner> { + cx: I, + alias_ty: ty::AliasTy<I>, + self_ty: I::Ty, + } + impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> { + fn cx(&self) -> I { + self.cx + } + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() { + if alias_ty == self.alias_ty { + return self.self_ty; + } + } + ty.super_fold_with(self) + } + } + + // We look at all item-bounds of the opaque, replacing the + // opaque with the current self type before considering + // them as a candidate. Imagine e've got `?x: Trait<?y>` + // and `?x` has been sub-unified with the hidden type of + // `impl Trait<u32>`, We take the item bound `opaque: Trait<u32>` + // and replace all occurrences of `opaque` with `?x`. This results + // in a `?x: Trait<u32>` alias-bound candidate. + for item_bound in self + .cx() + .item_self_bounds(alias_ty.def_id) + .iter_instantiated(self.cx(), alias_ty.args) + { + let assumption = + item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty }); + candidates.extend(G::probe_and_match_goal_against_assumption( + self, + CandidateSource::AliasBound, + goal, + assumption, + |ecx| { + // We want to reprove this goal once we've inferred the + // hidden type, so we force the certainty to `Maybe`. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + }, + )); + } + } + + // We also need to consider blanket impls for not-yet-defined opaque types. + // + // See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example. + if assemble_blanket_impls && assemble_from.should_assemble_impl_candidates() { + let cx = self.cx(); + cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| { + // For every `default impl`, there's always a non-default `impl` + // that will *also* apply. There's no reason to register a candidate + // for this impl, since it is *not* proof that the trait goal holds. + if cx.impl_is_default(impl_def_id) { + return; + } + + match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| { + if ecx.shallow_resolve(self_ty).is_ty_var() { + // We force the certainty of impl candidates to be `Maybe`. + let certainty = certainty.and(Certainty::AMBIGUOUS); + ecx.evaluate_added_goals_and_make_canonical_response(certainty) + } else { + // We don't want to use impls if they constrain the opaque. + // + // FIXME(trait-system-refactor-initiative#229): This isn't + // perfect yet as it still allows us to incorrectly constrain + // other inference variables. + Err(NoSolution) + } + }) { + Ok(candidate) => candidates.push(candidate), + Err(NoSolution) => (), + } + }); + } + + if candidates.is_empty() { + candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity)); + } + } + /// Assemble and merge candidates for goals which are related to an underlying trait /// goal. Right now, this is normalizes-to and host effect goals. /// diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 7c5940828da..f6eab286ba7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -605,7 +605,7 @@ fn coroutine_closure_to_certain_coroutine<I: Interner>( cx: I, goal_kind: ty::ClosureKind, goal_region: I::Region, - def_id: I::DefId, + def_id: I::CoroutineClosureId, args: ty::CoroutineClosureArgs<I>, sig: ty::CoroutineClosureSignature<I>, ) -> I::Ty { @@ -629,7 +629,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>( cx: I, goal_kind: ty::ClosureKind, goal_region: I::Region, - def_id: I::DefId, + def_id: I::CoroutineClosureId, args: ty::CoroutineClosureArgs<I>, sig: ty::CoroutineClosureSignature<I>, ) -> I::Ty { @@ -664,7 +664,7 @@ fn coroutine_closure_to_ambiguous_coroutine<I: Interner>( pub(in crate::solve) fn extract_fn_def_from_const_callable<I: Interner>( cx: I, self_ty: I::Ty, -) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::DefId, I::GenericArgs), NoSolution> { +) -> Result<(ty::Binder<I, (I::FnInputTys, I::Ty)>, I::FunctionId, I::GenericArgs), NoSolution> { match self_ty.kind() { ty::FnDef(def_id, args) => { let sig = cx.fn_sig(def_id); diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 229345065b1..cb72c1cd92b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -123,7 +123,8 @@ where fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, Self>, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, + then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { let cx = ecx.cx(); @@ -152,20 +153,20 @@ where } ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { - let impl_args = ecx.fresh_args_for_item(impl_def_id); + let impl_args = ecx.fresh_args_for_item(impl_def_id.into()); ecx.record_impl_args(impl_args); let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = cx - .predicates_of(impl_def_id) + .predicates_of(impl_def_id.into()) .iter_instantiated(cx, impl_args) .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); // For this impl to be `const`, we need to check its `[const]` bounds too. let const_conditions = cx - .const_conditions(impl_def_id) + .const_conditions(impl_def_id.into()) .iter_instantiated(cx, impl_args) .map(|bound_trait_ref| { goal.with( @@ -175,7 +176,7 @@ where }); ecx.add_goals(GoalSource::ImplWhereBound, const_conditions); - ecx.evaluate_added_goals_and_make_canonical_response(certainty) + then(ecx, certainty) }) } @@ -240,7 +241,7 @@ where ty::TraitRef::new(cx, cx.require_trait_lang_item(SolverTraitLangItem::Sized), [output]) }); let requirements = cx - .const_conditions(def_id) + .const_conditions(def_id.into()) .iter_instantiated(cx, args) .map(|trait_ref| { ( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 6f9f4067384..169832ca5fb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -16,7 +16,8 @@ use rustc_type_ir::data_structures::HashSet; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, + self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, + TypeFoldable, }; use tracing::{debug, instrument, trace}; @@ -336,7 +337,16 @@ where { match result_value.kind() { ty::GenericArgKind::Type(t) => { - if let ty::Bound(debruijn, b) = t.kind() { + // We disable the instantiation guess for inference variables + // and only use it for placeholders. We need to handle the + // `sub_root` of type inference variables which would make this + // more involved. They are also a lot rarer than region variables. + if let ty::Bound(debruijn, b) = t.kind() + && !matches!( + response.variables.get(b.var().as_usize()).unwrap(), + CanonicalVarKind::Ty { .. } + ) + { assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var()] = Some(*original_value); } @@ -355,39 +365,33 @@ where } } } - - let var_values = delegate.cx().mk_args_from_iter( - response.variables.iter().enumerate().map(|(index, var_kind)| { - if var_kind.universe() != ty::UniverseIndex::ROOT { - // A variable from inside a binder of the query. While ideally these shouldn't - // exist at all (see the FIXME at the start of this method), we have to deal with - // them for now. - delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| { - prev_universe + idx.index() - }) - } else if var_kind.is_existential() { - // As an optimization we sometimes avoid creating a new inference variable here. - // - // All new inference variables we create start out in the current universe of the caller. - // This is conceptually wrong as these inference variables would be able to name - // more placeholders then they should be able to. However the inference variables have - // to "come from somewhere", so by equating them with the original values of the caller - // later on, we pull them down into their correct universe again. - if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] { - v - } else { - delegate - .instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe) - } + CanonicalVarValues::instantiate(delegate.cx(), response.variables, |var_values, kind| { + if kind.universe() != ty::UniverseIndex::ROOT { + // A variable from inside a binder of the query. While ideally these shouldn't + // exist at all (see the FIXME at the start of this method), we have to deal with + // them for now. + delegate.instantiate_canonical_var(kind, span, &var_values, |idx| { + prev_universe + idx.index() + }) + } else if kind.is_existential() { + // As an optimization we sometimes avoid creating a new inference variable here. + // + // All new inference variables we create start out in the current universe of the caller. + // This is conceptually wrong as these inference variables would be able to name + // more placeholders then they should be able to. However the inference variables have + // to "come from somewhere", so by equating them with the original values of the caller + // later on, we pull them down into their correct universe again. + if let Some(v) = opt_values[ty::BoundVar::from_usize(var_values.len())] { + v } else { - // For placeholders which were already part of the input, we simply map this - // universal bound variable back the placeholder of the input. - original_values[var_kind.expect_placeholder_index()] + delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe) } - }), - ); - - CanonicalVarValues { var_values } + } else { + // For placeholders which were already part of the input, we simply map this + // universal bound variable back the placeholder of the input. + original_values[kind.expect_placeholder_index()] + } + }) } /// Unify the `original_values` with the `var_values` returned by the canonical query.. diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 443aebbdb4d..3e3a5246f3d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -407,20 +407,21 @@ where // If we have run this goal before, and it was stalled, check that any of the goal's // args have changed. Otherwise, we don't need to re-run the goal because it'll remain // stalled, since it'll canonicalize the same way and evaluation is pure. - if let Some(stalled_on) = stalled_on - && !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) - && !self - .delegate - .opaque_types_storage_num_entries() - .needs_reevaluation(stalled_on.num_opaques) + if let Some(GoalStalledOn { num_opaques, ref stalled_vars, ref sub_roots, stalled_cause }) = + stalled_on + && !stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value)) + && !sub_roots + .iter() + .any(|&vid| self.delegate.sub_unification_table_root_var(vid) != vid) + && !self.delegate.opaque_types_storage_num_entries().needs_reevaluation(num_opaques) { return Ok(( NestedNormalizationGoals::empty(), GoalEvaluation { goal, - certainty: Certainty::Maybe(stalled_on.stalled_cause), + certainty: Certainty::Maybe(stalled_cause), has_changed: HasChanged::No, - stalled_on: Some(stalled_on), + stalled_on, }, )); } @@ -476,16 +477,6 @@ where HasChanged::No => { let mut stalled_vars = orig_values; - // Remove the canonicalized universal vars, since we only care about stalled existentials. - stalled_vars.retain(|arg| match arg.kind() { - ty::GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Infer(_)), - ty::GenericArgKind::Const(ct) => { - matches!(ct.kind(), ty::ConstKind::Infer(_)) - } - // Lifetimes can never stall goals. - ty::GenericArgKind::Lifetime(_) => false, - }); - // Remove the unconstrained RHS arg, which is expected to have changed. if let Some(normalizes_to) = goal.predicate.as_normalizes_to() { let normalizes_to = normalizes_to.skip_binder(); @@ -497,6 +488,27 @@ where stalled_vars.swap_remove(idx); } + // Remove the canonicalized universal vars, since we only care about stalled existentials. + let mut sub_roots = Vec::new(); + stalled_vars.retain(|arg| match arg.kind() { + // Lifetimes can never stall goals. + ty::GenericArgKind::Lifetime(_) => false, + ty::GenericArgKind::Type(ty) => match ty.kind() { + ty::Infer(ty::TyVar(vid)) => { + sub_roots.push(self.delegate.sub_unification_table_root_var(vid)); + true + } + ty::Infer(_) => true, + ty::Param(_) | ty::Placeholder(_) => false, + _ => unreachable!("unexpected orig_value: {ty:?}"), + }, + ty::GenericArgKind::Const(ct) => match ct.kind() { + ty::ConstKind::Infer(_) => true, + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => false, + _ => unreachable!("unexpected orig_value: {ct:?}"), + }, + }); + Some(GoalStalledOn { num_opaques: canonical_goal .canonical @@ -505,6 +517,7 @@ where .opaque_types .len(), stalled_vars, + sub_roots, stalled_cause, }) } @@ -900,6 +913,10 @@ where && goal.param_env.visit_with(&mut visitor).is_continue() } + pub(super) fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { + self.delegate.sub_unify_ty_vids_raw(a, b) + } + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq<T: Relate<I>>( &mut self, @@ -1043,6 +1060,10 @@ where self.delegate.resolve_vars_if_possible(value) } + pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty { + self.delegate.shallow_resolve(ty) + } + pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region { if let ty::ReVar(vid) = r.kind() { self.delegate.opportunistic_resolve_lt_var(vid) @@ -1092,7 +1113,7 @@ where &self, goal_trait_ref: ty::TraitRef<I>, trait_assoc_def_id: I::DefId, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, ) -> Result<Option<I::DefId>, I::ErrorGuaranteed> { self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id) } @@ -1159,6 +1180,33 @@ where ) -> bool { may_use_unstable_feature(&**self.delegate, param_env, symbol) } + + pub(crate) fn opaques_with_sub_unified_hidden_type( + &self, + self_ty: I::Ty, + ) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> { + let delegate = self.delegate; + delegate + .clone_opaque_types_lookup_table() + .into_iter() + .chain(delegate.clone_duplicate_opaque_types()) + .filter_map(move |(key, hidden_ty)| { + if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() { + if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() { + if delegate.sub_unification_table_root_var(self_vid) + == delegate.sub_unification_table_root_var(hidden_vid) + { + return Some(ty::AliasTy::new_from_args( + delegate.cx(), + key.def_id.into(), + key.args, + )); + } + } + } + None + }) + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 85f9d852d95..cd27c9c26c1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -24,7 +24,7 @@ mod trait_goals; use derive_where::derive_where; use rustc_type_ir::inherent::*; pub use rustc_type_ir::solve::*; -use rustc_type_ir::{self as ty, Interner, TypingMode}; +use rustc_type_ir::{self as ty, Interner, TyVid, TypingMode}; use tracing::instrument; pub use self::eval_ctxt::{ @@ -119,11 +119,15 @@ where #[instrument(level = "trace", skip(self))] fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> { - if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) - } else { - self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + match (goal.predicate.a.kind(), goal.predicate.b.kind()) { + (ty::Infer(ty::TyVar(a_vid)), ty::Infer(ty::TyVar(b_vid))) => { + self.sub_unify_ty_vids_raw(a_vid, b_vid); + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } + _ => { + self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } } } @@ -422,6 +426,7 @@ pub struct GoalEvaluation<I: Interner> { pub struct GoalStalledOn<I: Interner> { pub num_opaques: usize, pub stalled_vars: Vec<I::GenericArg>, + pub sub_roots: Vec<TyVid>, /// The cause that will be returned on subsequent evaluations if this goal remains stalled. pub stalled_cause: MaybeCause, } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index cfdf2007391..54b92ebac1d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -5,7 +5,7 @@ mod opaque_types; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; -use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem}; +use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _}; use tracing::instrument; @@ -193,7 +193,8 @@ where fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, NormalizesTo<I>>, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, + then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { let cx = ecx.cx(); @@ -217,13 +218,13 @@ where }; ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { - let impl_args = ecx.fresh_args_for_item(impl_def_id); + let impl_args = ecx.fresh_args_for_item(impl_def_id.into()); let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; let where_clause_bounds = cx - .predicates_of(impl_def_id) + .predicates_of(impl_def_id.into()) .iter_instantiated(cx, impl_args) .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); @@ -314,8 +315,7 @@ where // nested goal for consistency. ty::TypingMode::Coherence => { ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous)); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + return then(ecx, Certainty::Yes); } ty::TypingMode::Analysis { .. } | ty::TypingMode::Borrowck { .. } @@ -325,8 +325,7 @@ where goal, goal.predicate.alias, ); - return ecx - .evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + return then(ecx, Certainty::Yes); } } } else { @@ -824,10 +823,10 @@ where // coroutine yield ty `Poll<Option<I>>`. let wrapped_expected_ty = Ty::new_adt( cx, - cx.adt_def(cx.require_lang_item(SolverLangItem::Poll)), + cx.adt_def(cx.require_adt_lang_item(SolverAdtLangItem::Poll)), cx.mk_args(&[Ty::new_adt( cx, - cx.adt_def(cx.require_lang_item(SolverLangItem::Option)), + cx.adt_def(cx.require_adt_lang_item(SolverAdtLangItem::Option)), cx.mk_args(&[expected_ty.into()]), ) .into()]), @@ -979,7 +978,7 @@ where fn translate_args( &mut self, goal: Goal<I, ty::NormalizesTo<I>>, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, impl_args: I::GenericArgs, impl_trait_ref: rustc_type_ir::TraitRef<I>, target_container_def_id: I::DefId, @@ -988,14 +987,15 @@ where Ok(if target_container_def_id == impl_trait_ref.def_id.into() { // Default value from the trait definition. No need to rebase. goal.predicate.alias.args - } else if target_container_def_id == impl_def_id { + } else if target_container_def_id == impl_def_id.into() { // Same impl, no need to fully translate, just a rebase from // the trait is sufficient. goal.predicate.alias.args.rebase_onto(cx, impl_trait_ref.def_id.into(), impl_args) } else { let target_args = self.fresh_args_for_item(target_container_def_id); - let target_trait_ref = - cx.impl_trait_ref(target_container_def_id).instantiate(cx, target_args); + let target_trait_ref = cx + .impl_trait_ref(target_container_def_id.try_into().unwrap()) + .instantiate(cx, target_args); // Relate source impl to target impl by equating trait refs. self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; // Also add predicates since they may be needed to constrain the diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index cdcfebf2909..a69e867289c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -54,7 +54,8 @@ where fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal<I, TraitPredicate<I>>, - impl_def_id: I::DefId, + impl_def_id: I::ImplId, + then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { let cx = ecx.cx(); @@ -91,13 +92,13 @@ where }; ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { - let impl_args = ecx.fresh_args_for_item(impl_def_id); + let impl_args = ecx.fresh_args_for_item(impl_def_id.into()); ecx.record_impl_args(impl_args); let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = cx - .predicates_of(impl_def_id) + .predicates_of(impl_def_id.into()) .iter_instantiated(cx, impl_args) .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); @@ -112,7 +113,7 @@ where .map(|pred| goal.with(cx, pred)), ); - ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) + then(ecx, maximal_certainty) }) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 77dd313d9b8..72cd75f6d89 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -479,9 +479,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` - .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 797d4830c2f..00ca5acd84d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1017,10 +1017,6 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[label] pub span: Span, pub suffix: Symbol, - #[help(parse_tuple_exception_line_1)] - #[help(parse_tuple_exception_line_2)] - #[help(parse_tuple_exception_line_3)] - pub exception: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f5f081efc49..51019db7c00 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -45,7 +45,7 @@ pub(crate) struct UnmatchedDelim { } /// Which tokens should be stripped before lexing the tokens. -pub(crate) enum StripTokens { +pub enum StripTokens { /// Strip both shebang and frontmatter. ShebangAndFrontmatter, /// Strip the shebang but not frontmatter. diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index d8792d7af4c..88b67d792de 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -54,29 +54,18 @@ pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T { } } -/// Creates a new parser from a source string. On failure, the errors must be consumed via -/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are -/// dropped. -pub fn new_parser_from_source_str( - psess: &ParseSess, - name: FileName, - source: String, -) -> Result<Parser<'_>, Vec<Diag<'_>>> { - let source_file = psess.source_map().new_source_file(name, source); - new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter) -} - -/// Creates a new parser from a simple (no shebang, no frontmatter) source string. +/// Creates a new parser from a source string. /// /// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`, /// etc., otherwise a panic will occur when they are dropped. -pub fn new_parser_from_simple_source_str( +pub fn new_parser_from_source_str( psess: &ParseSess, name: FileName, source: String, + strip_tokens: StripTokens, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let source_file = psess.source_map().new_source_file(name, source); - new_parser_from_source_file(psess, source_file, StripTokens::Nothing) + new_parser_from_source_file(psess, source_file, strip_tokens) } /// Creates a new parser from a filename. On failure, the errors must be consumed via @@ -87,6 +76,7 @@ pub fn new_parser_from_simple_source_str( pub fn new_parser_from_file<'a>( psess: &'a ParseSess, path: &Path, + strip_tokens: StripTokens, sp: Option<Span>, ) -> Result<Parser<'a>, Vec<Diag<'a>>> { let sm = psess.source_map(); @@ -110,7 +100,7 @@ pub fn new_parser_from_file<'a>( } err.emit(); }); - new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter) + new_parser_from_source_file(psess, source_file, strip_tokens) } pub fn utf8_error<E: EmissionGuarantee>( @@ -172,6 +162,9 @@ fn new_parser_from_source_file( Ok(parser) } +/// Given a source string, produces a sequence of token trees. +/// +/// NOTE: This only strips shebangs, not frontmatter! pub fn source_str_to_stream( psess: &ParseSess, name: FileName, @@ -179,13 +172,16 @@ pub fn source_str_to_stream( override_span: Option<Span>, ) -> Result<TokenStream, Vec<Diag<'_>>> { let source_file = psess.source_map().new_source_file(name, source); - // used mainly for `proc_macro` and the likes, not for our parsing purposes, so don't parse - // frontmatters as frontmatters, but for compatibility reason still strip the shebang + // FIXME(frontmatter): Consider stripping frontmatter in a future edition. We can't strip them + // in the current edition since that would be breaking. + // See also <https://github.com/rust-lang/rust/issues/145520>. + // Alternatively, stop stripping shebangs here, too, if T-lang and crater approve. source_file_to_stream(psess, source_file, override_span, StripTokens::Shebang) } -/// Given a source file, produces a sequence of token trees. Returns any buffered errors from -/// parsing the token stream. +/// Given a source file, produces a sequence of token trees. +/// +/// Returns any buffered errors from parsing the token stream. fn source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Arc<SourceFile>, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4c02547357e..81a5d48d94e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1163,7 +1163,10 @@ impl<'a> Parser<'a> { suffix, }) => { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(current.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: current.span, + suffix, + }); } match self.break_up_float(symbol, current.span) { // 1e2 @@ -1239,7 +1242,8 @@ impl<'a> Parser<'a> { suffix: Option<Symbol>, ) -> Box<Expr> { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(ident_span, suffix); + self.dcx() + .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix }); } self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span))) } @@ -2225,24 +2229,6 @@ impl<'a> Parser<'a> { }) } - pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { - if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: true, - }); - } else { - self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: false, - }); - } - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box<Expr>> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3bbca622975..ed4069dae93 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1335,7 +1335,10 @@ impl<'a> Parser<'a> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(self.token.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: self.token.span, + suffix, + }); } self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a6e7266e71b..e645fb47b9e 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -22,6 +22,7 @@ use rustc_span::{ }; use termcolor::WriteColor; +use crate::lexer::StripTokens; use crate::parser::{ForceCollect, Parser}; use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; @@ -35,6 +36,7 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { psess, PathBuf::from("bogofile").into(), source_str, + StripTokens::Nothing, )) } @@ -2240,7 +2242,7 @@ fn parse_item_from_source_str( source: String, psess: &ParseSess, ) -> PResult<'_, Option<Box<ast::Item>>> { - unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing)) .parse_item(ForceCollect::No) } @@ -2520,7 +2522,8 @@ fn ttdelim_span() { source: String, psess: &ParseSess, ) -> PResult<'_, Box<ast::Expr>> { - unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing)) + .parse_expr() } create_default_session_globals_then(|| { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6168647183f..23aaafac934 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -92,10 +92,10 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { } fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { - // `Not`, `Tilde` & `Const` are deliberately not part of this list to + // `!`, `const`, `[`, `async` are deliberately not part of this list to // contain the number of potential regressions esp. in MBE code. - // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`. - // `Not` would regress `dyn!(...)` macro calls in Rust 2015. + // `const` and `[` would regress UI test `macro-dyn-const-2015.rs`. + // `!` would regress `dyn!(...)` macro calls in Rust 2015. t.is_path_start() || t.is_lifetime() || t == &TokenKind::Question @@ -1015,12 +1015,18 @@ impl<'a> Parser<'a> { || self.check(exp!(Tilde)) || self.check_keyword(exp!(For)) || self.check(exp!(OpenParen)) - || self.check(exp!(OpenBracket)) + || self.can_begin_maybe_const_bound() || self.check_keyword(exp!(Const)) || self.check_keyword(exp!(Async)) || self.check_keyword(exp!(Use)) } + fn can_begin_maybe_const_bound(&mut self) -> bool { + self.check(exp!(OpenBracket)) + && self.look_ahead(1, |t| t.is_keyword(kw::Const)) + && self.look_ahead(2, |t| *t == token::CloseBracket) + } + /// Parse a bound. /// /// ```ebnf @@ -1199,10 +1205,7 @@ impl<'a> Parser<'a> { let span = tilde.to(self.prev_token.span); self.psess.gated_spans.gate(sym::const_trait_impl, span); BoundConstness::Maybe(span) - } else if self.check(exp!(OpenBracket)) - && self.look_ahead(1, |t| t.is_keyword(kw::Const)) - && self.look_ahead(2, |t| *t == token::CloseBracket) - { + } else if self.can_begin_maybe_const_bound() { let start = self.token.span; self.bump(); self.expect_keyword(exp!(Const)).unwrap(); diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index afd08319738..75537caa894 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -75,7 +75,7 @@ passes_const_stable_not_stable = .label = attribute specified here passes_custom_mir_incompatible_dialect_and_phase = - The {$dialect} dialect is not compatible with the {$phase} phase + the {$dialect} dialect is not compatible with the {$phase} phase .dialect_span = this dialect... .phase_span = ... is not compatible with this phase @@ -501,6 +501,10 @@ passes_repr_align_should_be_align = `#[repr(align(...))]` is not supported on {$item} .help = use `#[rustc_align(...)]` instead +passes_repr_align_should_be_align_static = + `#[repr(align(...))]` is not supported on {$item} + .help = use `#[rustc_align_static(...)]` instead + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2cd4830b5d9..2562d2e0b83 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -270,6 +270,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Linkage(..) | AttributeKind::MustUse { .. } | AttributeKind::CrateName { .. } + | AttributeKind::RecursionLimit { .. } + | AttributeKind::MoveSizeLimit { .. } + | AttributeKind::TypeLengthLimit { .. } + | AttributeKind::PatternComplexityLimit { .. } + | AttributeKind::NoCore { .. } + | AttributeKind::NoStd { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -1602,12 +1608,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ReprAttr::ReprAlign(align) => { match target { Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) => { + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { self.dcx().emit_err(errors::ReprAlignShouldBeAlign { span: *repr_span, item: target.plural_name(), }); } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { hint_span: *repr_span, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index fc33405d455..3c2c9683a4d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -373,31 +373,27 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// Automatically generated items marked with `rustc_trivial_field_reads` /// will be ignored for the purposes of dead code analysis (see PR #85200 /// for discussion). - fn should_ignore_item(&mut self, def_id: DefId) -> bool { - if let Some(impl_of) = self.tcx.trait_impl_of_assoc(def_id) { - if !self.tcx.is_automatically_derived(impl_of) { - return false; - } - - if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) - && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) + fn should_ignore_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) -> bool { + if let hir::ImplItemImplKind::Trait { .. } = impl_item.impl_kind + && let impl_of = self.tcx.parent(impl_item.owner_id.to_def_id()) + && self.tcx.is_automatically_derived(impl_of) + && let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity() + && self.tcx.has_attr(trait_ref.def_id, sym::rustc_trivial_field_reads) + { + if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() + && let Some(adt_def_id) = adt_def.did().as_local() { - let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap().instantiate_identity(); - if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() - && let Some(adt_def_id) = adt_def.did().as_local() - { - self.ignored_derived_traits.entry(adt_def_id).or_default().insert(trait_of); - } - return true; + self.ignored_derived_traits.entry(adt_def_id).or_default().insert(trait_ref.def_id); } + return true; } false } fn visit_node(&mut self, node: Node<'tcx>) { - if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node - && self.should_ignore_item(owner_id.to_def_id()) + if let Node::ImplItem(impl_item) = node + && self.should_ignore_impl_item(impl_item) { return; } @@ -439,7 +435,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } Node::ImplItem(impl_item) => { let item = self.tcx.local_parent(impl_item.owner_id.def_id); - if self.tcx.impl_trait_ref(item).is_none() { + if let hir::ImplItemImplKind::Inherent { .. } = impl_item.impl_kind { //// If it's a type whose items are live, then it's live, too. //// This is done to handle the case where, for example, the static //// method of a private type is used, but the type itself is never @@ -484,13 +480,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn check_impl_or_impl_item_live(&mut self, local_def_id: LocalDefId) -> bool { let (impl_block_id, trait_def_id) = match self.tcx.def_kind(local_def_id) { // assoc impl items of traits are live if the corresponding trait items are live - DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => ( - self.tcx.local_parent(local_def_id), - self.tcx - .associated_item(local_def_id) - .trait_item_def_id - .and_then(|def_id| def_id.as_local()), - ), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => { + let trait_item_id = + self.tcx.trait_item_of(local_def_id).and_then(|def_id| def_id.as_local()); + (self.tcx.local_parent(local_def_id), trait_item_id) + } // impl items are live if the corresponding traits are live DefKind::Impl { of_trait: true } => ( local_def_id, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 23dcabef1a1..2da4b6f52cf 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1610,6 +1610,15 @@ pub(crate) struct ReprAlignShouldBeAlign { } #[derive(Diagnostic)] +#[diag(passes_repr_align_should_be_align_static)] +pub(crate) struct ReprAlignShouldBeAlignStatic { + #[primary_span] + #[help] + pub span: Span, + pub item: &'static str, +} + +#[derive(Diagnostic)] #[diag(passes_custom_mir_phase_requires_dialect)] pub(crate) struct CustomMirPhaseRequiresDialect { #[primary_span] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 71650c6b9b9..2ee1bd0dfd1 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -21,8 +21,8 @@ use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult}; use rustc_middle::query::{LocalCrate, Providers}; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{AssocContainer, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL}; use rustc_span::{Span, Symbol, sym}; @@ -486,8 +486,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { self.check_compatible_stability(ii.owner_id.def_id); - let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id()); - if self.tcx.impl_trait_ref(impl_def_id).is_none() { + if let hir::ImplItemImplKind::Inherent { .. } = ii.impl_kind { self.check_missing_stability(ii.owner_id.def_id); self.check_missing_const_stability(ii.owner_id.def_id); } @@ -711,7 +710,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { for impl_item_ref in items { let impl_item = self.tcx.associated_item(impl_item_ref.owner_id); - if let Some(def_id) = impl_item.trait_item_def_id { + if let AssocContainer::TraitImpl(Ok(def_id)) = impl_item.container { // Pass `None` to skip deprecation warnings. self.tcx.check_stability( def_id, diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index 1b5f0ed1429..bcc77ff849d 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1612,11 +1612,7 @@ crate_def! { pub struct AssocItem { pub def_id: AssocDef, pub kind: AssocKind, - pub container: AssocItemContainer, - - /// If this is an item in an impl of a trait then this is the `DefId` of - /// the associated item on the trait that this implements. - pub trait_item_def_id: Option<AssocDef>, + pub container: AssocContainer, } #[derive(Clone, PartialEq, Debug, Eq, Serialize)] @@ -1636,9 +1632,11 @@ pub enum AssocKind { } #[derive(Clone, Debug, Eq, PartialEq, Serialize)] -pub enum AssocItemContainer { +pub enum AssocContainer { + InherentImpl, + /// The `AssocDef` points to the trait item being implemented. + TraitImpl(AssocDef), Trait, - Impl, } #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize)] diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 207038db40d..5131611eb02 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -1076,14 +1076,21 @@ impl<'tcx> Stable<'tcx> for ty::AssocKind { } } -impl<'tcx> Stable<'tcx> for ty::AssocItemContainer { - type T = crate::ty::AssocItemContainer; +impl<'tcx> Stable<'tcx> for ty::AssocContainer { + type T = crate::ty::AssocContainer; - fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T { - use crate::ty::AssocItemContainer; + fn stable( + &self, + tables: &mut Tables<'_, BridgeTys>, + _: &CompilerCtxt<'_, BridgeTys>, + ) -> Self::T { + use crate::ty::AssocContainer; match self { - ty::AssocItemContainer::Trait => AssocItemContainer::Trait, - ty::AssocItemContainer::Impl => AssocItemContainer::Impl, + ty::AssocContainer::Trait => AssocContainer::Trait, + ty::AssocContainer::InherentImpl => AssocContainer::InherentImpl, + ty::AssocContainer::TraitImpl(trait_item_id) => { + AssocContainer::TraitImpl(tables.assoc_def(trait_item_id.unwrap())) + } } } } @@ -1100,7 +1107,6 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem { def_id: tables.assoc_def(self.def_id), kind: self.kind.stable(tables, cx), container: self.container.stable(tables, cx), - trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)), } } } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index e5cceacf15d..257785b10c8 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -13,7 +13,6 @@ rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } -rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 55549cba737..4e601a6c594 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -9,6 +9,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; use rustc_hashes::Hash64; +use rustc_hir::limit::Limit; use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::dep_graph::{ @@ -31,7 +32,6 @@ use rustc_query_system::query::{ }; use rustc_query_system::{QueryOverflow, QueryOverflowNote}; use rustc_serialize::{Decodable, Encodable}; -use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use crate::QueryConfigRestored; diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 5108ecaeea3..2778b24e774 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -1,6 +1,6 @@ use rustc_errors::codes::*; +use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_session::Limit; use rustc_span::{Span, Symbol}; #[derive(Subdiagnostic)] diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 0e566e20a12..cc8fbc18b73 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -231,6 +231,9 @@ resolve_item_was_cfg_out = the item is gated here resolve_label_with_similar_name_reachable = a label with a similar name is reachable +resolve_legacy_derive_helpers = derive helper attribute is used before it is introduced + .label = the attribute is introduced here + resolve_lending_iterator_report_error = associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type @@ -260,6 +263,9 @@ resolve_macro_defined_later = resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments = macro-expanded `extern crate` items cannot shadow names passed with `--extern` +resolve_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths + .note = the macro is defined here + resolve_macro_expected_found = expected {$expected}, found {$found} `{$macro_path}` .label = not {$article} {$expected} @@ -268,6 +274,10 @@ resolve_macro_extern_deprecated = `#[macro_escape]` is a deprecated synonym for `#[macro_use]` .help = try an outer attribute: `#[macro_use]` +resolve_macro_use_deprecated = + applying the `#[macro_use]` attribute to an `extern crate` item is deprecated + .help = remove it and import macros at use sites with a `use` item instead + resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self` resolve_macro_use_name_already_in_use = @@ -339,6 +349,9 @@ resolve_param_in_ty_of_const_param = resolve_pattern_doesnt_bind_name = pattern doesn't bind `{$name}` +resolve_proc_macro_derive_resolution_fallback = cannot find {$ns_descr} `{$ident}` in this scope + .label = names from parent modules are not accessible without an explicit import + resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it .help = you can define integration tests in a directory named `tests` @@ -348,6 +361,9 @@ resolve_reexport_of_crate_public = resolve_reexport_of_private = re-export of private `{$ident}` +resolve_reexport_private_dependency = + {$kind} `{$name}` from private dependency '{$krate}' is re-exported + resolve_relative_2018 = relative paths are not supported in visibilities in 2018 edition or later .suggestion = try @@ -465,6 +481,14 @@ resolve_unreachable_label_suggestion_use_similarly_named = resolve_unreachable_label_with_similar_name_exists = a label with a similar name exists but is unreachable +resolve_unused_extern_crate = unused extern crate + .label = unused + .suggestion = remove the unused `extern crate` + +resolve_unused_label = unused label + +resolve_unused_macro_use = unused `#[macro_use]` import + resolve_variable_bound_with_different_mode = variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` .label = bound in different ways diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 50a1ad23a54..95f979a3fed 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -169,7 +169,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { UNUSED_EXTERN_CRATES, extern_crate.id, span, - BuiltinLintDiag::UnusedExternCrate { + crate::errors::UnusedExternCrate { span: extern_crate.span, removal_span: extern_crate.span_with_attributes, }, @@ -406,7 +406,7 @@ impl Resolver<'_, '_> { MACRO_USE_EXTERN_CRATE, import.root_id, import.span, - BuiltinLintDiag::MacroUseDeprecated, + crate::errors::MacroUseDeprecated, ); } } @@ -427,7 +427,7 @@ impl Resolver<'_, '_> { UNUSED_IMPORTS, import.root_id, import.span, - BuiltinLintDiag::UnusedMacroUse, + crate::errors::UnusedMacroUse, ); } _ => {} diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 689e713ef46..236ab1f09d3 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -138,7 +138,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, CRATE_NODE_ID, span_use, - BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def), + errors::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }, ); } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 72be94e58db..f0ea97ba8a0 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{ Applicability, Diag, ElidedLifetimeInPathSubdiag, EmissionGuarantee, IntoDiagArg, MultiSpan, Subdiagnostic, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; use crate::late::PatternSource; @@ -566,6 +566,22 @@ pub(crate) struct ProcMacroSameCrate { pub(crate) is_test: bool, } +#[derive(LintDiagnostic)] +#[diag(resolve_proc_macro_derive_resolution_fallback)] +pub(crate) struct ProcMacroDeriveResolutionFallback { + #[label] + pub span: Span, + pub ns_descr: &'static str, + pub ident: Ident, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_expanded_macro_exports_accessed_by_absolute_paths)] +pub(crate) struct MacroExpandedMacroExportsAccessedByAbsolutePaths { + #[note] + pub definition: Span, +} + #[derive(Diagnostic)] #[diag(resolve_imported_crate)] pub(crate) struct CrateImported { @@ -1276,3 +1292,40 @@ pub(crate) struct TraitImplMismatch { #[label(resolve_trait_impl_mismatch_label_item)] pub(crate) trait_item_span: Span, } + +#[derive(LintDiagnostic)] +#[diag(resolve_legacy_derive_helpers)] +pub(crate) struct LegacyDeriveHelpers { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unused_extern_crate)] +pub(crate) struct UnusedExternCrate { + #[label] + pub span: Span, + #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] + pub removal_span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_reexport_private_dependency)] +pub(crate) struct ReexportPrivateDependency { + pub name: Symbol, + pub kind: &'static str, + pub krate: Symbol, +} + +#[derive(LintDiagnostic)] +#[diag(resolve_unused_label)] +pub(crate) struct UnusedLabel; + +#[derive(LintDiagnostic)] +#[diag(resolve_unused_macro_use)] +pub(crate) struct UnusedMacroUse; + +#[derive(LintDiagnostic)] +#[diag(resolve_macro_use_deprecated)] +#[help] +pub(crate) struct MacroUseDeprecated; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index bc06a227571..35051675fd8 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -4,7 +4,6 @@ use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_middle::bug; -use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; @@ -520,7 +519,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, orig_ident.span, - BuiltinLintDiag::ProcMacroDeriveResolutionFallback { + errors::ProcMacroDeriveResolutionFallback { span: orig_ident.span, ns_descr: ns.descr(), ident, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d7fc028287f..33c2c7436d1 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -720,9 +720,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { EXPORTED_PRIVATE_DEPENDENCIES, binding_id, binding.span, - BuiltinLintDiag::ReexportPrivateDependency { - kind: binding.res().descr().to_string(), - name: key.ident.name.to_string(), + crate::errors::ReexportPrivateDependency { + name: key.ident.name, + kind: binding.res().descr(), krate: self.tcx.crate_name(reexported_def_id.krate), }, ); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 521fef2b9d4..4d4acc60ca8 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,7 +29,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::{DelegationFnSig, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; -use rustc_session::lint::{self, BuiltinLintDiag}; +use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; @@ -5225,7 +5225,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lint::builtin::UNUSED_LABELS, *id, *span, - BuiltinLintDiag::UnusedLabel, + errors::UnusedLabel, ); } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 5fa87b4cd9b..d3e98ef839b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -979,7 +979,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { LEGACY_DERIVE_HELPERS, node_id, ident.span, - BuiltinLintDiag::LegacyDeriveHelpers(binding.span), + errors::LegacyDeriveHelpers { span: binding.span }, ); } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index d81fa062e01..577a16a0d25 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -469,8 +469,7 @@ fn implemented_method<'tcx>( let ancestor = if let Some(impl_id) = tcx.impl_of_assoc(instance.def_id()) { // Implementation in an `impl` block trait_ref = tcx.impl_trait_ref(impl_id)?; - let impl_method = tcx.associated_item(instance.def_id()); - method_id = impl_method.trait_item_def_id?; + method_id = tcx.trait_item_of(instance.def_id())?; trait_method = tcx.associated_item(method_id); trait_id = trait_ref.skip_binder().def_id; impl_id diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 9793d8091e2..297df7c2c97 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -70,6 +70,7 @@ pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ ("target-libdir", PrintKind::TargetLibdir), ("target-list", PrintKind::TargetList), ("target-spec-json", PrintKind::TargetSpecJson), + ("target-spec-json-schema", PrintKind::TargetSpecJsonSchema), ("tls-models", PrintKind::TlsModels), // tidy-alphabetical-end ]; @@ -1043,6 +1044,7 @@ pub enum PrintKind { TargetLibdir, TargetList, TargetSpecJson, + TargetSpecJsonSchema, TlsModels, // tidy-alphabetical-end } @@ -2323,7 +2325,8 @@ fn is_print_request_stable(print_kind: PrintKind) -> bool { | PrintKind::CheckCfg | PrintKind::CrateRootLintLevels | PrintKind::SupportedCrateTypes - | PrintKind::TargetSpecJson => false, + | PrintKind::TargetSpecJson + | PrintKind::TargetSpecJsonSchema => false, _ => true, } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 96767d05439..3525c7c1d1a 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,10 +1,9 @@ use std::any::Any; -use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Arc; use std::sync::atomic::AtomicBool; -use std::{env, fmt, io}; +use std::{env, io}; use rand::{RngCore, rng}; use rustc_ast::NodeId; @@ -25,6 +24,7 @@ use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort, LintEmitter, TerminalUrl, fallback_fluent_bundle, }; +use rustc_hir::limit::Limit; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; use rustc_span::edition::Edition; @@ -62,64 +62,6 @@ pub enum CtfeBacktrace { Immediate, } -/// New-type wrapper around `usize` for representing limits. Ensures that comparisons against -/// limits are consistent throughout the compiler. -#[derive(Clone, Copy, Debug, HashStable_Generic)] -pub struct Limit(pub usize); - -impl Limit { - /// Create a new limit from a `usize`. - pub fn new(value: usize) -> Self { - Limit(value) - } - - /// Create a new unlimited limit. - pub fn unlimited() -> Self { - Limit(usize::MAX) - } - - /// Check that `value` is within the limit. Ensures that the same comparisons are used - /// throughout the compiler, as mismatches can cause ICEs, see #72540. - #[inline] - pub fn value_within_limit(&self, value: usize) -> bool { - value <= self.0 - } -} - -impl From<usize> for Limit { - fn from(value: usize) -> Self { - Self::new(value) - } -} - -impl fmt::Display for Limit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl Div<usize> for Limit { - type Output = Limit; - - fn div(self, rhs: usize) -> Self::Output { - Limit::new(self.0 / rhs) - } -} - -impl Mul<usize> for Limit { - type Output = Limit; - - fn mul(self, rhs: usize) -> Self::Output { - Limit::new(self.0 * rhs) - } -} - -impl rustc_errors::IntoDiagArg for Limit { - fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue { - self.to_string().into_diag_arg(&mut None) - } -} - #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct Limits { /// The maximum recursion limit for potentially infinitely recursive diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 19494ffc37e..633cbc3a4ae 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -46,6 +46,8 @@ use crate::symbol::{Symbol, kw, sym}; use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals}; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". +/// +/// See <https://rustc-dev-guide.rust-lang.org/macro-expansion.html> for more explanation. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct SyntaxContext(u32); @@ -61,7 +63,10 @@ pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency); #[derive(Clone, Copy, Debug)] struct SyntaxContextData { + /// The last macro expansion in the chain. + /// (Here we say the most deeply nested macro expansion is the "outermost" expansion.) outer_expn: ExpnId, + /// Transparency of the last macro expansion outer_transparency: Transparency, parent: SyntaxContext, /// This context, but with all transparent and semi-opaque expansions filtered away. @@ -450,11 +455,13 @@ impl HygieneData { self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque } + /// See [`SyntaxContextData::outer_expn`] #[inline] fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { self.syntax_context_data[ctxt.0 as usize].outer_expn } + /// The last macro expansion and its Transparency #[inline] fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { let data = &self.syntax_context_data[ctxt.0 as usize]; @@ -900,6 +907,7 @@ impl SyntaxContext { HygieneData::with(|data| data.normalize_to_macro_rules(self)) } + /// See [`SyntaxContextData::outer_expn`] #[inline] pub fn outer_expn(self) -> ExpnId { HygieneData::with(|data| data.outer_expn(self)) @@ -912,6 +920,7 @@ impl SyntaxContext { HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone()) } + /// See [`HygieneData::outer_mark`] #[inline] fn outer_mark(self) -> (ExpnId, Transparency) { HygieneData::with(|data| data.outer_mark(self)) @@ -982,19 +991,20 @@ impl Span { #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct ExpnData { // --- The part unique to each expansion. - /// The kind of this expansion - macro or compiler desugaring. pub kind: ExpnKind, - /// The expansion that produced this expansion. + /// The expansion that contains the definition of the macro for this expansion. pub parent: ExpnId, - /// The location of the actual macro invocation or syntax sugar , e.g. - /// `let x = foo!();` or `if let Some(y) = x {}` + /// The span of the macro call which produced this expansion. + /// + /// This span will typically have a different `ExpnData` and `call_site`. + /// This recursively traces back through any macro calls which expanded into further + /// macro calls, until the "source call-site" is reached at the root SyntaxContext. + /// For example, if `food!()` expands to `fruit!()` which then expands to `grape`, + /// then the call-site of `grape` is `fruit!()` and the call-site of `fruit!()` + /// is `food!()`. /// - /// This may recursively refer to other macro invocations, e.g., if - /// `foo!()` invoked `bar!()` internally, and there was an - /// expression inside `bar!`; the call_site of the expression in - /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnData, with the call_site - /// pointing to the `foo!` invocation. + /// For a desugaring expansion, this is the span of the expression or node that was + /// desugared. pub call_site: Span, /// Used to force two `ExpnData`s to have different `Fingerprint`s. /// Due to macro expansion, it's possible to end up with two `ExpnId`s diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index ae6755f0764..e95b743b1ce 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -710,8 +710,8 @@ impl Span { if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self } } - /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, - /// if any. + /// Returns the call-site span of the last macro expansion which produced this `Span`. + /// (see [`ExpnData::call_site`]). Returns `None` if this is not an expansion. pub fn parent_callsite(self) -> Option<Span> { let ctxt = self.ctxt(); (!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e5108d8b7e9..cdb0b5b58da 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -7,7 +7,7 @@ use std::ops::Deref; use std::{fmt, str}; use rustc_arena::DroplessArena; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; @@ -21,18 +21,17 @@ mod tests; // The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`. symbols! { - // This list includes things that are definitely keywords (e.g. `if`), - // a few things that are definitely not keywords (e.g. the empty symbol, - // `{{root}}`) and things where there is disagreement between people and/or - // documents (such as the Rust Reference) about whether it is a keyword - // (e.g. `_`). + // This list includes things that are definitely keywords (e.g. `if`), a + // few things that are definitely not keywords (e.g. `{{root}}`) and things + // where there is disagreement between people and/or documents (such as the + // Rust Reference) about whether it is a keyword (e.g. `_`). // // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` // predicates and `used_keywords`. Also consider adding new keywords to the // `ui/parser/raw/raw-idents.rs` test. Keywords { - // Special reserved identifiers used internally for elided lifetimes, - // unnamed method parameters, crate root module, error recovery etc. + // Special reserved identifiers used internally for unnamed method + // parameters, crate root module, etc. // Matching predicates: `is_special`/`is_reserved` // // tidy-alphabetical-start @@ -326,6 +325,7 @@ symbols! { RangeSub, RangeTo, RangeToInclusive, + RangeToInclusiveCopy, Rc, RcWeak, Ready, @@ -1280,6 +1280,7 @@ symbols! { lang, lang_items, large_assignments, + last, lateout, lazy_normalization_consts, lazy_type_alias, @@ -1846,6 +1847,7 @@ symbols! { rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity rustc_align, + rustc_align_static, rustc_allocator, rustc_allocator_zeroed, rustc_allocator_zeroed_variant, @@ -2097,6 +2099,7 @@ symbols! { staged_api, start, state, + static_align, static_in_const, static_nobundle, static_recursion, @@ -2868,11 +2871,20 @@ impl Interner { let byte_strs = FxIndexSet::from_iter( init.iter().copied().chain(extra.iter().copied()).map(|str| str.as_bytes()), ); - assert_eq!( - byte_strs.len(), - init.len() + extra.len(), - "duplicate symbols in the rustc symbol list and the extra symbols added by the driver", - ); + + // The order in which duplicates are reported is irrelevant. + #[expect(rustc::potential_query_instability)] + if byte_strs.len() != init.len() + extra.len() { + panic!( + "duplicate symbols in the rustc symbol list and the extra symbols added by the driver: {:?}", + FxHashSet::intersection( + &init.iter().copied().collect(), + &extra.iter().copied().collect(), + ) + .collect::<Vec<_>>() + ) + } + Interner(Lock::new(InternerInner { arena: Default::default(), byte_strs })) } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 4d9741f1d11..95a7ec61868 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -54,7 +54,7 @@ pub(super) fn mangle<'tcx>( // Erase regions because they may not be deterministic when hashed // and should not matter anyhow. - let instance_ty = tcx.erase_regions(instance_ty); + let instance_ty = tcx.erase_and_anonymize_regions(instance_ty); let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); @@ -422,7 +422,10 @@ impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> { || &args[..generics.count()] == self .tcx - .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item( + self.tcx, + impl_def_id, + )) .as_slice() { ( diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 0c6d1495e39..50935e7caf3 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -58,7 +58,7 @@ impl SymbolNamesTest<'_> { let def_id = def_id.to_def_id(); let instance = Instance::new_raw( def_id, - tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)), + tcx.erase_and_anonymize_regions(GenericArgs::identity_for_item(tcx, def_id)), ); let mangled = tcx.symbol_name(instance); tcx.dcx().emit_err(TestOutput { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 0655c2d5e81..1605b4958ba 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -329,7 +329,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { || &args[..generics.count()] == self .tcx - .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id)) + .erase_and_anonymize_regions(ty::GenericArgs::identity_for_item( + self.tcx, + impl_def_id, + )) .as_slice() { ( @@ -339,7 +342,7 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> { ) } else { assert!( - !args.has_non_region_param(), + !args.has_non_region_param() && !args.has_free_regions(), "should not be mangling partially substituted \ polymorphic instance: {impl_def_id:?} {args:?}" ); diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index 7fabb227d9a..ecdb6ab5a57 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -14,6 +14,7 @@ rustc_fs_util = { path = "../rustc_fs_util" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } +schemars = "1.0.4" serde = "1.0.219" serde_derive = "1.0.219" serde_json = "1.0.59" diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 91657fef803..b3fe1fffcce 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -72,3 +72,65 @@ fn find_relative_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> { Some(libdir) => libdir.into(), } } + +macro_rules! target_spec_enum { + ( + $( #[$attr:meta] )* + pub enum $name:ident { + $( + $( #[$variant_attr:meta] )* + $variant:ident = $string:literal, + )* + } + parse_error_type = $parse_error_type:literal; + ) => { + $( #[$attr] )* + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] + #[derive(schemars::JsonSchema)] + pub enum $name { + $( + $( #[$variant_attr] )* + #[serde(rename = $string)] // for JSON schema generation only + $variant, + )* + } + + impl FromStr for $name { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(match s { + $( $string => Self::$variant, )* + _ => { + let all = [$( concat!("'", $string, "'") ),*].join(", "); + return Err(format!("invalid {}: '{s}'. allowed values: {all}", $parse_error_type)); + } + }) + } + } + + impl $name { + pub fn desc(&self) -> &'static str { + match self { + $( Self::$variant => $string, )* + } + } + } + + impl crate::json::ToJson for $name { + fn to_json(&self) -> crate::json::Json { + self.desc().to_json() + } + } + + crate::json::serde_deserialize_from_str!($name); + + + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.desc()) + } + } + }; +} +use target_spec_enum; diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index e9ae5734d5b..f236be92b3b 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -408,12 +408,12 @@ impl ToJson for Target { } } -#[derive(serde_derive::Deserialize)] +#[derive(serde_derive::Deserialize, schemars::JsonSchema)] struct LinkSelfContainedComponentsWrapper { components: Vec<LinkSelfContainedComponents>, } -#[derive(serde_derive::Deserialize)] +#[derive(serde_derive::Deserialize, schemars::JsonSchema)] #[serde(untagged)] enum TargetFamiliesJson { Array(StaticCow<[StaticCow<str>]>), @@ -429,6 +429,18 @@ impl FromStr for EndianWrapper { } } crate::json::serde_deserialize_from_str!(EndianWrapper); +impl schemars::JsonSchema for EndianWrapper { + fn schema_name() -> std::borrow::Cow<'static, str> { + "Endian".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema! ({ + "type": "string", + "enum": ["big", "little"] + }) + .into() + } +} /// `ExternAbi` is in `rustc_abi`, which doesn't have access to the macro and serde. struct ExternAbiWrapper(rustc_abi::ExternAbi); @@ -441,8 +453,22 @@ impl FromStr for ExternAbiWrapper { } } crate::json::serde_deserialize_from_str!(ExternAbiWrapper); +impl schemars::JsonSchema for ExternAbiWrapper { + fn schema_name() -> std::borrow::Cow<'static, str> { + "ExternAbi".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + let all = + rustc_abi::ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect::<Vec<_>>(); + schemars::json_schema! ({ + "type": "string", + "enum": all, + }) + .into() + } +} -#[derive(serde_derive::Deserialize)] +#[derive(serde_derive::Deserialize, schemars::JsonSchema)] struct TargetSpecJsonMetadata { description: Option<StaticCow<str>>, tier: Option<u64>, @@ -450,7 +476,7 @@ struct TargetSpecJsonMetadata { std: Option<bool>, } -#[derive(serde_derive::Deserialize)] +#[derive(serde_derive::Deserialize, schemars::JsonSchema)] #[serde(rename_all = "kebab-case")] // Ensure that all unexpected fields get turned into errors. // This helps users stay up to date when the schema changes instead of silently @@ -593,3 +619,7 @@ struct TargetSpecJson { supports_xray: Option<bool>, entry_abi: Option<ExternAbiWrapper>, } + +pub fn json_schema() -> schemars::Schema { + schemars::schema_for!(TargetSpecJson) +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4d9f06c568b..07fb1ce63f7 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -70,6 +70,7 @@ mod json; pub use abi_map::{AbiMap, AbiMapping}; pub use base::apple; pub use base::avr::ef_avr_arch; +pub use json::json_schema; /// Linker is called through a C/C++ compiler. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -183,50 +184,15 @@ impl LinkerFlavorCli { } } -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] -pub enum LldFlavor { - Wasm, - Ld64, - Ld, - Link, -} - -impl LldFlavor { - pub fn as_str(&self) -> &'static str { - match self { - LldFlavor::Wasm => "wasm", - LldFlavor::Ld64 => "darwin", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - } - } -} - -impl FromStr for LldFlavor { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "darwin" => LldFlavor::Ld64, - "gnu" => LldFlavor::Ld, - "link" => LldFlavor::Link, - "wasm" => LldFlavor::Wasm, - _ => { - return Err( - "invalid value for lld flavor: '{s}', expected one of 'darwin', 'gnu', 'link', 'wasm'" - .into(), - ); - } - }) +crate::target_spec_enum! { + pub enum LldFlavor { + Wasm = "wasm", + Ld64 = "darwin", + Ld = "gnu", + Link = "link", } -} -crate::json::serde_deserialize_from_str!(LldFlavor); - -impl ToJson for LldFlavor { - fn to_json(&self) -> Json { - self.as_str().to_json() - } + parse_error_type = "LLD flavor"; } impl LinkerFlavor { @@ -558,6 +524,20 @@ linker_flavor_cli_impls! { } crate::json::serde_deserialize_from_str!(LinkerFlavorCli); +impl schemars::JsonSchema for LinkerFlavorCli { + fn schema_name() -> std::borrow::Cow<'static, str> { + "LinkerFlavor".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + let all: Vec<&'static str> = + Self::all().iter().map(|flavor| flavor.desc()).collect::<Vec<_>>(); + schemars::json_schema! ({ + "type": "string", + "enum": all + }) + .into() + } +} impl ToJson for LinkerFlavorCli { fn to_json(&self) -> Json { @@ -611,6 +591,18 @@ impl FromStr for LinkSelfContainedDefault { } crate::json::serde_deserialize_from_str!(LinkSelfContainedDefault); +impl schemars::JsonSchema for LinkSelfContainedDefault { + fn schema_name() -> std::borrow::Cow<'static, str> { + "LinkSelfContainedDefault".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema! ({ + "type": "string", + "enum": ["false", "true", "wasm", "musl", "mingw"] + }) + .into() + } +} impl ToJson for LinkSelfContainedDefault { fn to_json(&self) -> Json { @@ -743,6 +735,20 @@ impl FromStr for LinkSelfContainedComponents { } crate::json::serde_deserialize_from_str!(LinkSelfContainedComponents); +impl schemars::JsonSchema for LinkSelfContainedComponents { + fn schema_name() -> std::borrow::Cow<'static, str> { + "LinkSelfContainedComponents".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + let all = + Self::all_components().iter().map(|component| component.as_str()).collect::<Vec<_>>(); + schemars::json_schema! ({ + "type": "string", + "enum": all, + }) + .into() + } +} impl ToJson for LinkSelfContainedComponents { fn to_json(&self) -> Json { @@ -823,10 +829,14 @@ impl LinkerFeatures { } } -#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] -pub enum PanicStrategy { - Unwind, - Abort, +crate::target_spec_enum! { + #[derive(Encodable, Decodable, HashStable_Generic)] + pub enum PanicStrategy { + Unwind = "unwind", + Abort = "abort", + } + + parse_error_type = "panic strategy"; } #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] @@ -838,13 +848,6 @@ pub enum OnBrokenPipe { } impl PanicStrategy { - pub fn desc(&self) -> &str { - match *self { - PanicStrategy::Unwind => "unwind", - PanicStrategy::Abort => "abort", - } - } - pub const fn desc_symbol(&self) -> Symbol { match *self { PanicStrategy::Unwind => sym::unwind, @@ -857,24 +860,16 @@ impl PanicStrategy { } } -impl FromStr for PanicStrategy { - type Err = String; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "unwind" => PanicStrategy::Unwind, - "abort" => PanicStrategy::Abort, - _ => { - return Err(format!( - "'{}' is not a valid value for \ - panic-strategy. Use 'unwind' or 'abort'.", - s - )); - } - }) +crate::target_spec_enum! { + pub enum RelroLevel { + Full = "full", + Partial = "partial", + Off = "off", + None = "none", } -} -crate::json::serde_deserialize_from_str!(PanicStrategy); + parse_error_type = "relro level"; +} impl IntoDiagArg for PanicStrategy { fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue { @@ -882,109 +877,14 @@ impl IntoDiagArg for PanicStrategy { } } -impl ToJson for PanicStrategy { - fn to_json(&self) -> Json { - match *self { - PanicStrategy::Abort => "abort".to_json(), - PanicStrategy::Unwind => "unwind".to_json(), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Hash)] -pub enum RelroLevel { - Full, - Partial, - Off, - None, -} - -impl RelroLevel { - pub fn desc(&self) -> &str { - match *self { - RelroLevel::Full => "full", - RelroLevel::Partial => "partial", - RelroLevel::Off => "off", - RelroLevel::None => "none", - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Hash)] -pub enum SymbolVisibility { - Hidden, - Protected, - Interposable, -} - -impl SymbolVisibility { - pub fn desc(&self) -> &str { - match *self { - SymbolVisibility::Hidden => "hidden", - SymbolVisibility::Protected => "protected", - SymbolVisibility::Interposable => "interposable", - } - } -} - -impl FromStr for SymbolVisibility { - type Err = String; - - fn from_str(s: &str) -> Result<SymbolVisibility, Self::Err> { - match s { - "hidden" => Ok(SymbolVisibility::Hidden), - "protected" => Ok(SymbolVisibility::Protected), - "interposable" => Ok(SymbolVisibility::Interposable), - _ => Err(format!( - "'{}' is not a valid value for \ - symbol-visibility. Use 'hidden', 'protected, or 'interposable'.", - s - )), - } - } -} - -crate::json::serde_deserialize_from_str!(SymbolVisibility); - -impl ToJson for SymbolVisibility { - fn to_json(&self) -> Json { - match *self { - SymbolVisibility::Hidden => "hidden".to_json(), - SymbolVisibility::Protected => "protected".to_json(), - SymbolVisibility::Interposable => "interposable".to_json(), - } - } -} - -impl FromStr for RelroLevel { - type Err = String; - - fn from_str(s: &str) -> Result<RelroLevel, Self::Err> { - match s { - "full" => Ok(RelroLevel::Full), - "partial" => Ok(RelroLevel::Partial), - "off" => Ok(RelroLevel::Off), - "none" => Ok(RelroLevel::None), - _ => Err(format!( - "'{}' is not a valid value for \ - relro-level. Use 'full', 'partial, 'off', or 'none'.", - s - )), - } +crate::target_spec_enum! { + pub enum SymbolVisibility { + Hidden = "hidden", + Protected = "protected", + Interposable = "interposable", } -} - -crate::json::serde_deserialize_from_str!(RelroLevel); -impl ToJson for RelroLevel { - fn to_json(&self) -> Json { - match *self { - RelroLevel::Full => "full".to_json(), - RelroLevel::Partial => "partial".to_json(), - RelroLevel::Off => "off".to_json(), - RelroLevel::None => "None".to_json(), - } - } + parse_error_type = "symbol visibility"; } #[derive(Clone, Debug, PartialEq, Hash)] @@ -1014,6 +914,18 @@ impl FromStr for SmallDataThresholdSupport { } crate::json::serde_deserialize_from_str!(SmallDataThresholdSupport); +impl schemars::JsonSchema for SmallDataThresholdSupport { + fn schema_name() -> std::borrow::Cow<'static, str> { + "SmallDataThresholdSupport".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + schemars::json_schema! ({ + "type": "string", + "pattern": r#"^none|default-for-arch|llvm-module-flag=.+|llvm-arg=.+$"#, + }) + .into() + } +} impl ToJson for SmallDataThresholdSupport { fn to_json(&self) -> Value { @@ -1026,76 +938,31 @@ impl ToJson for SmallDataThresholdSupport { } } -#[derive(Clone, Copy, Debug, PartialEq, Hash)] -pub enum MergeFunctions { - Disabled, - Trampolines, - Aliases, -} - -impl MergeFunctions { - pub fn desc(&self) -> &str { - match *self { - MergeFunctions::Disabled => "disabled", - MergeFunctions::Trampolines => "trampolines", - MergeFunctions::Aliases => "aliases", - } +crate::target_spec_enum! { + pub enum MergeFunctions { + Disabled = "disabled", + Trampolines = "trampolines", + Aliases = "aliases", } -} - -impl FromStr for MergeFunctions { - type Err = String; - fn from_str(s: &str) -> Result<MergeFunctions, Self::Err> { - match s { - "disabled" => Ok(MergeFunctions::Disabled), - "trampolines" => Ok(MergeFunctions::Trampolines), - "aliases" => Ok(MergeFunctions::Aliases), - _ => Err(format!( - "'{}' is not a valid value for \ - merge-functions. Use 'disabled', \ - 'trampolines', or 'aliases'.", - s - )), - } - } + parse_error_type = "value for merge-functions"; } -crate::json::serde_deserialize_from_str!(MergeFunctions); - -impl ToJson for MergeFunctions { - fn to_json(&self) -> Json { - match *self { - MergeFunctions::Disabled => "disabled".to_json(), - MergeFunctions::Trampolines => "trampolines".to_json(), - MergeFunctions::Aliases => "aliases".to_json(), - } +crate::target_spec_enum! { + pub enum RelocModel { + Static = "static", + Pic = "pic", + Pie = "pie", + DynamicNoPic = "dynamic-no-pic", + Ropi = "ropi", + Rwpi = "rwpi", + RopiRwpi = "ropi-rwpi", } -} -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum RelocModel { - Static, - Pic, - Pie, - DynamicNoPic, - Ropi, - Rwpi, - RopiRwpi, + parse_error_type = "relocation model"; } impl RelocModel { - pub fn desc(&self) -> &str { - match *self { - RelocModel::Static => "static", - RelocModel::Pic => "pic", - RelocModel::Pie => "pie", - RelocModel::DynamicNoPic => "dynamic-no-pic", - RelocModel::Ropi => "ropi", - RelocModel::Rwpi => "rwpi", - RelocModel::RopiRwpi => "ropi-rwpi", - } - } pub const fn desc_symbol(&self) -> Symbol { match *self { RelocModel::Static => kw::Static, @@ -1121,236 +988,75 @@ impl RelocModel { } } -impl FromStr for RelocModel { - type Err = String; - - fn from_str(s: &str) -> Result<RelocModel, Self::Err> { - Ok(match s { - "static" => RelocModel::Static, - "pic" => RelocModel::Pic, - "pie" => RelocModel::Pie, - "dynamic-no-pic" => RelocModel::DynamicNoPic, - "ropi" => RelocModel::Ropi, - "rwpi" => RelocModel::Rwpi, - "ropi-rwpi" => RelocModel::RopiRwpi, - _ => { - return Err(format!( - "invalid relocation model '{s}'. - Run `rustc --print relocation-models` to \ - see the list of supported values.'" - )); - } - }) +crate::target_spec_enum! { + pub enum CodeModel { + Tiny = "tiny", + Small = "small", + Kernel = "kernel", + Medium = "medium", + Large = "large", } -} -crate::json::serde_deserialize_from_str!(RelocModel); - -impl ToJson for RelocModel { - fn to_json(&self) -> Json { - self.desc().to_json() - } -} - -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum CodeModel { - Tiny, - Small, - Kernel, - Medium, - Large, + parse_error_type = "code model"; } -impl FromStr for CodeModel { - type Err = String; - - fn from_str(s: &str) -> Result<CodeModel, Self::Err> { - Ok(match s { - "tiny" => CodeModel::Tiny, - "small" => CodeModel::Small, - "kernel" => CodeModel::Kernel, - "medium" => CodeModel::Medium, - "large" => CodeModel::Large, - _ => { - return Err(format!( - "'{s}' is not a valid code model. \ - Run `rustc --print code-models` to \ - see the list of supported values." - )); - } - }) +crate::target_spec_enum! { + /// The float ABI setting to be configured in the LLVM target machine. + pub enum FloatAbi { + Soft = "soft", + Hard = "hard", } -} -crate::json::serde_deserialize_from_str!(CodeModel); - -impl ToJson for CodeModel { - fn to_json(&self) -> Json { - match *self { - CodeModel::Tiny => "tiny", - CodeModel::Small => "small", - CodeModel::Kernel => "kernel", - CodeModel::Medium => "medium", - CodeModel::Large => "large", - } - .to_json() - } + parse_error_type = "float abi"; } -/// The float ABI setting to be configured in the LLVM target machine. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum FloatAbi { - Soft, - Hard, -} - -impl FromStr for FloatAbi { - type Err = String; - - fn from_str(s: &str) -> Result<FloatAbi, Self::Err> { - Ok(match s { - "soft" => FloatAbi::Soft, - "hard" => FloatAbi::Hard, - _ => { - return Err(format!( - "'{}' is not a valid value for \ - llvm-floatabi. Use 'soft' or 'hard'.", - s - )); - } - }) +crate::target_spec_enum! { + /// The Rustc-specific variant of the ABI used for this target. + pub enum RustcAbi { + /// On x86-32 only: make use of SSE and SSE2 for ABI purposes. + X86Sse2 = "x86-sse2", + /// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI. + X86Softfloat = "x86-softfloat", } -} - -crate::json::serde_deserialize_from_str!(FloatAbi); -impl ToJson for FloatAbi { - fn to_json(&self) -> Json { - match *self { - FloatAbi::Soft => "soft", - FloatAbi::Hard => "hard", - } - .to_json() - } -} - -/// The Rustc-specific variant of the ABI used for this target. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum RustcAbi { - /// On x86-32 only: make use of SSE and SSE2 for ABI purposes. - X86Sse2, - /// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI. - X86Softfloat, + parse_error_type = "rustc abi"; } -impl FromStr for RustcAbi { - type Err = String; - - fn from_str(s: &str) -> Result<RustcAbi, Self::Err> { - Ok(match s { - "x86-sse2" => RustcAbi::X86Sse2, - "x86-softfloat" => RustcAbi::X86Softfloat, - _ => { - return Err(format!( - "'{s}' is not a valid value for rustc-abi. \ - Use 'x86-softfloat' or leave the field unset." - )); - } - }) - } -} - -crate::json::serde_deserialize_from_str!(RustcAbi); - -impl ToJson for RustcAbi { - fn to_json(&self) -> Json { - match *self { - RustcAbi::X86Sse2 => "x86-sse2", - RustcAbi::X86Softfloat => "x86-softfloat", - } - .to_json() +crate::target_spec_enum! { + pub enum TlsModel { + GeneralDynamic = "global-dynamic", + LocalDynamic = "local-dynamic", + InitialExec = "initial-exec", + LocalExec = "local-exec", + Emulated = "emulated", } -} -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum TlsModel { - GeneralDynamic, - LocalDynamic, - InitialExec, - LocalExec, - Emulated, -} - -impl FromStr for TlsModel { - type Err = String; - - fn from_str(s: &str) -> Result<TlsModel, Self::Err> { - Ok(match s { - // Note the difference "general" vs "global" difference. The model name is "general", - // but the user-facing option name is "global" for consistency with other compilers. - "global-dynamic" => TlsModel::GeneralDynamic, - "local-dynamic" => TlsModel::LocalDynamic, - "initial-exec" => TlsModel::InitialExec, - "local-exec" => TlsModel::LocalExec, - "emulated" => TlsModel::Emulated, - _ => { - return Err(format!( - "'{s}' is not a valid TLS model. \ - Run `rustc --print tls-models` to \ - see the list of supported values." - )); - } - }) - } + parse_error_type = "TLS model"; } -crate::json::serde_deserialize_from_str!(TlsModel); - -impl ToJson for TlsModel { - fn to_json(&self) -> Json { - match *self { - TlsModel::GeneralDynamic => "global-dynamic", - TlsModel::LocalDynamic => "local-dynamic", - TlsModel::InitialExec => "initial-exec", - TlsModel::LocalExec => "local-exec", - TlsModel::Emulated => "emulated", - } - .to_json() +crate::target_spec_enum! { + /// Everything is flattened to a single enum to make the json encoding/decoding less annoying. + pub enum LinkOutputKind { + /// Dynamically linked non position-independent executable. + DynamicNoPicExe = "dynamic-nopic-exe", + /// Dynamically linked position-independent executable. + DynamicPicExe = "dynamic-pic-exe", + /// Statically linked non position-independent executable. + StaticNoPicExe = "static-nopic-exe", + /// Statically linked position-independent executable. + StaticPicExe = "static-pic-exe", + /// Regular dynamic library ("dynamically linked"). + DynamicDylib = "dynamic-dylib", + /// Dynamic library with bundled libc ("statically linked"). + StaticDylib = "static-dylib", + /// WASI module with a lifetime past the _initialize entry point + WasiReactorExe = "wasi-reactor-exe", } -} -/// Everything is flattened to a single enum to make the json encoding/decoding less annoying. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub enum LinkOutputKind { - /// Dynamically linked non position-independent executable. - DynamicNoPicExe, - /// Dynamically linked position-independent executable. - DynamicPicExe, - /// Statically linked non position-independent executable. - StaticNoPicExe, - /// Statically linked position-independent executable. - StaticPicExe, - /// Regular dynamic library ("dynamically linked"). - DynamicDylib, - /// Dynamic library with bundled libc ("statically linked"). - StaticDylib, - /// WASI module with a lifetime past the _initialize entry point - WasiReactorExe, + parse_error_type = "CRT object kind"; } impl LinkOutputKind { - fn as_str(&self) -> &'static str { - match self { - LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe", - LinkOutputKind::DynamicPicExe => "dynamic-pic-exe", - LinkOutputKind::StaticNoPicExe => "static-nopic-exe", - LinkOutputKind::StaticPicExe => "static-pic-exe", - LinkOutputKind::DynamicDylib => "dynamic-dylib", - LinkOutputKind::StaticDylib => "static-dylib", - LinkOutputKind::WasiReactorExe => "wasi-reactor-exe", - } - } - pub fn can_link_dylib(self) -> bool { match self { LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false, @@ -1363,171 +1069,64 @@ impl LinkOutputKind { } } -impl FromStr for LinkOutputKind { - type Err = String; - - fn from_str(s: &str) -> Result<LinkOutputKind, Self::Err> { - Ok(match s { - "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe, - "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe, - "static-nopic-exe" => LinkOutputKind::StaticNoPicExe, - "static-pic-exe" => LinkOutputKind::StaticPicExe, - "dynamic-dylib" => LinkOutputKind::DynamicDylib, - "static-dylib" => LinkOutputKind::StaticDylib, - "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe, - _ => { - return Err(format!( - "invalid value for CRT object kind. \ - Use '(dynamic,static)-(nopic,pic)-exe' or \ - '(dynamic,static)-dylib' or 'wasi-reactor-exe'" - )); - } - }) - } -} - -crate::json::serde_deserialize_from_str!(LinkOutputKind); - -impl fmt::Display for LinkOutputKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>; pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>; -/// Which kind of debuginfo does the target use? -/// -/// Useful in determining whether a target supports Split DWARF (a target with -/// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example). -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub enum DebuginfoKind { - /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`). - #[default] - Dwarf, - /// DWARF debuginfo in dSYM files (such as on Apple platforms). - DwarfDsym, - /// Program database files (such as on Windows). - Pdb, -} - -impl DebuginfoKind { - fn as_str(&self) -> &'static str { - match self { - DebuginfoKind::Dwarf => "dwarf", - DebuginfoKind::DwarfDsym => "dwarf-dsym", - DebuginfoKind::Pdb => "pdb", - } - } -} - -impl FromStr for DebuginfoKind { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "dwarf" => DebuginfoKind::Dwarf, - "dwarf-dsym" => DebuginfoKind::DwarfDsym, - "pdb" => DebuginfoKind::Pdb, - _ => { - return Err(format!( - "'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \ - 'dwarf-dsym' or 'pdb'." - )); - } - }) - } -} - -crate::json::serde_deserialize_from_str!(DebuginfoKind); - -impl ToJson for DebuginfoKind { - fn to_json(&self) -> Json { - self.as_str().to_json() - } -} - -impl fmt::Display for DebuginfoKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub enum SplitDebuginfo { - /// Split debug-information is disabled, meaning that on supported platforms - /// you can find all debug information in the executable itself. This is - /// only supported for ELF effectively. - /// - /// * Windows - not supported - /// * macOS - don't run `dsymutil` - /// * ELF - `.debug_*` sections - #[default] - Off, - - /// Split debug-information can be found in a "packed" location separate - /// from the final artifact. This is supported on all platforms. +crate::target_spec_enum! { + /// Which kind of debuginfo does the target use? /// - /// * Windows - `*.pdb` - /// * macOS - `*.dSYM` (run `dsymutil`) - /// * ELF - `*.dwp` (run `thorin`) - Packed, - - /// Split debug-information can be found in individual object files on the - /// filesystem. The main executable may point to the object files. - /// - /// * Windows - not supported - /// * macOS - supported, scattered object files - /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`) - Unpacked, -} - -impl SplitDebuginfo { - fn as_str(&self) -> &'static str { - match self { - SplitDebuginfo::Off => "off", - SplitDebuginfo::Packed => "packed", - SplitDebuginfo::Unpacked => "unpacked", - } - } -} - -impl FromStr for SplitDebuginfo { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "off" => SplitDebuginfo::Off, - "unpacked" => SplitDebuginfo::Unpacked, - "packed" => SplitDebuginfo::Packed, - _ => { - return Err(format!( - "'{s}' is not a valid value for \ - split-debuginfo. Use 'off', 'unpacked', or 'packed'.", - )); - } - }) - } -} - -crate::json::serde_deserialize_from_str!(SplitDebuginfo); - -impl ToJson for SplitDebuginfo { - fn to_json(&self) -> Json { - self.as_str().to_json() - } -} - -impl fmt::Display for SplitDebuginfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } + /// Useful in determining whether a target supports Split DWARF (a target with + /// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example). + #[derive(Default)] + pub enum DebuginfoKind { + /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`). + #[default] + Dwarf = "dwarf", + /// DWARF debuginfo in dSYM files (such as on Apple platforms). + DwarfDsym = "dwarf-dsym", + /// Program database files (such as on Windows). + Pdb = "pdb", + } + + parse_error_type = "debuginfo kind"; +} + +crate::target_spec_enum! { + #[derive(Default)] + pub enum SplitDebuginfo { + /// Split debug-information is disabled, meaning that on supported platforms + /// you can find all debug information in the executable itself. This is + /// only supported for ELF effectively. + /// + /// * Windows - not supported + /// * macOS - don't run `dsymutil` + /// * ELF - `.debug_*` sections + #[default] + Off = "off", + + /// Split debug-information can be found in a "packed" location separate + /// from the final artifact. This is supported on all platforms. + /// + /// * Windows - `*.pdb` + /// * macOS - `*.dSYM` (run `dsymutil`) + /// * ELF - `*.dwp` (run `thorin`) + Packed = "packed", + + /// Split debug-information can be found in individual object files on the + /// filesystem. The main executable may point to the object files. + /// + /// * Windows - not supported + /// * macOS - supported, scattered object files + /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`) + Unpacked = "unpacked", + } + + parse_error_type = "split debuginfo"; } into_diag_arg_using_display!(SplitDebuginfo); -#[derive(Clone, Debug, PartialEq, Eq, serde_derive::Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, serde_derive::Deserialize, schemars::JsonSchema)] #[serde(tag = "kind")] #[serde(rename_all = "kebab-case")] pub enum StackProbeType { @@ -1688,6 +1287,19 @@ impl FromStr for SanitizerSet { } crate::json::serde_deserialize_from_str!(SanitizerSet); +impl schemars::JsonSchema for SanitizerSet { + fn schema_name() -> std::borrow::Cow<'static, str> { + "SanitizerSet".into() + } + fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { + let all = Self::all().iter().map(|sanitizer| sanitizer.as_str()).collect::<Vec<_>>(); + schemars::json_schema! ({ + "type": "string", + "enum": all, + }) + .into() + } +} impl ToJson for SanitizerSet { fn to_json(&self) -> Json { @@ -1699,17 +1311,20 @@ impl ToJson for SanitizerSet { } } -#[derive(Clone, Copy, PartialEq, Hash, Debug)] -pub enum FramePointer { - /// Forces the machine code generator to always preserve the frame pointers. - Always, - /// Forces the machine code generator to preserve the frame pointers except for the leaf - /// functions (i.e. those that don't call other functions). - NonLeaf, - /// Allows the machine code generator to omit the frame pointers. - /// - /// This option does not guarantee that the frame pointers will be omitted. - MayOmit, +crate::target_spec_enum! { + pub enum FramePointer { + /// Forces the machine code generator to always preserve the frame pointers. + Always = "always", + /// Forces the machine code generator to preserve the frame pointers except for the leaf + /// functions (i.e. those that don't call other functions). + NonLeaf = "non-leaf", + /// Allows the machine code generator to omit the frame pointers. + /// + /// This option does not guarantee that the frame pointers will be omitted. + MayOmit = "may-omit", + } + + parse_error_type = "frame pointer"; } impl FramePointer { @@ -1726,93 +1341,43 @@ impl FramePointer { } } -impl FromStr for FramePointer { - type Err = String; - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "always" => Self::Always, - "non-leaf" => Self::NonLeaf, - "may-omit" => Self::MayOmit, - _ => return Err(format!("'{s}' is not a valid value for frame-pointer")), - }) - } -} - -crate::json::serde_deserialize_from_str!(FramePointer); - -impl ToJson for FramePointer { - fn to_json(&self) -> Json { - match *self { - Self::Always => "always", - Self::NonLeaf => "non-leaf", - Self::MayOmit => "may-omit", - } - .to_json() - } -} - -/// Controls use of stack canaries. -#[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] -pub enum StackProtector { - /// Disable stack canary generation. - None, - - /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see - /// llvm/docs/LangRef.rst). This triggers stack canary generation in - /// functions which contain an array of a byte-sized type with more than - /// eight elements. - Basic, +crate::target_spec_enum! { + /// Controls use of stack canaries. + pub enum StackProtector { + /// Disable stack canary generation. + None = "none", - /// On LLVM, mark all generated LLVM functions with the `sspstrong` - /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary - /// generation in functions which either contain an array, or which take - /// the address of a local variable. - Strong, + /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see + /// llvm/docs/LangRef.rst). This triggers stack canary generation in + /// functions which contain an array of a byte-sized type with more than + /// eight elements. + Basic = "basic", - /// Generate stack canaries in all functions. - All, -} + /// On LLVM, mark all generated LLVM functions with the `sspstrong` + /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary + /// generation in functions which either contain an array, or which take + /// the address of a local variable. + Strong = "strong", -impl StackProtector { - fn as_str(&self) -> &'static str { - match self { - StackProtector::None => "none", - StackProtector::Basic => "basic", - StackProtector::Strong => "strong", - StackProtector::All => "all", - } + /// Generate stack canaries in all functions. + All = "all", } -} -impl FromStr for StackProtector { - type Err = (); - - fn from_str(s: &str) -> Result<StackProtector, ()> { - Ok(match s { - "none" => StackProtector::None, - "basic" => StackProtector::Basic, - "strong" => StackProtector::Strong, - "all" => StackProtector::All, - _ => return Err(()), - }) - } -} - -impl fmt::Display for StackProtector { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } + parse_error_type = "stack protector"; } into_diag_arg_using_display!(StackProtector); -#[derive(PartialEq, Clone, Debug)] -pub enum BinaryFormat { - Coff, - Elf, - MachO, - Wasm, - Xcoff, +crate::target_spec_enum! { + pub enum BinaryFormat { + Coff = "coff", + Elf = "elf", + MachO = "mach-o", + Wasm = "wasm", + Xcoff = "xcoff", + } + + parse_error_type = "binary format"; } impl BinaryFormat { @@ -1828,38 +1393,6 @@ impl BinaryFormat { } } -impl FromStr for BinaryFormat { - type Err = String; - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "coff" => Ok(Self::Coff), - "elf" => Ok(Self::Elf), - "mach-o" => Ok(Self::MachO), - "wasm" => Ok(Self::Wasm), - "xcoff" => Ok(Self::Xcoff), - _ => Err(format!( - "'{s}' is not a valid value for binary_format. \ - Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' " - )), - } - } -} - -crate::json::serde_deserialize_from_str!(BinaryFormat); - -impl ToJson for BinaryFormat { - fn to_json(&self) -> Json { - match self { - Self::Coff => "coff", - Self::Elf => "elf", - Self::MachO => "mach-o", - Self::Wasm => "wasm", - Self::Xcoff => "xcoff", - } - .to_json() - } -} - impl ToJson for Align { fn to_json(&self) -> Json { self.bits().to_json() diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 4c1b8c99426..dc70089c385 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -849,6 +849,7 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]), ("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]), ("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]), + ("soft-float", Forbidden { reason: "currently unsupported ABI-configuration feature" }, &[]), ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), ("vector", Unstable(sym::s390x_target_feature), &[]), ("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]), @@ -1177,6 +1178,13 @@ impl Target { _ => unreachable!(), } } + "s390x" => { + // We don't currently support a softfloat target on this architecture. + // As usual, we have to reject swapping the `soft-float` target feature. + // The "vector" target feature does not affect the ABI for floats + // because the vector and float registers overlap. + FeatureConstraints { required: &[], incompatible: &["soft-float"] } + } _ => NOTHING, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 812e20e4338..e18e294635b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -91,7 +91,6 @@ mod suggest; pub mod need_type_info; pub mod nice_region_error; pub mod region; -pub mod sub_relations; /// Makes a valid string literal from a string by escaping special characters (" and \), /// unless they are already escaped. @@ -1617,20 +1616,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some((e, f)) = values.ty() && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr { - let e = self.tcx.erase_regions(e); - let f = self.tcx.erase_regions(f); - let mut expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); - let mut found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); - if let ObligationCauseCode::Pattern { span, .. } = cause.code() - && let Some(span) = span - && !span.from_expansion() - && cause.span.from_expansion() - { - // When the type error comes from a macro like `assert!()`, and we are pointing at - // code the user wrote the cause and effect are reversed as the expected value is - // what the macro expanded to. - (found, expected) = (expected, found); - } + let e = self.tcx.erase_and_anonymize_regions(e); + let f = self.tcx.erase_and_anonymize_regions(f); + let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx)); + let found = with_forced_trimmed_paths!(f.sort_string(self.tcx)); if expected == found { label_or_note(span, terr.to_string(self.tcx)); } else { @@ -2153,9 +2142,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => { - self.expected_found_str_term(cause, exp_found, long_ty_path) - } + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path), ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2194,7 +2181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, - cause: &ObligationCause<'tcx>, exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>, long_ty_path: &mut Option<PathBuf>, ) -> Option<(DiagStyledString, DiagStyledString)> { @@ -2202,27 +2188,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if exp_found.references_error() { return None; } - let (mut expected, mut found) = (exp_found.expected, exp_found.found); - - if let ObligationCauseCode::Pattern { span, .. } = cause.code() - && let Some(span) = span - && !span.from_expansion() - && cause.span.from_expansion() - { - // When the type error comes from a macro like `assert!()`, and we are pointing at - // code the user wrote, the cause and effect are reversed as the expected value is - // what the macro expanded to. So if the user provided a `Type` when the macro is - // written in such a way that a `bool` was expected, we want to print: - // = note: expected `bool` - // found `Type`" - // but as far as the compiler is concerned, after expansion what was expected was `Type` - // = note: expected `Type` - // found `bool`" - // so we reverse them here to match user expectation. - (expected, found) = (found, expected); - } - Some(match (expected.kind(), found.kind()) { + Some(match (exp_found.expected.kind(), exp_found.found.kind()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let (mut exp, mut fnd) = self.cmp(expected, found); // Use the terminal width as the basis to determine when to compress the printed diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index ec2287ed516..edab530590b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -894,7 +894,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { use ty::{Infer, TyVar}; match (inner_ty.kind(), target_ty.kind()) { (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => { - self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid) + self.tecx.sub_unification_table_root_var(a_vid) + == self.tecx.sub_unification_table_root_var(b_vid) } _ => false, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 40285e5d0e9..f997842a607 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -629,7 +629,11 @@ impl<T> Trait<T> for X { let tcx = self.tcx; // Don't suggest constraining a projection to something containing itself - if self.tcx.erase_regions(values.found).contains(self.tcx.erase_regions(values.expected)) { + if self + .tcx + .erase_and_anonymize_regions(values.found) + .contains(self.tcx.erase_and_anonymize_regions(values.expected)) + { return; } @@ -853,11 +857,11 @@ fn foo(&self) -> Self::T { String::new() } && self.infcx.can_eq(param_env, assoc_ty, found) { let msg = match assoc_item.container { - ty::AssocItemContainer::Trait => { + ty::AssocContainer::Trait => { "associated type defaults can't be assumed inside the \ trait defining them" } - ty::AssocItemContainer::Impl => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { "associated type is `default` and may be overridden" } }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 7369134420c..518d4fe17e8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -571,13 +571,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // but right now it's not really very smart when it comes to implicit `Sized` // predicates and bounds on the trait itself. - let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) - else { - return; - }; - let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else { + let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(impl_item_def_id.to_def_id()) else { return; }; + let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_args = trait_ref .instantiate_identity() // Replace the explicit self type with `Self` for better suggestion rendering diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs deleted file mode 100644 index ef26a8ff7b8..00000000000 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs +++ /dev/null @@ -1,81 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::undo_log::NoUndo; -use rustc_data_structures::unify as ut; -use rustc_middle::ty; - -use crate::infer::InferCtxt; - -#[derive(Debug, Copy, Clone, PartialEq)] -struct SubId(u32); -impl ut::UnifyKey for SubId { - type Value = (); - #[inline] - fn index(&self) -> u32 { - self.0 - } - #[inline] - fn from_index(i: u32) -> SubId { - SubId(i) - } - fn tag() -> &'static str { - "SubId" - } -} - -/// When reporting ambiguity errors, we sometimes want to -/// treat all inference vars which are subtypes of each -/// others as if they are equal. For this case we compute -/// the transitive closure of our subtype obligations here. -/// -/// E.g. when encountering ambiguity errors, we want to suggest -/// specifying some method argument or to add a type annotation -/// to a local variable. Because subtyping cannot change the -/// shape of a type, it's fine if the cause of the ambiguity error -/// is only related to the suggested variable via subtyping. -/// -/// Even for something like `let x = returns_arg(); x.method();` the -/// type of `x` is only a supertype of the argument of `returns_arg`. We -/// still want to suggest specifying the type of the argument. -#[derive(Default)] -pub struct SubRelations { - map: FxHashMap<ty::TyVid, SubId>, - table: ut::UnificationTableStorage<SubId>, -} - -impl SubRelations { - fn get_id<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, vid: ty::TyVid) -> SubId { - let root_vid = infcx.root_var(vid); - *self.map.entry(root_vid).or_insert_with(|| self.table.with_log(&mut NoUndo).new_key(())) - } - - pub fn add_constraints<'tcx>( - &mut self, - infcx: &InferCtxt<'tcx>, - obls: impl IntoIterator<Item = ty::Predicate<'tcx>>, - ) { - for p in obls { - let (a, b) = match p.kind().skip_binder() { - ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => { - (a, b) - } - ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => (a, b), - _ => continue, - }; - - match (a.kind(), b.kind()) { - (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { - let a = self.get_id(infcx, a_vid); - let b = self.get_id(infcx, b_vid); - self.table.with_log(&mut NoUndo).unify_var_var(a, b).unwrap(); - } - _ => continue, - } - } - } - - pub fn unified<'tcx>(&mut self, infcx: &InferCtxt<'tcx>, a: ty::TyVid, b: ty::TyVid) -> bool { - let a = self.get_id(infcx, a); - let b = self.get_id(infcx, b); - self.table.with_log(&mut NoUndo).unioned(a, b) - } -} diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs index 82695688ae8..cce20b05c79 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs @@ -7,8 +7,6 @@ use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::ty::{self, Ty}; -use crate::error_reporting::infer::sub_relations; - pub mod infer; pub mod traits; @@ -21,7 +19,6 @@ pub mod traits; /// methods which should not be used during the happy path. pub struct TypeErrCtxt<'a, 'tcx> { pub infcx: &'a InferCtxt<'tcx>, - pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>, pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>, pub fallback_has_occurred: bool, @@ -38,7 +35,6 @@ impl<'tcx> InferCtxt<'tcx> { fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { TypeErrCtxt { infcx: self, - sub_relations: Default::default(), typeck_results: None, fallback_has_occurred: false, normalize_fn_sig: Box::new(|fn_sig| fn_sig), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index 8a67e4ccd45..f54ebd76cab 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -5,7 +5,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, lang_items}; -use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; +use rustc_middle::ty::{AssocContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym}; use tracing::debug; @@ -76,8 +76,9 @@ pub fn call_kind<'tcx>( let parent = tcx.opt_associated_item(method_did).and_then(|assoc| { let container_id = assoc.container_id(tcx); match assoc.container { - AssocItemContainer::Impl => tcx.trait_id_of_impl(container_id), - AssocItemContainer::Trait => Some(container_id), + AssocContainer::InherentImpl => None, + AssocContainer::TraitImpl(_) => tcx.trait_id_of_impl(container_id), + AssocContainer::Trait => Some(container_id), } }); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index bc984f30472..149f5e638b1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -27,8 +27,8 @@ use rustc_middle::ty::print::{ with_forced_trimmed_paths, }; use rustc_middle::ty::{ - self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, - Upcast, + self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; @@ -75,7 +75,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(cause) = self .tcx - .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc)) + .diagnostic_hir_wf_check((tcx.erase_and_anonymize_regions(obligation.predicate), *wf_loc)) { obligation.cause = cause.clone(); span = obligation.cause.span; @@ -2316,7 +2316,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cand }) .collect(); - impl_candidates.sort_by_key(|cand| (cand.similarity, cand.trait_ref.to_string())); + impl_candidates.sort_by_key(|cand| { + // When suggesting array types, sort them by the length of the array, not lexicographically (#135098) + let len = if let GenericArgKind::Type(ty) = cand.trait_ref.args[0].kind() + && let ty::Array(_, len) = ty.kind() + { + // Deprioritize suggestions for parameterized arrays. + len.try_to_target_usize(self.tcx).unwrap_or(u64::MAX) + } else { + 0 + }; + + (cand.similarity, len, cand.trait_ref.to_string()) + }); let mut impl_candidates: Vec<_> = impl_candidates.into_iter().map(|cand| cand.trait_ref).collect(); impl_candidates.dedup(); @@ -2612,8 +2624,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Erase regions because layout code doesn't particularly care about regions. - let trait_pred = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred)); + let trait_pred = self.tcx.erase_and_anonymize_regions( + self.tcx.instantiate_bound_regions_with_erased(trait_pred), + ); let src_and_dst = rustc_transmute::Types { dst: trait_pred.trait_ref.args.type_at(0), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index c8500b2d9d4..f794ff632c5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -139,10 +139,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, mut errors: Vec<FulfillmentError<'tcx>>, ) -> ErrorGuaranteed { - self.sub_relations - .borrow_mut() - .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); - #[derive(Debug)] struct ErrorDescriptor<'tcx> { goal: Goal<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index 4f1f5c330e5..a0876d8fe75 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -3,10 +3,10 @@ use std::fmt; use rustc_errors::{Diag, E0275, EmissionGuarantee, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::limit::Limit; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::{self, TyCtxt, Upcast}; -use rustc_session::Limit; use rustc_span::Span; use tracing::debug; @@ -67,7 +67,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // We don't need to save the type to a file, we will be talking about this type already // in a separate note when we explain the obligation, so it will be available that way. let mut p: FmtPrinter<'_, '_> = - FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, rustc_session::Limit(6)); + FmtPrinter::new_with_limit(tcx, Namespace::TypeNS, Limit(6)); value.print(&mut p).unwrap(); p.into_buffer() } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index f6dbbeb51ca..f2f840581cf 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -421,7 +421,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | hir::Node::ImplItem(hir::ImplItem { generics, - trait_item_def_id: None, + impl_kind: hir::ImplItemImplKind::Inherent { .. }, kind: hir::ImplItemKind::Fn(..), .. }) if finder.can_suggest_bound(generics) => { @@ -2442,7 +2442,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Look for a type inside the coroutine interior that matches the target type to get // a span. - let target_ty_erased = self.tcx.erase_regions(target_ty); + let target_ty_erased = self.tcx.erase_and_anonymize_regions(target_ty); let ty_matches = |ty| -> bool { // Careful: the regions for types that appear in the // coroutine interior are not generally known, so we @@ -2454,10 +2454,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // interior generally contain "bound regions" to // represent regions that are part of the suspended // coroutine frame. Bound regions are preserved by - // `erase_regions` and so we must also call + // `erase_and_anonymize_regions` and so we must also call // `instantiate_bound_regions_with_erased`. let ty_erased = self.tcx.instantiate_bound_regions_with_erased(ty); - let ty_erased = self.tcx.erase_regions(ty_erased); + let ty_erased = self.tcx.erase_and_anonymize_regions(ty_erased); let eq = ty_erased == target_ty_erased; debug!(?ty_erased, ?target_ty_erased, ?eq); eq diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 7c6b7b14ecb..4c50c44b841 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -184,10 +184,9 @@ impl<'tcx> InferCtxtBuilder<'tcx> { R: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { - let (infcx, key, canonical_inference_vars) = - self.build_with_canonical(DUMMY_SP, canonical_key); + let (infcx, key, var_values) = self.build_with_canonical(DUMMY_SP, canonical_key); let ocx = ObligationCtxt::new(&infcx); let value = operation(&ocx, key)?; - ocx.make_canonicalized_query_response(canonical_inference_vars, value) + ocx.make_canonicalized_query_response(var_values, value) } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e6a2761db5a..b6bdf1067a3 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -126,13 +126,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. }) | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { - if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { - // FIXME: We also need to register a subtype relation between these vars - // when those are added, and if they aren't in the same sub root then - // we should mark this goal as `has_changed`. - Some(Certainty::AMBIGUOUS) - } else { - None + match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) { + (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { + self.sub_unify_ty_vids_raw(a_vid, b_vid); + Some(Certainty::AMBIGUOUS) + } + _ => None, } } ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => { @@ -238,13 +237,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< canonical.instantiate(self.tcx, &values) } - fn instantiate_canonical_var_with_infer( + fn instantiate_canonical_var( &self, kind: CanonicalVarKind<'tcx>, span: Span, + var_values: &[ty::GenericArg<'tcx>], universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, ) -> ty::GenericArg<'tcx> { - self.0.instantiate_canonical_var(span, kind, universe_map) + self.0.instantiate_canonical_var(span, kind, var_values, universe_map) } fn add_item_bounds_for_hidden_type( @@ -300,7 +300,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> Result<Certainty, NoSolution> { // Erase regions because we compute layouts in `rustc_transmute`, // which will ICE for region vars. - let (dst, src) = self.tcx.erase_regions((dst, src)); + let (dst, src) = self.tcx.erase_and_anonymize_regions((dst, src)); let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else { return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 4b493c95d59..bcd11d6918d 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -759,7 +759,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { )), ) .map(|trait_ref| { - self.tcx.erase_regions( + self.tcx.erase_and_anonymize_regions( self.tcx.instantiate_bound_regions_with_erased(trait_ref), ) }) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a9fb16b8000..6fefac43699 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -576,7 +576,7 @@ pub fn try_evaluate_const<'tcx>( let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args); let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (args, typing_env) } @@ -589,7 +589,7 @@ pub fn try_evaluate_const<'tcx>( } } else { let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) } @@ -634,14 +634,14 @@ pub fn try_evaluate_const<'tcx>( } let typing_env = infcx - .typing_env(tcx.erase_regions(param_env)) + .typing_env(tcx.erase_and_anonymize_regions(param_env)) .with_post_analysis_normalized(tcx); (uv.args, typing_env) } }; let uv = ty::UnevaluatedConst::new(uv.def, args); - let erased_uv = tcx.erase_regions(uv); + let erased_uv = tcx.erase_and_anonymize_regions(uv); use rustc_middle::mir::interpret::ErrorHandled; // FIXME: `def_span` will point at the definition of this const; ideally, we'd point at diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index de404532899..945ca7c3775 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -350,7 +350,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // Note that we don't care about whether the resume type has any drops since this is // redundant; there is no storage for the resume type, so if it is actually stored // in the interior, we'll already detect the need for a drop by checking the interior. - let typing_env = tcx.erase_regions(typing_env); + // + // FIXME(@lcnr): Why do we erase regions in the env here? Seems odd + let typing_env = tcx.erase_and_anonymize_regions(typing_env); let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| { witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env)) }); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 19eb85506b6..4d0465777dd 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -387,7 +387,7 @@ pub(crate) fn assoc_def( if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) { // Ensure that the impl is constrained, otherwise projection may give us // bad unconstrained infer vars. - if assoc_item.item.container == ty::AssocItemContainer::Impl + if let ty::AssocContainer::TraitImpl(_) = assoc_item.item.container && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local() { tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 7dd3c59edd0..4b05e2cc381 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -73,7 +73,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( } let impl_source = infcx.resolve_vars_if_possible(impl_source); - let impl_source = tcx.erase_regions(impl_source); + let impl_source = tcx.erase_and_anonymize_regions(impl_source); if impl_source.has_non_region_infer() { // Unused generic types or consts on an impl get replaced with inference vars, // but never resolved, causing the return value of a query to contain inference diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index 819b8e3231c..8f72bdf0972 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -19,7 +19,7 @@ fn evaluate_obligation<'tcx>( ) -> Result<EvaluationResult, OverflowError> { assert!(!tcx.next_trait_solver_globally()); debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal); - let (ref infcx, goal, _canonical_inference_vars) = + let (ref infcx, goal, _var_values) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); debug!("evaluate_obligation: goal={:#?}", goal); let ParamEnvAnd { param_env, value: predicate } = goal; diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index c1b848a2e79..c98b56abe9c 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -41,7 +41,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par // fresh `InferCtxt`. If this assert does trigger, it will give // us a test case. debug_assert_eq!(normalized_value, resolved_value); - let erased = infcx.tcx.erase_regions(resolved_value); + let erased = infcx.tcx.erase_and_anonymize_regions(resolved_value); debug_assert!(!erased.has_infer(), "{erased:?}"); Ok(erased) } diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index acbce258f39..4e548ff8fe2 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -163,7 +163,7 @@ pub mod rustc { ty: Ty<'tcx>, ) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> { use rustc_middle::ty::layout::LayoutOf; - let ty = cx.tcx().erase_regions(ty); + let ty = cx.tcx().erase_and_anonymize_regions(ty); cx.layout_of(ty).map(|tl| tl.layout) } } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 3f83b4d50aa..d7ea26a2ab1 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -426,24 +426,23 @@ pub(crate) mod rustc { assert!(def.is_enum()); // Computes the layout of a variant. - let layout_of_variant = - |index, encoding: Option<TagEncoding<VariantIdx>>| -> Result<Self, Err> { - let variant_layout = ty_variant(cx, (ty, layout), index); - if variant_layout.is_uninhabited() { - return Ok(Self::uninhabited()); - } - let tag = cx.tcx().tag_for_variant( - cx.typing_env.as_query_input((cx.tcx().erase_regions(ty), index)), - ); - let variant_def = Def::Variant(def.variant(index)); - Self::from_variant( - variant_def, - tag.map(|tag| (tag, index, encoding.unwrap())), - (ty, variant_layout), - layout.size, - cx, - ) - }; + let layout_of_variant = |index, encoding: Option<_>| -> Result<Self, Err> { + let variant_layout = ty_variant(cx, (ty, layout), index); + if variant_layout.is_uninhabited() { + return Ok(Self::uninhabited()); + } + let tag = cx.tcx().tag_for_variant( + cx.typing_env.as_query_input((cx.tcx().erase_and_anonymize_regions(ty), index)), + ); + let variant_def = Def::Variant(def.variant(index)); + Self::from_variant( + variant_def, + tag.map(|tag| (tag, index, encoding.unwrap())), + (ty, variant_layout), + layout.size, + cx, + ) + }; match layout.variants() { Variants::Empty => Ok(Self::uninhabited()), @@ -634,7 +633,7 @@ pub(crate) mod rustc { (ty, layout): (Ty<'tcx>, Layout<'tcx>), i: VariantIdx, ) -> Layout<'tcx> { - let ty = cx.tcx().erase_regions(ty); + let ty = cx.tcx().erase_and_anonymize_regions(ty); TyAndLayout { ty, layout }.for_variant(&cx, i).layout } } diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index e9629e31482..84f52e7fc9d 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, ItemKind}; +use rustc_hir::{self as hir, ImplItemImplKind, ItemKind}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -63,7 +63,7 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems { fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> { tcx.associated_items(impl_id) .in_definition_order() - .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id))) + .filter_map(|item| item.trait_item_def_id().map(|trait_item| (trait_item, item.def_id))) .collect() } @@ -97,12 +97,7 @@ fn associated_item_from_trait_item( } }; - ty::AssocItem { - kind, - def_id: owner_id.to_def_id(), - trait_item_def_id: Some(owner_id.to_def_id()), - container: ty::AssocItemContainer::Trait, - } + ty::AssocItem { kind, def_id: owner_id.to_def_id(), container: ty::AssocContainer::Trait } } fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem { @@ -118,12 +113,13 @@ fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_> } }; - ty::AssocItem { - kind, - def_id: owner_id.to_def_id(), - trait_item_def_id: impl_item.trait_item_def_id, - container: ty::AssocItemContainer::Impl, - } + let container = match impl_item.impl_kind { + ImplItemImplKind::Inherent { .. } => ty::AssocContainer::InherentImpl, + ImplItemImplKind::Trait { trait_item_def_id, .. } => { + ty::AssocContainer::TraitImpl(trait_item_def_id) + } + }; + ty::AssocItem { kind, def_id: owner_id.to_def_id(), container } } struct RPITVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -190,7 +186,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>( } let did = item.owner_id.def_id.to_def_id(); let item = tcx.hir_impl_item(*item); - let Some(trait_item_def_id) = item.trait_item_def_id else { + let ImplItemImplKind::Trait { + trait_item_def_id: Ok(trait_item_def_id), .. + } = item.impl_kind + else { return Some((did, vec![])); }; let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| { @@ -256,8 +255,7 @@ fn associated_type_for_impl_trait_in_trait( }), }, def_id, - trait_item_def_id: None, - container: ty::AssocItemContainer::Trait, + container: ty::AssocContainer::Trait, }); // Copy visility of the containing function. @@ -322,8 +320,7 @@ fn associated_type_for_impl_trait_in_impl( }), }, def_id, - trait_item_def_id: Some(trait_assoc_def_id), - container: ty::AssocItemContainer::Impl, + container: ty::AssocContainer::TraitImpl(Ok(trait_assoc_def_id)), }); // Copy visility of the containing function. diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index cdfb93c4e7d..543f6a3ccf7 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -107,7 +107,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' // the assumed wf types of the trait's RPITIT GAT. ty::ImplTraitInTraitData::Impl { .. } => { let impl_def_id = tcx.local_parent(def_id); - let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap(); + let rpitit_def_id = tcx.trait_item_of(def_id).unwrap(); let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto( tcx, impl_def_id.to_def_id(), diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 5c3f7d491a5..e28ebaabc0a 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -176,7 +176,7 @@ fn resolve_associated_item<'tcx>( args, leaf_def.defining_node, ); - let args = infcx.tcx.erase_regions(args); + let args = infcx.tcx.erase_and_anonymize_regions(args); // HACK: We may have overlapping `dyn Trait` built-in impls and // user-provided blanket impls. Detect that case here, and return @@ -222,7 +222,7 @@ fn resolve_associated_item<'tcx>( return Err(guar); } - let args = tcx.erase_regions(args); + let args = tcx.erase_and_anonymize_regions(args); // We check that the impl item is compatible with the trait item // because otherwise we may ICE in const eval due to type mismatches, @@ -279,7 +279,7 @@ fn resolve_associated_item<'tcx>( assert_eq!(name, sym::clone_from); // Use the default `fn clone_from` from `trait Clone`. - let args = tcx.erase_regions(rcvr_args); + let args = tcx.erase_and_anonymize_regions(rcvr_args); Some(ty::Instance::new_raw(trait_item_id, args)) } } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { @@ -380,7 +380,7 @@ fn resolve_associated_item<'tcx>( } else if tcx.is_lang_item(trait_ref.def_id, LangItem::TransmuteTrait) { let name = tcx.item_name(trait_item_id); assert_eq!(name, sym::transmute); - let args = tcx.erase_regions(rcvr_args); + let args = tcx.erase_and_anonymize_regions(rcvr_args); Some(ty::Instance::new_raw(trait_item_id, args)) } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 13d56889bd1..0ef435b1a0e 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -2,11 +2,11 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; +use rustc_hir::limit::Limit; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::util::{AlwaysRequiresDrop, needs_drop_components}; use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt}; -use rustc_session::Limit; use rustc_span::sym; use tracing::{debug, instrument}; diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 4a7263d0ccd..eb3236d3006 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -245,7 +245,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { for &assoc in self.tcx.associated_items(parent).in_definition_order() { trace!(?assoc); - if assoc.trait_item_def_id != Some(alias_ty.def_id) { + if assoc.expect_trait_impl() != Ok(alias_ty.def_id) { continue; } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index b22c326b9f2..a5987757dc3 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -88,7 +88,10 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness { }), .. }) - | hir::Node::ImplItem(hir::ImplItem { defaultness, .. }) + | hir::Node::ImplItem(hir::ImplItem { + impl_kind: hir::ImplItemImplKind::Trait { defaultness, .. }, + .. + }) | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness, node => { bug!("`defaultness` called on {:?}", node); @@ -165,7 +168,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { if tcx.def_kind(def_id) == DefKind::AssocFn && let assoc_item = tcx.associated_item(def_id) - && assoc_item.container == ty::AssocItemContainer::Trait + && assoc_item.container == ty::AssocContainer::Trait && assoc_item.defaultness(tcx).has_value() { let sig = tcx.fn_sig(def_id).instantiate_identity(); diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index d55e9b3b1be..6ccddb17ff2 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" derive-where = "1.2.7" ena = "0.14.3" diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index de2a9186e7c..ecf3ae4f8b2 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,7 +1,7 @@ use std::fmt; -use std::hash::Hash; use std::ops::Index; +use arrayvec::ArrayVec; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; @@ -91,8 +91,18 @@ impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> { derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) )] pub enum CanonicalVarKind<I: Interner> { - /// Some kind of type inference variable. - Ty(CanonicalTyVarKind), + /// General type variable `?T` that can be unified with arbitrary types. + /// + /// We also store the index of the first type variable which is sub-unified + /// with this one. If there is no inference variable related to this one, + /// its `sub_root` just points to itself. + Ty { ui: UniverseIndex, sub_root: ty::BoundVar }, + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, /// A "placeholder" that represents "any type". PlaceholderTy(I::PlaceholderTy), @@ -117,15 +127,13 @@ impl<I: Interner> Eq for CanonicalVarKind<I> {} impl<I: Interner> CanonicalVarKind<I> { pub fn universe(self) -> UniverseIndex { match self { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui, + CanonicalVarKind::Ty { ui, sub_root: _ } => ui, CanonicalVarKind::Region(ui) => ui, CanonicalVarKind::Const(ui) => ui, CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(), CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(), - CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { - UniverseIndex::ROOT - } + CanonicalVarKind::Float | CanonicalVarKind::Int => UniverseIndex::ROOT, } } @@ -135,9 +143,7 @@ impl<I: Interner> CanonicalVarKind<I> { /// the updated universe is not the root. pub fn with_updated_universe(self, ui: UniverseIndex) -> CanonicalVarKind<I> { match self { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(_)) => { - CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) - } + CanonicalVarKind::Ty { ui: _, sub_root } => CanonicalVarKind::Ty { ui, sub_root }, CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui), @@ -150,7 +156,7 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::PlaceholderConst(placeholder) => { CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui)) } - CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => { + CanonicalVarKind::Int | CanonicalVarKind::Float => { assert_eq!(ui, UniverseIndex::ROOT); self } @@ -159,19 +165,23 @@ impl<I: Interner> CanonicalVarKind<I> { pub fn is_existential(self) -> bool { match self { - CanonicalVarKind::Ty(_) => true, - CanonicalVarKind::PlaceholderTy(_) => false, - CanonicalVarKind::Region(_) => true, - CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(_) => true, - CanonicalVarKind::PlaceholderConst(_) => false, + CanonicalVarKind::Ty { .. } + | CanonicalVarKind::Int + | CanonicalVarKind::Float + | CanonicalVarKind::Region(_) + | CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::PlaceholderRegion(..) + | CanonicalVarKind::PlaceholderConst(_) => false, } } pub fn is_region(self) -> bool { match self { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, - CanonicalVarKind::Ty(_) + CanonicalVarKind::Ty { .. } + | CanonicalVarKind::Int + | CanonicalVarKind::Float | CanonicalVarKind::PlaceholderTy(_) | CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => false, @@ -180,7 +190,11 @@ impl<I: Interner> CanonicalVarKind<I> { pub fn expect_placeholder_index(self) -> usize { match self { - CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) | CanonicalVarKind::Const(_) => { + CanonicalVarKind::Ty { .. } + | CanonicalVarKind::Int + | CanonicalVarKind::Float + | CanonicalVarKind::Region(_) + | CanonicalVarKind::Const(_) => { panic!("expected placeholder: {self:?}") } @@ -191,27 +205,6 @@ impl<I: Interner> CanonicalVarKind<I> { } } -/// Rust actually has more than one category of type variables; -/// notably, the type variables we create for literals (e.g., 22 or -/// 22.) can only be instantiated with integral/float types (e.g., -/// usize or f32). In order to faithfully reproduce a type, we need to -/// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -pub enum CanonicalTyVarKind { - /// General type variable `?T` that can be unified with arbitrary types. - General(UniverseIndex), - - /// Integral type variable `?I` (that can only be unified with integral types). - Int, - - /// Floating-point type variable `?F` (that can only be unified with float types). - Float, -} - /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to /// `canonical_value.instantiate` to instantiate them into the canonical @@ -287,7 +280,10 @@ impl<I: Interner> CanonicalVarValues<I> { var_values: cx.mk_args_from_iter(infos.iter().enumerate().map( |(i, kind)| -> I::GenericArg { match kind { - CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { + CanonicalVarKind::Ty { .. } + | CanonicalVarKind::Int + | CanonicalVarKind::Float + | CanonicalVarKind::PlaceholderTy(_) => { Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } @@ -311,6 +307,37 @@ impl<I: Interner> CanonicalVarValues<I> { CanonicalVarValues { var_values: Default::default() } } + pub fn instantiate( + cx: I, + variables: I::CanonicalVarKinds, + mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg, + ) -> CanonicalVarValues<I> { + // Instantiating `CanonicalVarValues` is really hot, but limited to less than + // 4 most of the time. Avoid creating a `Vec` here. + if variables.len() <= 4 { + let mut var_values = ArrayVec::<_, 4>::new(); + for info in variables.iter() { + var_values.push(f(&var_values, info)); + } + CanonicalVarValues { var_values: cx.mk_args(&var_values) } + } else { + CanonicalVarValues::instantiate_cold(cx, variables, f) + } + } + + #[cold] + fn instantiate_cold( + cx: I, + variables: I::CanonicalVarKinds, + mut f: impl FnMut(&[I::GenericArg], CanonicalVarKind<I>) -> I::GenericArg, + ) -> CanonicalVarValues<I> { + let mut var_values = Vec::with_capacity(variables.len()); + for info in variables.iter() { + var_values.push(f(&var_values, info)); + } + CanonicalVarValues { var_values: cx.mk_args(&var_values) } + } + #[inline] pub fn len(&self) -> usize { self.var_values.len() diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 5a05630e1bd..ed6416a7f55 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -122,7 +122,7 @@ pub fn simplify_type<I: Interner>( ty::Int(int_type) => Some(SimplifiedType::Int(int_type)), ty::Uint(uint_type) => Some(SimplifiedType::Uint(uint_type)), ty::Float(float_type) => Some(SimplifiedType::Float(float_type)), - ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id())), + ty::Adt(def, _) => Some(SimplifiedType::Adt(def.def_id().into())), ty::Str => Some(SimplifiedType::Str), ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), @@ -135,11 +135,11 @@ pub fn simplify_type<I: Interner>( _ => Some(SimplifiedType::MarkerTraitObject), }, ty::Ref(_, _, mutbl) => Some(SimplifiedType::Ref(mutbl)), - ty::FnDef(def_id, _) | ty::Closure(def_id, _) | ty::CoroutineClosure(def_id, _) => { - Some(SimplifiedType::Closure(def_id)) - } - ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id)), - ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id)), + ty::FnDef(def_id, _) => Some(SimplifiedType::Closure(def_id.into())), + ty::Closure(def_id, _) => Some(SimplifiedType::Closure(def_id.into())), + ty::CoroutineClosure(def_id, _) => Some(SimplifiedType::Closure(def_id.into())), + ty::Coroutine(def_id, _) => Some(SimplifiedType::Coroutine(def_id.into())), + ty::CoroutineWitness(def_id, _) => Some(SimplifiedType::CoroutineWitness(def_id.into())), ty::Never => Some(SimplifiedType::Never), ty::Tuple(tys) => Some(SimplifiedType::Tuple(tys.len())), ty::FnPtr(sig_tys, _hdr) => { @@ -161,7 +161,7 @@ pub fn simplify_type<I: Interner>( } TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None, }, - ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), + ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id.into())), ty::Error(_) => Some(SimplifiedType::Error), ty::Bound(..) | ty::Infer(_) => None, } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index b4462294700..56962b4597b 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -158,6 +158,7 @@ pub trait InferCtxtLike: Sized { fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>; fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid; fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty; @@ -197,6 +198,7 @@ pub trait InferCtxtLike: Sized { ) -> U; fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid); + fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid); fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid); fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 64063b1a365..ecfc05a6e20 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -74,7 +74,7 @@ pub trait Ty<I: Interner<Ty = Self>>: fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; - fn new_foreign(interner: I, def_id: I::DefId) -> Self; + fn new_foreign(interner: I, def_id: I::ForeignId) -> Self; fn new_dynamic( interner: I, @@ -83,17 +83,21 @@ pub trait Ty<I: Interner<Ty = Self>>: kind: ty::DynKind, ) -> Self; - fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self; - fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine_closure( + interner: I, + def_id: I::CoroutineClosureId, + args: I::GenericArgs, + ) -> Self; - fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_closure(interner: I, def_id: I::ClosureId, args: I::GenericArgs) -> Self; - fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine_witness(interner: I, def_id: I::CoroutineId, args: I::GenericArgs) -> Self; fn new_coroutine_witness_for_coroutine( interner: I, - def_id: I::DefId, + def_id: I::CoroutineId, coroutine_args: I::GenericArgs, ) -> Self; @@ -112,7 +116,7 @@ pub trait Ty<I: Interner<Ty = Self>>: It: Iterator<Item = T>, T: CollectAndApply<Self, Self>; - fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_fn_def(interner: I, def_id: I::FunctionId, args: I::GenericArgs) -> Self; fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self; @@ -599,7 +603,7 @@ pub trait ParamLike: Copy + Debug + Hash + Eq { } pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq { - fn def_id(self) -> I::DefId; + fn def_id(self) -> I::AdtId; fn is_struct(self) -> bool; @@ -646,6 +650,16 @@ pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> { fn as_local(self) -> Option<I::LocalDefId>; } +pub trait SpecificDefId<I: Interner>: + DefId<I> + Into<I::DefId> + TryFrom<I::DefId, Error: std::fmt::Debug> +{ +} + +impl<I: Interner, T: DefId<I> + Into<I::DefId> + TryFrom<I::DefId, Error: std::fmt::Debug>> + SpecificDefId<I> for T +{ +} + pub trait BoundExistentialPredicates<I: Interner>: Copy + Debug + Hash + Eq + Relate<I> + SliceLike<Item = ty::Binder<I, ty::ExistentialPredicate<I>>> { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 3355c0c2104..cf58aec14a6 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -9,7 +9,7 @@ use rustc_index::bit_set::DenseBitSet; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; -use crate::lang_items::{SolverLangItem, SolverTraitLangItem}; +use crate::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; use crate::solve::{ CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, inspect, @@ -41,13 +41,20 @@ pub trait Interner: type DefId: DefId<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; - /// A `DefId` of a trait. - /// - /// In rustc this is just a `DefId`, but rust-analyzer uses different types for different items. - /// - /// Note: The `TryFrom<DefId>` always succeeds (in rustc), so don't use it to check if some `DefId` - /// is a trait! - type TraitId: DefId<Self> + Into<Self::DefId> + TryFrom<Self::DefId, Error: std::fmt::Debug>; + // Various more specific `DefId`s. + // + // rustc just defines them all to be `DefId`, but rust-analyzer uses different types so this is convenient for it. + // + // Note: The `TryFrom<DefId>` always succeeds (in rustc), so don't use it to check if some `DefId` + // is of some specific type! + type TraitId: SpecificDefId<Self>; + type ForeignId: SpecificDefId<Self>; + type FunctionId: SpecificDefId<Self>; + type ClosureId: SpecificDefId<Self>; + type CoroutineClosureId: SpecificDefId<Self>; + type CoroutineId: SpecificDefId<Self>; + type AdtId: SpecificDefId<Self>; + type ImplId: SpecificDefId<Self>; type Span: Span<Self>; type GenericArgs: GenericArgs<Self>; @@ -199,7 +206,7 @@ pub trait Interner: -> ty::EarlyBinder<Self, Self::Ty>; type AdtDef: AdtDef<Self>; - fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; + fn adt_def(self, adt_def_id: Self::AdtId) -> Self::AdtDef; fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind; @@ -240,17 +247,17 @@ pub trait Interner: fn coroutine_hidden_types( self, - def_id: Self::DefId, + def_id: Self::CoroutineId, ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::CoroutineWitnessTypes<Self>>>; fn fn_sig( self, - def_id: Self::DefId, + def_id: Self::FunctionId, ) -> ty::EarlyBinder<Self, ty::Binder<Self, ty::FnSig<Self>>>; - fn coroutine_movability(self, def_id: Self::DefId) -> Movability; + fn coroutine_movability(self, def_id: Self::CoroutineId) -> Movability; - fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId; + fn coroutine_for_closure(self, def_id: Self::CoroutineClosureId) -> Self::CoroutineId; fn generics_require_sized_self(self, def_id: Self::DefId) -> bool; @@ -293,11 +300,11 @@ pub trait Interner: /// and filtering them to the outlives predicates. This is purely for performance. fn impl_super_outlives( self, - impl_def_id: Self::DefId, + impl_def_id: Self::ImplId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; - fn impl_is_const(self, def_id: Self::DefId) -> bool; - fn fn_is_const(self, def_id: Self::DefId) -> bool; + fn impl_is_const(self, def_id: Self::ImplId) -> bool; + fn fn_is_const(self, def_id: Self::FunctionId) -> bool; fn alias_has_const_conditions(self, def_id: Self::DefId) -> bool; fn const_conditions( self, @@ -308,42 +315,50 @@ pub trait Interner: def_id: Self::DefId, ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>; - fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool; + fn impl_self_is_guaranteed_unsized(self, def_id: Self::ImplId) -> bool; - fn has_target_features(self, def_id: Self::DefId) -> bool; + fn has_target_features(self, def_id: Self::FunctionId) -> bool; fn require_lang_item(self, lang_item: SolverLangItem) -> Self::DefId; fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> Self::TraitId; + fn require_adt_lang_item(self, lang_item: SolverAdtLangItem) -> Self::AdtId; + fn is_lang_item(self, def_id: Self::DefId, lang_item: SolverLangItem) -> bool; fn is_trait_lang_item(self, def_id: Self::TraitId, lang_item: SolverTraitLangItem) -> bool; + fn is_adt_lang_item(self, def_id: Self::AdtId, lang_item: SolverAdtLangItem) -> bool; + fn is_default_trait(self, def_id: Self::TraitId) -> bool; fn as_lang_item(self, def_id: Self::DefId) -> Option<SolverLangItem>; fn as_trait_lang_item(self, def_id: Self::TraitId) -> Option<SolverTraitLangItem>; + fn as_adt_lang_item(self, def_id: Self::AdtId) -> Option<SolverAdtLangItem>; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>; fn for_each_relevant_impl( self, trait_def_id: Self::TraitId, self_ty: Self::Ty, - f: impl FnMut(Self::DefId), + f: impl FnMut(Self::ImplId), ); + fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId)); fn has_item_definition(self, def_id: Self::DefId) -> bool; - fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool; + fn impl_specializes(self, impl_def_id: Self::ImplId, victim_def_id: Self::ImplId) -> bool; - fn impl_is_default(self, impl_def_id: Self::DefId) -> bool; + fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool; - fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>; + fn impl_trait_ref(self, impl_def_id: Self::ImplId) + -> ty::EarlyBinder<Self, ty::TraitRef<Self>>; - fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity; + fn impl_polarity(self, impl_def_id: Self::ImplId) -> ty::ImplPolarity; fn trait_is_auto(self, trait_def_id: Self::TraitId) -> bool; @@ -364,13 +379,13 @@ pub trait Interner: fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; - fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; - fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool; - fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; - fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; + fn is_general_coroutine(self, coroutine_def_id: Self::CoroutineId) -> bool; + fn coroutine_is_async(self, coroutine_def_id: Self::CoroutineId) -> bool; + fn coroutine_is_gen(self, coroutine_def_id: Self::CoroutineId) -> bool; + fn coroutine_is_async_gen(self, coroutine_def_id: Self::CoroutineId) -> bool; type UnsizingParams: Deref<Target = DenseBitSet<u32>>; - fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; + fn unsizing_params_for_adt(self, adt_def_id: Self::AdtId) -> Self::UnsizingParams; fn anonymize_bound_vars<T: TypeFoldable<Self>>( self, diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 31f8f5be588..5f503d8b912 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -11,6 +11,11 @@ pub enum SolverLangItem { DynMetadata, FutureOutput, Metadata, + // tidy-alphabetical-end +} + +pub enum SolverAdtLangItem { + // tidy-alphabetical-start Option, Poll, // tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 223230fde9e..690a5f65e08 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -405,7 +405,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( Ok(if a_args.is_empty() { a } else { - let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; + let args = relation.relate_item_args(a_def.def_id().into(), a_args, b_args)?; if args == a_args { a } else { Ty::new_adt(cx, a_def, args) } }) } @@ -524,7 +524,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( Ok(if a_args.is_empty() { a } else { - let args = relation.relate_item_args(a_def_id, a_args, b_args)?; + let args = relation.relate_item_args(a_def_id.into(), a_args, b_args)?; if args == a_args { a } else { Ty::new_fn_def(cx, a_def_id, args) } }) } diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index dbbc0c217d7..8f8f019510f 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -1262,7 +1262,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); - // If the current goal is not the root of a cycle, we are done. + // If the current goal is not a cycle head, we are done. // // There are no provisional cache entries which depend on this goal. let Some(usages) = stack_entry.usages else { @@ -1278,7 +1278,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> { // // Check whether we reached a fixpoint, either because the final result // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the + // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usages, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 3fd8e2bd16e..8348666be41 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -13,7 +13,7 @@ rustc_index::newtype_index! { pub(super) struct StackDepth {} } -/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// Stack entries of the evaluation stack. Its fields tend to be lazily updated /// when popping a child goal or completely immutable. #[derive_where(Debug; X: Cx)] pub(super) struct StackEntry<X: Cx> { @@ -42,7 +42,7 @@ pub(super) struct StackEntry<X: Cx> { /// Whether evaluating this goal encountered overflow. Lazily updated. pub encountered_overflow: bool, - /// Whether and how this goal has been used as the root of a cycle. Lazily updated. + /// Whether and how this goal has been used as a cycle head. Lazily updated. pub usages: Option<HeadUsages>, /// We want to be able to ignore head usages if they happen inside of candidates diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index b6d362d77c4..b48a8f46ebe 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -136,7 +136,7 @@ pub enum CandidateSource<I: Interner> { /// let y = x.clone(); /// } /// ``` - Impl(I::DefId), + Impl(I::ImplId), /// A builtin impl generated by the compiler. When adding a new special /// trait, try to use actual impls whenever possible. Builtin impls should /// only be used in cases where the impl cannot be manually be written. diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index bde506ffd93..225d85f79c3 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -101,7 +101,7 @@ pub enum TyKind<I: Interner> { Adt(I::AdtDef, I::GenericArgs), /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. - Foreign(I::DefId), + Foreign(I::ForeignId), /// The pointee of a string slice. Written as `str`. Str, @@ -137,7 +137,7 @@ pub enum TyKind<I: Interner> { /// fn foo() -> i32 { 1 } /// let bar = foo; // bar: fn() -> i32 {foo} /// ``` - FnDef(I::DefId, I::GenericArgs), + FnDef(I::FunctionId, I::GenericArgs), /// A pointer to a function. Written as `fn() -> i32`. /// @@ -172,21 +172,21 @@ pub enum TyKind<I: Interner> { /// Closure args contain both the - potentially instantiated - generic parameters /// of its parent and some synthetic parameters. See the documentation for /// `ClosureArgs` for more details. - Closure(I::DefId, I::GenericArgs), + Closure(I::ClosureId, I::GenericArgs), /// The anonymous type of a closure. Used to represent the type of `async |a| a`. /// /// Coroutine-closure args contain both the - potentially instantiated - generic /// parameters of its parent and some synthetic parameters. See the documentation /// for `CoroutineClosureArgs` for more details. - CoroutineClosure(I::DefId, I::GenericArgs), + CoroutineClosure(I::CoroutineClosureId, I::GenericArgs), /// The anonymous type of a coroutine. Used to represent the type of /// `|a| yield a`. /// /// For more info about coroutine args, visit the documentation for /// `CoroutineArgs`. - Coroutine(I::DefId, I::GenericArgs), + Coroutine(I::CoroutineId, I::GenericArgs), /// A type representing the types stored inside a coroutine. /// This should only appear as part of the `CoroutineArgs`. @@ -211,7 +211,7 @@ pub enum TyKind<I: Interner> { /// } /// # ; /// ``` - CoroutineWitness(I::DefId, I::GenericArgs), + CoroutineWitness(I::CoroutineId, I::GenericArgs), /// The never type `!`. Never, diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index a2e16d917a9..3a6d1acfa8d 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -391,7 +391,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { cx: I, parent_args: I::GenericArgsSlice, coroutine_kind_ty: I::Ty, - coroutine_def_id: I::DefId, + coroutine_def_id: I::CoroutineId, tupled_upvars_ty: I::Ty, ) -> I::Ty { let coroutine_args = ty::CoroutineArgs::new( @@ -418,7 +418,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { self, cx: I, parent_args: I::GenericArgsSlice, - coroutine_def_id: I::DefId, + coroutine_def_id: I::CoroutineId, goal_kind: ty::ClosureKind, env_region: I::Region, closure_tupled_upvars_ty: I::Ty, diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 5104484e9c4..6e62e1031a9 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -398,9 +398,9 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { // looks, particular for `Ty`/`Predicate` where it's just a field access. // // N.B. The only case where this isn't totally true is binders, which also -// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that +// add `HAS_BINDER_VARS` flag depending on the *bound variables* that // are present, regardless of whether those bound variables are used. This -// is important for anonymization of binders in `TyCtxt::erase_regions`. We +// is important for anonymization of binders in `TyCtxt::erase_and_anonymize_regions`. We // specifically detect this case in `visit_binder`. impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { type Result = ControlFlow<FoundFlags>; diff --git a/compiler/rustc_windows_rc/Cargo.toml b/compiler/rustc_windows_rc/Cargo.toml new file mode 100644 index 00000000000..080acd35c38 --- /dev/null +++ b/compiler/rustc_windows_rc/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rustc_windows_rc" +version = "0.0.0" +edition = "2024" + +[dependencies] +#tidy-alphabetical-start +# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version +# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_codegen_ssa`. +cc = "=1.2.16" +#tidy-alphabetical-end diff --git a/compiler/rustc_windows_rc/rustc.rc.in b/compiler/rustc_windows_rc/rustc.rc.in new file mode 100644 index 00000000000..10a00b9bd4e --- /dev/null +++ b/compiler/rustc_windows_rc/rustc.rc.in @@ -0,0 +1,40 @@ +// A template for the rustc_driver and rustc Windows resource files. +// This file is processed by the build script to produce rustc.rc and rustc_driver.rc +// with the appropriate version information filled in. + +// All the strings are in UTF-8 +#pragma code_page(65001) + +#define RUSTC_FILEDESCRIPTION_STR "@RUSTC_FILEDESCRIPTION_STR@" +#define RUSTC_FILETYPE @RUSTC_FILETYPE@ +#define RUSTC_FILEVERSION_QUAD @RUSTC_FILEVERSION_QUAD@ +#define RUSTC_FILEVERSION_STR "@RUSTC_FILEVERSION_STR@" + +#define RUSTC_PRODUCTNAME_STR "@RUSTC_PRODUCTNAME_STR@" +#define RUSTC_PRODUCTVERSION_QUAD @RUSTC_PRODUCTVERSION_QUAD@ +#define RUSTC_PRODUCTVERSION_STR "@RUSTC_PRODUCTVERSION_STR@" + + +1 VERSIONINFO +FILEVERSION RUSTC_FILEVERSION_QUAD +PRODUCTVERSION RUSTC_PRODUCTVERSION_QUAD +FILEOS 0x00040004 +FILETYPE RUSTC_FILETYPE +FILESUBTYPE 0 +FILEFLAGSMASK 0x3f +FILEFLAGS 0x0 +{ + BLOCK "StringFileInfo" + { + BLOCK "000004b0" + { + VALUE "FileDescription", RUSTC_FILEDESCRIPTION_STR + VALUE "FileVersion", RUSTC_FILEVERSION_STR + VALUE "ProductVersion", RUSTC_PRODUCTVERSION_STR + VALUE "ProductName", RUSTC_PRODUCTNAME_STR + } + } + BLOCK "VarFileInfo" { + VALUE "Translation", 0x0, 0x04b0 + } +} diff --git a/compiler/rustc_windows_rc/src/lib.rs b/compiler/rustc_windows_rc/src/lib.rs new file mode 100644 index 00000000000..caa5e5ef276 --- /dev/null +++ b/compiler/rustc_windows_rc/src/lib.rs @@ -0,0 +1,158 @@ +//! A build script dependency to create a Windows resource file for the compiler +//! +//! Uses values from the `CFG_VERSION` and `CFG_RELEASE` environment variables +//! to set the product and file version information in the Windows resource file. +use std::{env, ffi, fs, path, process}; + +use cc::windows_registry; + +/// The template for the Windows resource file. +const RESOURCE_TEMPLATE: &str = include_str!("../rustc.rc.in"); + +/// A subset of the possible values for the `FILETYPE` field in a Windows resource file +/// +/// See the `dwFileType` member of [VS_FIXEDFILEINFO](https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo#members) +#[derive(Debug, Clone, Copy)] +#[repr(u32)] +pub enum VersionInfoFileType { + /// `VFT_APP` - The file is an application. + App = 0x00000001, + /// `VFT_DLL` - The file is a dynamic link library. + Dll = 0x00000002, +} + +/// Create and compile a Windows resource file with the product and file version information for the rust compiler. +/// +/// Returns the path to the compiled resource file +/// +/// Does not emit any cargo directives, the caller is responsible for that. +pub fn compile_windows_resource_file( + file_stem: &path::Path, + file_description: &str, + filetype: VersionInfoFileType, +) -> path::PathBuf { + let mut resources_dir = path::PathBuf::from(env::var_os("OUT_DIR").unwrap()); + resources_dir.push("resources"); + fs::create_dir_all(&resources_dir).unwrap(); + + let resource_compiler = + find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe"); + + let rc_path = resources_dir.join(file_stem.with_extension("rc")); + + write_resource_script_file(&rc_path, file_description, filetype); + + let res_path = resources_dir.join(file_stem.with_extension("res")); + + let status = process::Command::new(resource_compiler) + .arg("/fo") + .arg(&res_path) + .arg(&rc_path) + .status() + .expect("can execute resource compiler"); + assert!(status.success(), "rc.exe failed with status {}", status); + assert!( + res_path.try_exists().unwrap_or(false), + "resource file {} was not created", + res_path.display() + ); + res_path +} + +/// Writes a Windows resource script file for the rust compiler with the product and file version information +/// into `rc_path` +fn write_resource_script_file( + rc_path: &path::Path, + file_description: &str, + filetype: VersionInfoFileType, +) { + let mut resource_script = RESOURCE_TEMPLATE.to_string(); + + // Set the string product and file version to the same thing as `rustc --version` + let descriptive_version = env::var("CFG_VERSION").unwrap_or("unknown".to_string()); + + // Set the product name to "Rust Compiler" or "Rust Compiler (nightly)" etc + let product_name = product_name(env::var("CFG_RELEASE_CHANNEL").unwrap()); + + // For the numeric version we need `major,minor,patch,build`. + // Extract them from `CFG_RELEASE` which is "major.minor.patch" and a "-dev", "-nightly" or similar suffix + let cfg_release = env::var("CFG_RELEASE").unwrap(); + // remove the suffix, if present and parse into [`ResourceVersion`] + let version = parse_version(cfg_release.split("-").next().unwrap_or("0.0.0")) + .expect("valid CFG_RELEASE version"); + + resource_script = resource_script + .replace("@RUSTC_FILEDESCRIPTION_STR@", file_description) + .replace("@RUSTC_FILETYPE@", &format!("{}", filetype as u32)) + .replace("@RUSTC_FILEVERSION_QUAD@", &version.to_quad_string()) + .replace("@RUSTC_FILEVERSION_STR@", &descriptive_version) + .replace("@RUSTC_PRODUCTNAME_STR@", &product_name) + .replace("@RUSTC_PRODUCTVERSION_QUAD@", &version.to_quad_string()) + .replace("@RUSTC_PRODUCTVERSION_STR@", &descriptive_version); + + fs::write(&rc_path, resource_script) + .unwrap_or_else(|_| panic!("failed to write resource file {}", rc_path.display())); +} + +fn product_name(channel: String) -> String { + format!( + "Rust Compiler{}", + if channel == "stable" { "".to_string() } else { format!(" ({})", channel) } + ) +} + +/// Windows resources store versions as four 16-bit integers. +struct ResourceVersion { + major: u16, + minor: u16, + patch: u16, + build: u16, +} + +impl ResourceVersion { + /// Format the version as a comma-separated string of four integers + /// as expected by Windows resource scripts for the `FILEVERSION` and `PRODUCTVERSION` fields. + fn to_quad_string(&self) -> String { + format!("{},{},{},{}", self.major, self.minor, self.patch, self.build) + } +} + +/// Parse a string in the format "major.minor.patch" into a [`ResourceVersion`]. +/// The build is set to 0. +/// Returns `None` if the version string is not in the expected format. +fn parse_version(version: &str) -> Option<ResourceVersion> { + let mut parts = version.split('.'); + let major = parts.next()?.parse::<u16>().ok()?; + let minor = parts.next()?.parse::<u16>().ok()?; + let patch = parts.next()?.parse::<u16>().ok()?; + if parts.next().is_some() { + None + } else { + Some(ResourceVersion { major, minor, patch, build: 0 }) + } +} + +/// Find the Windows SDK resource compiler `rc.exe` for the given architecture or target triple. +/// Returns `None` if the tool could not be found. +fn find_resource_compiler(arch_or_target: &str) -> Option<path::PathBuf> { + find_windows_sdk_tool(arch_or_target, "rc.exe") +} + +/// Find a Windows SDK tool for the given architecture or target triple. +/// Returns `None` if the tool could not be found. +fn find_windows_sdk_tool(arch_or_target: &str, tool_name: &str) -> Option<path::PathBuf> { + // windows_registry::find_tool can only find MSVC tools, not Windows SDK tools, but + // cc does include the Windows SDK tools in the PATH environment of MSVC tools. + + let msvc_linker = windows_registry::find_tool(arch_or_target, "link.exe")?; + let path = &msvc_linker.env().iter().find(|(k, _)| k == "PATH")?.1; + find_tool_in_path(tool_name, path) +} + +/// Find a tool in the directories in a given PATH-like string. +fn find_tool_in_path<P: AsRef<ffi::OsStr>>(tool_name: &str, path: P) -> Option<path::PathBuf> { + env::split_paths(path.as_ref()).find_map(|p| { + let tool_path = p.join(tool_name); + if tool_path.try_exists().unwrap_or(false) { Some(tool_path) } else { None } + }) +} diff --git a/library/Cargo.lock b/library/Cargo.lock index e601137e005..e4b3839847b 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -99,13 +99,12 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", - "unicode-width", ] [[package]] @@ -362,16 +361,6 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - -[[package]] name = "unwind" version = "0.0.0" dependencies = [ diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 8b6d86a2888..98f11e2ea57 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1433,7 +1433,6 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// # Examples /// /// ``` - /// #![feature(btree_extract_if)] /// use std::collections::BTreeMap; /// /// // Splitting a map into even and odd keys, reusing the original map: @@ -1450,7 +1449,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// assert_eq!(low.keys().copied().collect::<Vec<_>>(), [0, 1, 2, 3]); /// assert_eq!(high.keys().copied().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` - #[unstable(feature = "btree_extract_if", issue = "70530")] + #[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, K, V, R, F, A> where K: Ord, @@ -1937,7 +1936,7 @@ impl<K, V> Default for Values<'_, K, V> { } /// An iterator produced by calling `extract_if` on BTreeMap. -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1970,7 +1969,7 @@ pub(super) struct ExtractIfInner<'a, K, V, R> { range: R, } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<K, V, R, F, A> fmt::Debug for ExtractIf<'_, K, V, R, F, A> where K: fmt::Debug, @@ -1982,7 +1981,7 @@ where } } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<K, V, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, K, V, R, F, A> where K: PartialOrd, @@ -2056,7 +2055,7 @@ impl<'a, K, V, R> ExtractIfInner<'a, K, V, R> { } } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<K, V, R, F> FusedIterator for ExtractIf<'_, K, V, R, F> where K: PartialOrd, diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d50ce02bda7..e6b0a1f6323 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1202,7 +1202,6 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// # Examples /// /// ``` - /// #![feature(btree_extract_if)] /// use std::collections::BTreeSet; /// /// // Splitting a set into even and odd values, reusing the original set: @@ -1219,7 +1218,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// assert_eq!(low.into_iter().collect::<Vec<_>>(), [0, 1, 2, 3]); /// assert_eq!(high.into_iter().collect::<Vec<_>>(), [4, 5, 6, 7]); /// ``` - #[unstable(feature = "btree_extract_if", issue = "70530")] + #[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if<F, R>(&mut self, range: R, pred: F) -> ExtractIf<'_, T, R, F, A> where T: Ord, @@ -1554,7 +1553,7 @@ impl<'a, T, A: Allocator + Clone> IntoIterator for &'a BTreeSet<T, A> { } /// An iterator produced by calling `extract_if` on BTreeSet. -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1569,7 +1568,7 @@ pub struct ExtractIf< alloc: A, } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<T, R, F, A> fmt::Debug for ExtractIf<'_, T, R, F, A> where T: fmt::Debug, @@ -1582,7 +1581,7 @@ where } } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<T, R, F, A: Allocator + Clone> Iterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, @@ -1602,7 +1601,7 @@ where } } -#[unstable(feature = "btree_extract_if", issue = "70530")] +#[stable(feature = "btree_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<T, R, F, A: Allocator + Clone> FusedIterator for ExtractIf<'_, T, R, F, A> where T: PartialOrd, diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index 2633154318c..721d685527f 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -1,6 +1,5 @@ // Disabling in Miri as these would take too long. #![cfg(not(miri))] -#![feature(btree_extract_if)] #![feature(iter_next_chunk)] #![feature(repr_simd)] #![feature(slice_partition_dedup)] diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index bf446ae1ba4..8c3ce156f3c 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -2,7 +2,6 @@ #![feature(alloc_layout_extra)] #![feature(iter_array_chunks)] #![feature(assert_matches)] -#![feature(btree_extract_if)] #![feature(wtf8_internals)] #![feature(char_max_len)] #![feature(cow_is_borrowed)] diff --git a/library/core/src/any.rs b/library/core/src/any.rs index e7d9763d46e..76ea2d18a82 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -705,7 +705,8 @@ impl dyn Any + Send + Sync { /// std::mem::forget(fake_one_ring); /// } /// ``` -#[derive(Clone, Copy, Eq, PartialOrd, Ord)] +#[derive(Copy, PartialOrd, Ord)] +#[derive_const(Clone, Eq)] #[stable(feature = "rust1", since = "1.0.0")] #[lang = "type_id"] pub struct TypeId { diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 1ad2cca64a3..c2c7ccf0daa 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -1,9 +1,10 @@ use crate::cmp::BytewiseEq; #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<[U; N]> for [T; N] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &[U; N]) -> bool { @@ -16,9 +17,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<[U]> for [T; N] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<[U]> for [T; N] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &[U]) -> bool { @@ -37,9 +39,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<[U; N]> for [T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<[U; N]> for [T] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &[U; N]) -> bool { @@ -58,9 +61,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<&[U]> for [T; N] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<&[U]> for [T; N] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &&[U]) -> bool { @@ -73,9 +77,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<[U; N]> for &[T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<[U; N]> for &[T] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &[U; N]) -> bool { @@ -88,9 +93,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<&mut [U]> for [T; N] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<&mut [U]> for [T; N] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &&mut [U]) -> bool { @@ -103,9 +109,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T, U, const N: usize> PartialEq<[U; N]> for &mut [T] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T, U, const N: usize> const PartialEq<[U; N]> for &mut [T] where - T: PartialEq<U>, + T: [const] PartialEq<U>, { #[inline] fn eq(&self, other: &[U; N]) -> bool { @@ -122,14 +129,18 @@ where // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Eq, const N: usize> Eq for [T; N] {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] Eq, const N: usize> const Eq for [T; N] {} +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] trait SpecArrayEq<Other, const N: usize>: Sized { fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool; fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool; } -impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] PartialEq<Other>, Other, const N: usize> const SpecArrayEq<Other, N> for T { default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool { a[..] == b[..] } @@ -138,7 +149,8 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T { } } -impl<T: BytewiseEq<U>, U, const N: usize> SpecArrayEq<U, N> for T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] BytewiseEq<U>, U, const N: usize> const SpecArrayEq<U, N> for T { fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { // SAFETY: Arrays are compared element-wise, and don't add any padding // between elements, so when the elements are `BytewiseEq`, we can diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 49d540314a2..178af2c0e3b 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -54,7 +54,8 @@ use crate::{assert_unsafe_precondition, fmt}; /// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf /// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf /// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Hash)] +#[derive_const(Clone, Eq, PartialEq, Ord, PartialOrd)] #[unstable(feature = "ascii_char", issue = "110998")] #[repr(u8)] pub enum AsciiChar { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 0812322f3fb..94536f25b41 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -29,7 +29,7 @@ mod bytewise; pub(crate) use bytewise::BytewiseEq; use self::Ordering::*; -use crate::marker::PointeeSized; +use crate::marker::{Destruct, PointeeSized}; use crate::ops::ControlFlow; /// Trait for comparisons using the equality operator. @@ -334,7 +334,9 @@ pub macro PartialEq($item:item) { #[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] -pub trait Eq: PartialEq<Self> + PointeeSized { +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub trait Eq: [const] PartialEq<Self> + PointeeSized { // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a // type implements `Eq` itself. The current deriving infrastructure means doing this assertion // without using a method on this trait is nearly impossible. @@ -380,8 +382,8 @@ pub struct AssertParamIsEq<T: Eq + PointeeSized> { /// /// assert_eq!(2.cmp(&1), Ordering::Greater); /// ``` -#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)] -#[derive_const(PartialEq)] +#[derive(Copy, Debug, Hash)] +#[derive_const(Clone, Eq, PartialOrd, Ord, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] // This is a lang item only so that `BinOp::Cmp` in MIR can return it. // It has no special behavior, but does require that the three variants @@ -635,7 +637,11 @@ impl Ordering { #[inline] #[must_use] #[stable(feature = "ordering_chaining", since = "1.17.0")] - pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + pub const fn then_with<F>(self, f: F) -> Ordering + where + F: [const] FnOnce() -> Ordering + [const] Destruct, + { match self { Equal => f(), _ => self, @@ -659,13 +665,15 @@ impl Ordering { /// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` -#[derive(PartialEq, Eq, Debug, Copy, Default, Hash)] +#[derive(Copy, Debug, Hash)] +#[derive_const(PartialEq, Eq, Default)] #[stable(feature = "reverse_cmp_key", since = "1.19.0")] #[repr(transparent)] pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -impl<T: PartialOrd> PartialOrd for Reverse<T> { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] PartialOrd> const PartialOrd for Reverse<T> { #[inline] fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> { other.0.partial_cmp(&self.0) @@ -690,7 +698,8 @@ impl<T: PartialOrd> PartialOrd for Reverse<T> { } #[stable(feature = "reverse_cmp_key", since = "1.19.0")] -impl<T: Ord> Ord for Reverse<T> { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] Ord> const Ord for Reverse<T> { #[inline] fn cmp(&self, other: &Reverse<T>) -> Ordering { other.0.cmp(&self.0) @@ -957,7 +966,9 @@ impl<T: Clone> Clone for Reverse<T> { #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] -pub trait Ord: Eq + PartialOrd<Self> + PointeeSized { +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub trait Ord: [const] Eq + [const] PartialOrd<Self> + PointeeSized { /// This method returns an [`Ordering`] between `self` and `other`. /// /// By convention, `self.cmp(&other)` returns the ordering matching the expression @@ -1011,7 +1022,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized { #[rustc_diagnostic_item = "cmp_ord_max"] fn max(self, other: Self) -> Self where - Self: Sized, + Self: Sized + [const] Destruct, { if other < self { self } else { other } } @@ -1050,7 +1061,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized { #[rustc_diagnostic_item = "cmp_ord_min"] fn min(self, other: Self) -> Self where - Self: Sized, + Self: Sized + [const] Destruct, { if other < self { other } else { self } } @@ -1076,7 +1087,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized { #[stable(feature = "clamp", since = "1.50.0")] fn clamp(self, min: Self, max: Self) -> Self where - Self: Sized, + Self: Sized + [const] Destruct, { assert!(min <= max); if self < min { @@ -1341,6 +1352,8 @@ pub macro Ord($item:item) { )] #[rustc_diagnostic_item = "PartialOrd"] #[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized { /// This method returns an ordering between `self` and `other` values if one exists. /// @@ -1481,13 +1494,14 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized { } } -fn default_chaining_impl<T, U>( +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +const fn default_chaining_impl<T, U>( lhs: &T, rhs: &U, - p: impl FnOnce(Ordering) -> bool, + p: impl [const] FnOnce(Ordering) -> bool + [const] Destruct, ) -> ControlFlow<bool> where - T: PartialOrd<U> + PointeeSized, + T: [const] PartialOrd<U> + PointeeSized, U: PointeeSized, { // It's important that this only call `partial_cmp` once, not call `eq` then @@ -1545,7 +1559,8 @@ pub macro PartialOrd($item:item) { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_min"] -pub fn min<T: Ord>(v1: T, v2: T) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn min<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T { v1.min(v2) } @@ -1575,7 +1590,12 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn min_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>( + v1: T, + v2: T, + compare: F, +) -> T { if compare(&v1, &v2).is_le() { v1 } else { v2 } } @@ -1600,7 +1620,13 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn min_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T +where + T: [const] Destruct, + F: [const] FnMut(&T) -> K + [const] Destruct, + K: [const] Ord + [const] Destruct, +{ if f(&v2) < f(&v1) { v2 } else { v1 } } @@ -1640,7 +1666,8 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_max"] -pub fn max<T: Ord>(v1: T, v2: T) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn max<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T { v1.max(v2) } @@ -1670,7 +1697,12 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn max_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>( + v1: T, + v2: T, + compare: F, +) -> T { if compare(&v1, &v2).is_gt() { v1 } else { v2 } } @@ -1695,7 +1727,13 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] -pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn max_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T +where + T: [const] Destruct, + F: [const] FnMut(&T) -> K + [const] Destruct, + K: [const] Ord + [const] Destruct, +{ if f(&v2) < f(&v1) { v1 } else { v2 } } @@ -1739,9 +1777,10 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[unstable(feature = "cmp_minmax", issue = "115939")] -pub fn minmax<T>(v1: T, v2: T) -> [T; 2] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn minmax<T>(v1: T, v2: T) -> [T; 2] where - T: Ord, + T: [const] Ord, { if v2 < v1 { [v2, v1] } else { [v1, v2] } } @@ -1773,9 +1812,10 @@ where #[inline] #[must_use] #[unstable(feature = "cmp_minmax", issue = "115939")] -pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] where - F: FnOnce(&T, &T) -> Ordering, + F: [const] FnOnce(&T, &T) -> Ordering, { if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } } @@ -1801,10 +1841,11 @@ where #[inline] #[must_use] #[unstable(feature = "cmp_minmax", issue = "115939")] -pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +pub const fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2] where - F: FnMut(&T) -> K, - K: Ord, + F: [const] FnMut(&T) -> K + [const] Destruct, + K: [const] Ord + [const] Destruct, { if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] } } @@ -1830,7 +1871,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialEq for () { #[inline] fn eq(&self, _other: &()) -> bool { true @@ -1848,7 +1890,8 @@ mod impls { macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for $t {} + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Eq for $t {} )*) } @@ -1896,7 +1939,8 @@ mod impls { macro_rules! partial_ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { match (*self <= *other, *self >= *other) { @@ -1913,7 +1957,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialOrd for () { #[inline] fn partial_cmp(&self, _: &()) -> Option<Ordering> { Some(Equal) @@ -1921,7 +1966,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for bool { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialOrd for bool { #[inline] fn partial_cmp(&self, other: &bool) -> Option<Ordering> { Some(self.cmp(other)) @@ -1935,7 +1981,8 @@ mod impls { macro_rules! ord_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialOrd for $t { #[inline] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(crate::intrinsics::three_way_compare(*self, *other)) @@ -1945,7 +1992,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for $t { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Ord for $t { #[inline] fn cmp(&self, other: &Self) -> Ordering { crate::intrinsics::three_way_compare(*self, *other) @@ -1955,7 +2003,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for () { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Ord for () { #[inline] fn cmp(&self, _other: &()) -> Ordering { Equal @@ -1963,7 +2012,8 @@ mod impls { } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for bool { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Ord for bool { #[inline] fn cmp(&self, other: &bool) -> Ordering { // Casting to i8's and converting the difference to an Ordering generates @@ -1998,7 +2048,8 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } #[unstable(feature = "never_type", issue = "35121")] - impl PartialEq for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialEq for ! { #[inline] fn eq(&self, _: &!) -> bool { *self @@ -2006,10 +2057,12 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - impl Eq for ! {} + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Eq for ! {} #[unstable(feature = "never_type", issue = "35121")] - impl PartialOrd for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const PartialOrd for ! { #[inline] fn partial_cmp(&self, _: &!) -> Option<Ordering> { *self @@ -2017,7 +2070,8 @@ mod impls { } #[unstable(feature = "never_type", issue = "35121")] - impl Ord for ! { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl const Ord for ! { #[inline] fn cmp(&self, _: &!) -> Ordering { *self @@ -2042,9 +2096,10 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized, B: PointeeSized> PartialOrd<&B> for &A + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&B> for &A where - A: PartialOrd<B>, + A: [const] PartialOrd<B>, { #[inline] fn partial_cmp(&self, other: &&B) -> Option<Ordering> { @@ -2084,9 +2139,10 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized> Ord for &A + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized> const Ord for &A where - A: Ord, + A: [const] Ord, { #[inline] fn cmp(&self, other: &Self) -> Ordering { @@ -2094,7 +2150,8 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized> Eq for &A where A: Eq {} + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized> const Eq for &A where A: [const] Eq {} // &mut pointers @@ -2114,9 +2171,10 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized, B: PointeeSized> PartialOrd<&mut B> for &mut A + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&mut B> for &mut A where - A: PartialOrd<B>, + A: [const] PartialOrd<B>, { #[inline] fn partial_cmp(&self, other: &&mut B) -> Option<Ordering> { @@ -2156,9 +2214,10 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized> Ord for &mut A + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized> const Ord for &mut A where - A: Ord, + A: [const] Ord, { #[inline] fn cmp(&self, other: &Self) -> Ordering { @@ -2166,7 +2225,8 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl<A: PointeeSized> Eq for &mut A where A: Eq {} + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<A: PointeeSized> const Eq for &mut A where A: [const] Eq {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index a3cfd85974a..89cda30c030 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -963,17 +963,20 @@ impl const PartialEq for Infallible { } #[stable(feature = "convert_infallible", since = "1.34.0")] -impl Eq for Infallible {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Eq for Infallible {} #[stable(feature = "convert_infallible", since = "1.34.0")] -impl PartialOrd for Infallible { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd for Infallible { fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> { match *self {} } } #[stable(feature = "convert_infallible", since = "1.34.0")] -impl Ord for Infallible { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for Infallible { fn cmp(&self, _other: &Self) -> crate::cmp::Ordering { match *self {} } diff --git a/library/core/src/default.rs b/library/core/src/default.rs index cc9289307c1..1cc4fb6e8fd 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -33,7 +33,7 @@ use crate::ascii::Char as AsciiChar; /// } /// ``` /// -/// Now, you get all of the default values. Rust implements `Default` for various primitives types. +/// Now, you get all of the default values. Rust implements `Default` for various primitive types. /// /// If you want to override a particular option, but still retain the other defaults: /// diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 88ad1197777..643bd95df84 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -202,18 +202,23 @@ mod sealed { impl<T> Sealed for *const T {} } -/// Trait which permits the allowed types to be used with [`VaListImpl::arg`]. +/// Types that are valid to read using [`VaListImpl::arg`]. /// /// # Safety /// -/// This trait must only be implemented for types that C passes as varargs without implicit promotion. +/// The standard library implements this trait for primitive types that are +/// expected to have a variable argument application-binary interface (ABI) on all +/// platforms. /// -/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`] -/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for -/// types that are subject to this promotion rule is invalid. +/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller +/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively. +/// Implementing this trait for types that are subject to this promotion rule is invalid. /// /// [`c_int`]: core::ffi::c_int /// [`c_double`]: core::ffi::c_double +// We may unseal this trait in the future, but currently our `va_arg` implementations don't support +// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used +// to accept unsupported types in the meantime. pub unsafe trait VaArgSafe: sealed::Sealed {} // i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`. @@ -233,7 +238,19 @@ unsafe impl<T> VaArgSafe for *mut T {} unsafe impl<T> VaArgSafe for *const T {} impl<'f> VaListImpl<'f> { - /// Advance to the next arg. + /// Advance to and read the next variable argument. + /// + /// # Safety + /// + /// This function is only sound to call when the next variable argument: + /// + /// - has a type that is ABI-compatible with the type `T` + /// - has a value that is a properly initialized value of type `T` + /// + /// Calling this function with an incompatible type, an invalid value, or when there + /// are no more variable arguments, is unsound. + /// + /// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html #[inline] pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T { // SAFETY: the caller must uphold the safety contract for `va_arg`. diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 73122369b41..3b805139ded 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -203,7 +203,7 @@ macro_rules! float_sum_product { integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } saturating_integer_sum_product! { u8 u16 u32 u64 u128 usize } -float_sum_product! { f32 f64 } +float_sum_product! { f16 f32 f64 f128 } #[stable(feature = "iter_arith_traits_result", since = "1.16.0")] impl<T, U, E> Sum<Result<U, E>> for Result<T, E> diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c306011bdda..86a68e18b0a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -252,47 +252,16 @@ pub use crate::macros::cfg_select; #[macro_use] mod internal_macros; -#[path = "num/shells/int_macros.rs"] -#[macro_use] -mod int_macros; - -#[rustc_diagnostic_item = "i128_legacy_mod"] -#[path = "num/shells/i128.rs"] -pub mod i128; -#[rustc_diagnostic_item = "i16_legacy_mod"] -#[path = "num/shells/i16.rs"] -pub mod i16; -#[rustc_diagnostic_item = "i32_legacy_mod"] -#[path = "num/shells/i32.rs"] -pub mod i32; -#[rustc_diagnostic_item = "i64_legacy_mod"] -#[path = "num/shells/i64.rs"] -pub mod i64; -#[rustc_diagnostic_item = "i8_legacy_mod"] -#[path = "num/shells/i8.rs"] -pub mod i8; -#[rustc_diagnostic_item = "isize_legacy_mod"] -#[path = "num/shells/isize.rs"] -pub mod isize; - -#[rustc_diagnostic_item = "u128_legacy_mod"] -#[path = "num/shells/u128.rs"] -pub mod u128; -#[rustc_diagnostic_item = "u16_legacy_mod"] -#[path = "num/shells/u16.rs"] -pub mod u16; -#[rustc_diagnostic_item = "u32_legacy_mod"] -#[path = "num/shells/u32.rs"] -pub mod u32; -#[rustc_diagnostic_item = "u64_legacy_mod"] -#[path = "num/shells/u64.rs"] -pub mod u64; -#[rustc_diagnostic_item = "u8_legacy_mod"] -#[path = "num/shells/u8.rs"] -pub mod u8; -#[rustc_diagnostic_item = "usize_legacy_mod"] -#[path = "num/shells/usize.rs"] -pub mod usize; +#[path = "num/shells/legacy_int_modules.rs"] +mod legacy_int_modules; +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(clippy::useless_attribute)] // FIXME false positive (https://github.com/rust-lang/rust-clippy/issues/15636) +#[allow(deprecated_in_future)] +pub use legacy_int_modules::{i8, i16, i32, i64, isize, u8, u16, u32, u64, usize}; +#[stable(feature = "i128", since = "1.26.0")] +#[allow(clippy::useless_attribute)] // FIXME false positive (https://github.com/rust-lang/rust-clippy/issues/15636) +#[allow(deprecated_in_future)] +pub use legacy_int_modules::{i128, u128}; #[path = "num/f128.rs"] pub mod f128; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index ccf41dfb01d..3f58fc448aa 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1017,6 +1017,7 @@ pub(crate) mod builtin { )] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] + #[doc(hidden)] #[macro_export] macro_rules! format_args_nl { ($fmt:expr) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index e33f58197bb..f21fe0b4438 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -335,43 +335,6 @@ macro_rules! define_bignum { } (self, borrow) } - - /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the - /// remainder. - pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - // Stupid slow base-2 long division taken from - // https://en.wikipedia.org/wiki/Division_algorithm - // FIXME use a greater base ($ty) for the long division. - assert!(!d.is_zero()); - let digitbits = <$ty>::BITS as usize; - for digit in &mut q.base[..] { - *digit = 0; - } - for digit in &mut r.base[..] { - *digit = 0; - } - r.size = d.size; - q.size = 1; - let mut q_is_zero = true; - let end = self.bit_length(); - for i in (0..end).rev() { - r.mul_pow2(1); - r.base[0] |= self.get_bit(i) as $ty; - if &*r >= d { - r.sub(d); - // Set bit `i` of q to 1. - let digit_idx = i / digitbits; - let bit_idx = i % digitbits; - if q_is_zero { - q.size = digit_idx + 1; - q_is_zero = false; - } - q.base[digit_idx] |= 1 << bit_idx; - } - } - debug_assert!(q.base[q.size..].iter().all(|&d| d == 0)); - debug_assert!(r.base[r.size..].iter().all(|&d| d == 0)); - } } impl crate::cmp::PartialEq for $name { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0f38081c355..1b7c28bb95a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -4,7 +4,7 @@ use super::{IntErrorKind, ParseIntError}; use crate::clone::UseCloned; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; -use crate::marker::{Freeze, StructuralPartialEq}; +use crate::marker::{Destruct, Freeze, StructuralPartialEq}; use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign}; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::str::FromStr; @@ -220,12 +220,14 @@ where impl<T> StructuralPartialEq for NonZero<T> where T: ZeroablePrimitive + StructuralPartialEq {} #[stable(feature = "nonzero", since = "1.28.0")] -impl<T> Eq for NonZero<T> where T: ZeroablePrimitive + Eq {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T> const Eq for NonZero<T> where T: ZeroablePrimitive + [const] Eq {} #[stable(feature = "nonzero", since = "1.28.0")] -impl<T> PartialOrd for NonZero<T> +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T> const PartialOrd for NonZero<T> where - T: ZeroablePrimitive + PartialOrd, + T: ZeroablePrimitive + [const] PartialOrd, { #[inline] fn partial_cmp(&self, other: &Self) -> Option<Ordering> { @@ -254,9 +256,12 @@ where } #[stable(feature = "nonzero", since = "1.28.0")] -impl<T> Ord for NonZero<T> +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T> const Ord for NonZero<T> where - T: ZeroablePrimitive + Ord, + // FIXME(const_hack): the T: ~const Destruct should be inferred from the Self: ~const Destruct. + // See https://github.com/rust-lang/rust/issues/144207 + T: ZeroablePrimitive + [const] Ord + [const] Destruct, { #[inline] fn cmp(&self, other: &Self) -> Ordering { diff --git a/library/core/src/num/shells/i128.rs b/library/core/src/num/shells/i128.rs deleted file mode 100644 index b3b3d3b4875..00000000000 --- a/library/core/src/num/shells/i128.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`i128` primitive type][i128]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "i128", since = "1.26.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `i128`" -)] - -int_module! { i128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/library/core/src/num/shells/i16.rs b/library/core/src/num/shells/i16.rs deleted file mode 100644 index 70a452e1939..00000000000 --- a/library/core/src/num/shells/i16.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`i16` primitive type][i16]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `i16`" -)] - -int_module! { i16 } diff --git a/library/core/src/num/shells/i32.rs b/library/core/src/num/shells/i32.rs deleted file mode 100644 index c30849e2591..00000000000 --- a/library/core/src/num/shells/i32.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`i32` primitive type][i32]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `i32`" -)] - -int_module! { i32 } diff --git a/library/core/src/num/shells/i64.rs b/library/core/src/num/shells/i64.rs deleted file mode 100644 index 77d95d71250..00000000000 --- a/library/core/src/num/shells/i64.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`i64` primitive type][i64]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `i64`" -)] - -int_module! { i64 } diff --git a/library/core/src/num/shells/i8.rs b/library/core/src/num/shells/i8.rs deleted file mode 100644 index 516ba8cdef3..00000000000 --- a/library/core/src/num/shells/i8.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`i8` primitive type][i8]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `i8`" -)] - -int_module! { i8 } diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs deleted file mode 100644 index 8ae9b7abae3..00000000000 --- a/library/core/src/num/shells/int_macros.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![doc(hidden)] - -macro_rules! int_module { - ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); - ($T:ident, #[$attr:meta]) => ( - #[doc = concat!( - "The smallest value that can be represented by this integer type. Use ", - "[`", stringify!($T), "::MIN", "`] instead." - )] - /// - /// # Examples - /// - /// ```rust - /// // deprecated way - #[doc = concat!("let min = std::", stringify!($T), "::MIN;")] - /// - /// // intended way - #[doc = concat!("let min = ", stringify!($T), "::MIN;")] - /// ``` - /// - #[$attr] - #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")] - #[rustc_diagnostic_item = concat!(stringify!($T), "_legacy_const_min")] - pub const MIN: $T = $T::MIN; - - #[doc = concat!( - "The largest value that can be represented by this integer type. Use ", - "[`", stringify!($T), "::MAX", "`] instead." - )] - /// - /// # Examples - /// - /// ```rust - /// // deprecated way - #[doc = concat!("let max = std::", stringify!($T), "::MAX;")] - /// - /// // intended way - #[doc = concat!("let max = ", stringify!($T), "::MAX;")] - /// ``` - /// - #[$attr] - #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")] - #[rustc_diagnostic_item = concat!(stringify!($T), "_legacy_const_max")] - pub const MAX: $T = $T::MAX; - ) -} diff --git a/library/core/src/num/shells/isize.rs b/library/core/src/num/shells/isize.rs deleted file mode 100644 index 828f7345baf..00000000000 --- a/library/core/src/num/shells/isize.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`isize` primitive type][isize]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `isize`" -)] - -int_module! { isize } diff --git a/library/core/src/num/shells/legacy_int_modules.rs b/library/core/src/num/shells/legacy_int_modules.rs new file mode 100644 index 00000000000..6b4f2539111 --- /dev/null +++ b/library/core/src/num/shells/legacy_int_modules.rs @@ -0,0 +1,71 @@ +#![doc(hidden)] + +macro_rules! legacy_int_module { + ($T:ident) => (legacy_int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); + ($T:ident, #[$attr:meta]) => ( + #[$attr] + #[deprecated( + since = "TBD", + note = "all constants in this module replaced by associated constants on the type" + )] + #[rustc_diagnostic_item = concat!(stringify!($T), "_legacy_mod")] + pub mod $T { + #![doc = concat!("Redundant constants module for the [`", stringify!($T), "` primitive type][", stringify!($T), "].")] + //! + //! New code should use the associated constants directly on the primitive type. + + #[doc = concat!( + "The smallest value that can be represented by this integer type. Use ", + "[`", stringify!($T), "::MIN", "`] instead." + )] + /// + /// # Examples + /// + /// ```rust + /// // deprecated way + #[doc = concat!("let min = std::", stringify!($T), "::MIN;")] + /// + /// // intended way + #[doc = concat!("let min = ", stringify!($T), "::MIN;")] + /// ``` + /// + #[$attr] + #[deprecated(since = "TBD", note = "replaced by the `MIN` associated constant on this type")] + #[rustc_diagnostic_item = concat!(stringify!($T), "_legacy_const_min")] + pub const MIN: $T = $T::MIN; + + #[doc = concat!( + "The largest value that can be represented by this integer type. Use ", + "[`", stringify!($T), "::MAX", "`] instead." + )] + /// + /// # Examples + /// + /// ```rust + /// // deprecated way + #[doc = concat!("let max = std::", stringify!($T), "::MAX;")] + /// + /// // intended way + #[doc = concat!("let max = ", stringify!($T), "::MAX;")] + /// ``` + /// + #[$attr] + #[deprecated(since = "TBD", note = "replaced by the `MAX` associated constant on this type")] + #[rustc_diagnostic_item = concat!(stringify!($T), "_legacy_const_max")] + pub const MAX: $T = $T::MAX; + } + ) +} + +legacy_int_module! { i128, #[stable(feature = "i128", since = "1.26.0")] } +legacy_int_module! { i16 } +legacy_int_module! { i32 } +legacy_int_module! { i64 } +legacy_int_module! { i8 } +legacy_int_module! { isize } +legacy_int_module! { u128, #[stable(feature = "i128", since = "1.26.0")] } +legacy_int_module! { u16 } +legacy_int_module! { u32 } +legacy_int_module! { u64 } +legacy_int_module! { u8 } +legacy_int_module! { usize } diff --git a/library/core/src/num/shells/u128.rs b/library/core/src/num/shells/u128.rs deleted file mode 100644 index b1e30e38435..00000000000 --- a/library/core/src/num/shells/u128.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`u128` primitive type][u128]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "i128", since = "1.26.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `u128`" -)] - -int_module! { u128, #[stable(feature = "i128", since="1.26.0")] } diff --git a/library/core/src/num/shells/u16.rs b/library/core/src/num/shells/u16.rs deleted file mode 100644 index 7394977e507..00000000000 --- a/library/core/src/num/shells/u16.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`u16` primitive type][u16]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `u16`" -)] - -int_module! { u16 } diff --git a/library/core/src/num/shells/u32.rs b/library/core/src/num/shells/u32.rs deleted file mode 100644 index 4c84274e752..00000000000 --- a/library/core/src/num/shells/u32.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`u32` primitive type][u32]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `u32`" -)] - -int_module! { u32 } diff --git a/library/core/src/num/shells/u64.rs b/library/core/src/num/shells/u64.rs deleted file mode 100644 index 47a95c6820f..00000000000 --- a/library/core/src/num/shells/u64.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`u64` primitive type][u64]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `u64`" -)] - -int_module! { u64 } diff --git a/library/core/src/num/shells/u8.rs b/library/core/src/num/shells/u8.rs deleted file mode 100644 index 360baef7228..00000000000 --- a/library/core/src/num/shells/u8.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`u8` primitive type][u8]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `u8`" -)] - -int_module! { u8 } diff --git a/library/core/src/num/shells/usize.rs b/library/core/src/num/shells/usize.rs deleted file mode 100644 index 44c24dfc2cf..00000000000 --- a/library/core/src/num/shells/usize.rs +++ /dev/null @@ -1,11 +0,0 @@ -//! Redundant constants module for the [`usize` primitive type][usize]. -//! -//! New code should use the associated constants directly on the primitive type. - -#![stable(feature = "rust1", since = "1.0.0")] -#![deprecated( - since = "TBD", - note = "all constants in this module replaced by associated constants on `usize`" -)] - -int_module! { usize } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 73b74d53323..b760a7c4e21 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -83,7 +83,8 @@ use crate::{convert, ops}; #[must_use] // ControlFlow should not implement PartialOrd or Ord, per RFC 3058: // https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Debug, Hash)] +#[derive_const(Clone, PartialEq, Eq)] pub enum ControlFlow<B, C = ()> { /// Move on to the next phase of the operation as normal. #[stable(feature = "control_flow_enum_type", since = "1.55.0")] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 198636c67d0..886d581b0a6 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -585,7 +585,8 @@ use crate::{cmp, convert, hint, mem, slice}; /// The `Option` type. See [the module level documentation](self) for more. #[doc(search_unbox)] -#[derive(Copy, Eq, Debug, Hash)] +#[derive(Copy, Debug, Hash)] +#[derive_const(Eq)] #[rustc_diagnostic_item = "Option"] #[lang = "Option"] #[stable(feature = "rust1", since = "1.0.0")] @@ -2363,7 +2364,8 @@ impl<T: [const] PartialEq> const PartialEq for Option<T> { // https://github.com/rust-lang/rust/issues/49892, although still // not optimal. #[stable(feature = "rust1", since = "1.0.0")] -impl<T: PartialOrd> PartialOrd for Option<T> { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] PartialOrd> const PartialOrd for Option<T> { #[inline] fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { match (self, other) { @@ -2376,7 +2378,8 @@ impl<T: PartialOrd> PartialOrd for Option<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Ord> Ord for Option<T> { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] Ord> const Ord for Option<T> { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { match (self, other) { diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index c5f0cb8016e..45109270944 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -146,28 +146,7 @@ impl<T: PointeeSized> *const T { self as _ } - /// Gets the "address" portion of the pointer. - /// - /// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of - /// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that - /// casting the returned address back to a pointer yields a [pointer without - /// provenance][without_provenance], which is undefined behavior to dereference. To properly - /// restore the lost information and obtain a dereferenceable pointer, use - /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. - /// - /// If using those APIs is not possible because there is no way to preserve a pointer with the - /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts - /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance] - /// instead. However, note that this makes your code less portable and less amenable to tools - /// that check for compliance with the Rust memory model. - /// - /// On most platforms this will produce a value with the same bytes as the original - /// pointer, because all the bytes are dedicated to describing the address. - /// Platforms which need to store additional information in the pointer may - /// perform a change of representation to produce a value containing only the address - /// portion of the pointer. What that means is up to the platform to define. - /// - /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. + #[doc = include_str!("./docs/addr.md")] #[must_use] #[inline(always)] #[stable(feature = "strict_provenance", since = "1.84.0")] @@ -254,23 +233,16 @@ impl<T: PointeeSized> *const T { (self.cast(), metadata(self)) } - /// Returns `None` if the pointer is null, or else returns a shared reference to - /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`] - /// must be used instead. - /// - /// [`as_uninit_ref`]: #method.as_uninit_ref - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). + #[doc = include_str!("./docs/as_ref.md")] /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. + /// ``` + /// let ptr: *const u8 = &10u8 as *const u8; /// - /// [`is_null`]: #method.is_null + /// unsafe { + /// let val_back = &*ptr; + /// assert_eq!(val_back, &10); + /// } + /// ``` /// /// # Examples /// @@ -284,20 +256,9 @@ impl<T: PointeeSized> *const T { /// } /// ``` /// - /// # Null-unchecked version /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. - /// - /// ``` - /// let ptr: *const u8 = &10u8 as *const u8; - /// - /// unsafe { - /// let val_back = &*ptr; - /// assert_eq!(val_back, &10); - /// } - /// ``` + /// [`is_null`]: #method.is_null + /// [`as_uninit_ref`]: #method.as_uninit_ref #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[inline] @@ -338,23 +299,10 @@ impl<T: PointeeSized> *const T { unsafe { &*self } } - /// Returns `None` if the pointer is null, or else returns a shared reference to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// [`as_ref`]: #method.as_ref - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). - /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. + #[doc = include_str!("./docs/as_uninit_ref.md")] /// /// [`is_null`]: #method.is_null + /// [`as_ref`]: #method.as_ref /// /// # Examples /// diff --git a/library/core/src/ptr/docs/INFO.md b/library/core/src/ptr/docs/INFO.md new file mode 100644 index 00000000000..28a0da4926a --- /dev/null +++ b/library/core/src/ptr/docs/INFO.md @@ -0,0 +1,21 @@ +This directory holds method documentation that otherwise +would be duplicated across mutable and immutable pointers. + +Note that most of the docs here are not the complete docs +for their corresponding method. This is for a few reasons: + +1. Examples need to be different for mutable/immutable + pointers, in order to actually call the correct method. +2. Link reference definitions are frequently different + between mutable/immutable pointers, in order to link to + the correct method. + For example, `<*const T>::as_ref` links to + `<*const T>::is_null`, while `<*mut T>::as_ref` links to + `<*mut T>::is_null`. +3. Many methods on mutable pointers link to an alternate + version that returns a mutable reference instead of + a shared reference. + +Always review the rendered docs manually when making +changes to these files to make sure you're not accidentally +splitting up a section. diff --git a/library/core/src/ptr/docs/addr.md b/library/core/src/ptr/docs/addr.md new file mode 100644 index 00000000000..785b88a9987 --- /dev/null +++ b/library/core/src/ptr/docs/addr.md @@ -0,0 +1,22 @@ +Gets the "address" portion of the pointer. + +This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of +the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that +casting the returned address back to a pointer yields a [pointer without +provenance][without_provenance], which is undefined behavior to dereference. To properly +restore the lost information and obtain a dereferenceable pointer, use +[`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. + +If using those APIs is not possible because there is no way to preserve a pointer with the +required provenance, then Strict Provenance might not be for you. Use pointer-integer casts +or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance] +instead. However, note that this makes your code less portable and less amenable to tools +that check for compliance with the Rust memory model. + +On most platforms this will produce a value with the same bytes as the original +pointer, because all the bytes are dedicated to describing the address. +Platforms which need to store additional information in the pointer may +perform a change of representation to produce a value containing only the address +portion of the pointer. What that means is up to the platform to define. + +This is a [Strict Provenance][crate::ptr#strict-provenance] API. diff --git a/library/core/src/ptr/docs/as_ref.md b/library/core/src/ptr/docs/as_ref.md new file mode 100644 index 00000000000..0c0d2768c74 --- /dev/null +++ b/library/core/src/ptr/docs/as_ref.md @@ -0,0 +1,19 @@ +Returns `None` if the pointer is null, or else returns a shared reference to +the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`] +must be used instead. + +# Safety + +When calling this method, you have to ensure that *either* the pointer is null *or* +the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). + +# Panics during const evaluation + +This method will panic during const evaluation if the pointer cannot be +determined to be null or not. See [`is_null`] for more information. + +# Null-unchecked version + +If you are sure the pointer can never be null and are looking for some kind of +`as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can +dereference the pointer directly. diff --git a/library/core/src/ptr/docs/as_uninit_ref.md b/library/core/src/ptr/docs/as_uninit_ref.md new file mode 100644 index 00000000000..5b9a1ecb85b --- /dev/null +++ b/library/core/src/ptr/docs/as_uninit_ref.md @@ -0,0 +1,15 @@ +Returns `None` if the pointer is null, or else returns a shared reference to +the value wrapped in `Some`. In contrast to [`as_ref`], this does not require +that the value has to be initialized. + +# Safety + +When calling this method, you have to ensure that *either* the pointer is null *or* +the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). +Note that because the created reference is to `MaybeUninit<T>`, the +source pointer can point to uninitialized memory. + +# Panics during const evaluation + +This method will panic during const evaluation if the pointer cannot be +determined to be null or not. See [`is_null`] for more information. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6b94088cb56..625024373ef 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1348,6 +1348,40 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) { /// assert_eq!(x, [7, 8, 3, 4]); /// assert_eq!(y, [1, 2, 9]); /// ``` +/// +/// # Const evaluation limitations +/// +/// If this function is invoked during const-evaluation, the current implementation has a small (and +/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y` +/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may +/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the +/// future. +/// +/// The limitation is illustrated by the following example: +/// +/// ``` +/// use std::mem::size_of; +/// use std::ptr; +/// +/// const { unsafe { +/// const PTR_SIZE: usize = size_of::<*const i32>(); +/// let mut data1 = [0u8; PTR_SIZE]; +/// let mut data2 = [0u8; PTR_SIZE]; +/// // Store a pointer in `data1`. +/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42); +/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks. +/// // This call will fail, because the pointer in `data1` crosses the boundary +/// // between several of the 1-byte chunks that are being swapped here. +/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE); +/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size +/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between +/// // two chunks. +/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1); +/// // Read the pointer from `data2` and dereference it. +/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned(); +/// assert!(*ptr == 42); +/// } } +/// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] #[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")] @@ -1376,7 +1410,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { const_eval_select!( @capture[T] { x: *mut T, y: *mut T, count: usize }: if const { - // At compile-time we don't need all the special code below. + // At compile-time we want to always copy this in chunks of `T`, to ensure that if there + // are pointers inside `T` we will copy them in one go rather than trying to copy a part + // of a pointer (which would not work). // SAFETY: Same preconditions as this function unsafe { swap_nonoverlapping_const(x, y, count) } } else { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ce6eee4f911..ba78afc7ea1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -135,28 +135,9 @@ impl<T: PointeeSized> *mut T { self as _ } - /// Gets the "address" portion of the pointer. - /// - /// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of - /// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that - /// casting the returned address back to a pointer yields a [pointer without - /// provenance][without_provenance_mut], which is undefined behavior to dereference. To properly - /// restore the lost information and obtain a dereferenceable pointer, use - /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. - /// - /// If using those APIs is not possible because there is no way to preserve a pointer with the - /// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts - /// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance] - /// instead. However, note that this makes your code less portable and less amenable to tools - /// that check for compliance with the Rust memory model. - /// - /// On most platforms this will produce a value with the same bytes as the original - /// pointer, because all the bytes are dedicated to describing the address. - /// Platforms which need to store additional information in the pointer may - /// perform a change of representation to produce a value containing only the address - /// portion of the pointer. What that means is up to the platform to define. + #[doc = include_str!("./docs/addr.md")] /// - /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. + /// [without_provenance]: without_provenance_mut #[must_use] #[inline(always)] #[stable(feature = "strict_provenance", since = "1.84.0")] @@ -243,26 +224,16 @@ impl<T: PointeeSized> *mut T { (self.cast(), super::metadata(self)) } - /// Returns `None` if the pointer is null, or else returns a shared reference to - /// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`] - /// must be used instead. - /// - /// For the mutable counterpart see [`as_mut`]. + #[doc = include_str!("./docs/as_ref.md")] /// - /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 - /// [`as_mut`]: #method.as_mut - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). - /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. + /// ``` + /// let ptr: *mut u8 = &mut 10u8 as *mut u8; /// - /// [`is_null`]: #method.is_null-1 + /// unsafe { + /// let val_back = &*ptr; + /// println!("We got back the value: {val_back}!"); + /// } + /// ``` /// /// # Examples /// @@ -276,20 +247,14 @@ impl<T: PointeeSized> *mut T { /// } /// ``` /// - /// # Null-unchecked version - /// - /// If you are sure the pointer can never be null and are looking for some kind of - /// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can - /// dereference the pointer directly. + /// # See Also /// - /// ``` - /// let ptr: *mut u8 = &mut 10u8 as *mut u8; + /// For the mutable counterpart see [`as_mut`]. /// - /// unsafe { - /// let val_back = &*ptr; - /// println!("We got back the value: {val_back}!"); - /// } - /// ``` + /// [`is_null`]: #method.is_null-1 + /// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1 + /// [`as_mut`]: #method.as_mut + #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")] #[inline] @@ -332,28 +297,15 @@ impl<T: PointeeSized> *mut T { unsafe { &*self } } - /// Returns `None` if the pointer is null, or else returns a shared reference to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// For the mutable counterpart see [`as_uninit_mut`]. + #[doc = include_str!("./docs/as_uninit_ref.md")] /// + /// [`is_null`]: #method.is_null-1 /// [`as_ref`]: pointer#method.as_ref-1 - /// [`as_uninit_mut`]: #method.as_uninit_mut - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion). - /// Note that because the created reference is to `MaybeUninit<T>`, the - /// source pointer can point to uninitialized memory. - /// - /// # Panics during const evaluation /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. + /// # See Also + /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`is_null`]: #method.is_null-1 + /// [`as_uninit_mut`]: #method.as_uninit_mut /// /// # Examples /// diff --git a/library/core/src/range.rs b/library/core/src/range.rs index 332ae51d848..a096a8ceafc 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -31,9 +31,7 @@ pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive}; #[doc(inline)] pub use crate::iter::Step; #[doc(inline)] -pub use crate::ops::{ - Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive, -}; +pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo}; /// A (half-open) range bounded inclusively below and exclusively above /// (`start..end` in a future edition). @@ -51,7 +49,8 @@ pub use crate::ops::{ /// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum()); /// ``` #[lang = "RangeCopy"] -#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] +#[derive(Copy, Hash)] +#[derive_const(Clone, Default, PartialEq, Eq)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct Range<Idx> { /// The lower bound of the range (inclusive). @@ -209,20 +208,20 @@ impl<T> const From<legacy::Range<T>> for Range<T> { } } -/// A range bounded inclusively below and above (`start..=end`). +/// A range bounded inclusively below and above (`start..=last`). /// -/// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. It is empty unless `start <= end`. +/// The `RangeInclusive` `start..=last` contains all values with `x >= start` +/// and `x <= last`. It is empty unless `start <= last`. /// /// # Examples /// -/// The `start..=end` syntax is a `RangeInclusive`: +/// The `start..=last` syntax is a `RangeInclusive`: /// /// ``` /// #![feature(new_range_api)] /// use core::range::RangeInclusive; /// -/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 }); +/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, last: 5 }); /// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum()); /// ``` #[lang = "RangeInclusiveCopy"] @@ -234,7 +233,7 @@ pub struct RangeInclusive<Idx> { pub start: Idx, /// The upper bound of the range (inclusive). #[unstable(feature = "new_range_api", issue = "125687")] - pub end: Idx, + pub last: Idx, } #[unstable(feature = "new_range_api", issue = "125687")] @@ -242,7 +241,7 @@ impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.start.fmt(fmt)?; write!(fmt, "..=")?; - self.end.fmt(fmt)?; + self.last.fmt(fmt)?; Ok(()) } } @@ -306,7 +305,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { #[unstable(feature = "new_range_api", issue = "125687")] #[inline] pub fn is_empty(&self) -> bool { - !(self.start <= self.end) + !(self.start <= self.last) } } @@ -335,10 +334,10 @@ impl<Idx: Step> RangeInclusive<Idx> { impl RangeInclusive<usize> { /// Converts to an exclusive `Range` for `SliceIndex` implementations. - /// The caller is responsible for dealing with `end == usize::MAX`. + /// The caller is responsible for dealing with `last == usize::MAX`. #[inline] pub(crate) const fn into_slice_range(self) -> Range<usize> { - Range { start: self.start, end: self.end + 1 } + Range { start: self.start, end: self.last + 1 } } } @@ -348,7 +347,7 @@ impl<T> RangeBounds<T> for RangeInclusive<T> { Included(&self.start) } fn end_bound(&self) -> Bound<&T> { - Included(&self.end) + Included(&self.last) } } @@ -364,7 +363,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> { Included(self.start) } fn end_bound(&self) -> Bound<&T> { - Included(self.end) + Included(self.last) } } @@ -372,7 +371,7 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> { #[unstable(feature = "new_range_api", issue = "125687")] impl<T> IntoBounds<T> for RangeInclusive<T> { fn into_bounds(self) -> (Bound<T>, Bound<T>) { - (Included(self.start), Included(self.end)) + (Included(self.start), Included(self.last)) } } @@ -381,7 +380,7 @@ impl<T> IntoBounds<T> for RangeInclusive<T> { impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> { #[inline] fn from(value: RangeInclusive<T>) -> Self { - Self::new(value.start, value.end) + Self::new(value.start, value.last) } } #[unstable(feature = "new_range_api", issue = "125687")] @@ -394,8 +393,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> { "attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)" ); - let (start, end) = value.into_inner(); - RangeInclusive { start, end } + let (start, last) = value.into_inner(); + RangeInclusive { start, last } } } @@ -426,7 +425,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> { /// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum()); /// ``` #[lang = "RangeFromCopy"] -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Hash)] +#[derive_const(Clone, PartialEq, Eq)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct RangeFrom<Idx> { /// The lower bound of the range (inclusive). @@ -544,3 +544,107 @@ impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> { Self { start: value.start } } } + +/// A range only bounded inclusively above (`..=last`). +/// +/// The `RangeToInclusive` `..=last` contains all values with `x <= last`. +/// It cannot serve as an [`Iterator`] because it doesn't have a starting point. +/// +/// # Examples +/// +/// The `..=last` syntax is a `RangeToInclusive`: +/// +/// ``` +/// #![feature(new_range_api)] +/// #![feature(new_range)] +/// assert_eq!((..=5), std::range::RangeToInclusive{ last: 5 }); +/// ``` +/// +/// It does not have an [`IntoIterator`] implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```compile_fail,E0277 +/// // error[E0277]: the trait bound `std::range::RangeToInclusive<{integer}>: +/// // std::iter::Iterator` is not satisfied +/// for i in ..=5 { +/// // ... +/// } +/// ``` +/// +/// When used as a [slicing index], `RangeToInclusive` produces a slice of all +/// array elements up to and including the index indicated by `last`. +/// +/// ``` +/// let arr = [0, 1, 2, 3, 4]; +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); // This is a `RangeToInclusive` +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); +/// ``` +/// +/// [slicing index]: crate::slice::SliceIndex +#[lang = "RangeToInclusiveCopy"] +#[doc(alias = "..=")] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[unstable(feature = "new_range_api", issue = "125687")] +pub struct RangeToInclusive<Idx> { + /// The upper bound of the range (inclusive) + #[unstable(feature = "new_range_api", issue = "125687")] + pub last: Idx, +} + +#[unstable(feature = "new_range_api", issue = "125687")] +impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "..=")?; + self.last.fmt(fmt)?; + Ok(()) + } +} + +impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> { + /// Returns `true` if `item` is contained in the range. + /// + /// # Examples + /// + /// ``` + /// assert!( (..=5).contains(&-1_000_000_000)); + /// assert!( (..=5).contains(&5)); + /// assert!(!(..=5).contains(&6)); + /// + /// assert!( (..=1.0).contains(&1.0)); + /// assert!(!(..=1.0).contains(&f32::NAN)); + /// assert!(!(..=f32::NAN).contains(&0.5)); + /// ``` + #[inline] + #[unstable(feature = "new_range_api", issue = "125687")] + pub fn contains<U>(&self, item: &U) -> bool + where + Idx: PartialOrd<U>, + U: ?Sized + PartialOrd<Idx>, + { + <Self as RangeBounds<Idx>>::contains(self, item) + } +} + +// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>> +// because underflow would be possible with (..0).into() + +#[unstable(feature = "new_range_api", issue = "125687")] +impl<T> RangeBounds<T> for RangeToInclusive<T> { + fn start_bound(&self) -> Bound<&T> { + Unbounded + } + fn end_bound(&self) -> Bound<&T> { + Included(&self.last) + } +} + +#[unstable(feature = "range_into_bounds", issue = "136903")] +impl<T> IntoBounds<T> for RangeToInclusive<T> { + fn into_bounds(self) -> (Bound<T>, Bound<T>) { + (Unbounded, Included(self.last)) + } +} diff --git a/library/core/src/range/iter.rs b/library/core/src/range/iter.rs index 1e261d8c1d9..24efd4a204a 100644 --- a/library/core/src/range/iter.rs +++ b/library/core/src/range/iter.rs @@ -164,7 +164,7 @@ impl<A: Step> IterRangeInclusive<A> { return None; } - Some(RangeInclusive { start: self.0.start, end: self.0.end }) + Some(RangeInclusive { start: self.0.start, last: self.0.end }) } } diff --git a/library/core/src/range/legacy.rs b/library/core/src/range/legacy.rs index 6723c4903f7..aa11331382d 100644 --- a/library/core/src/range/legacy.rs +++ b/library/core/src/range/legacy.rs @@ -1,10 +1,10 @@ //! # Legacy range types //! //! The types within this module will be replaced by the types -//! [`Range`], [`RangeInclusive`], and [`RangeFrom`] in the parent +//! [`Range`], [`RangeInclusive`], [`RangeToInclusive`], and [`RangeFrom`] in the parent //! module, [`core::range`]. //! //! The types here are equivalent to those in [`core::ops`]. #[doc(inline)] -pub use crate::ops::{Range, RangeFrom, RangeInclusive}; +pub use crate::ops::{Range, RangeFrom, RangeInclusive, RangeToInclusive}; diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 7dffab9b316..5c1f64bfe14 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -542,7 +542,8 @@ use crate::{convert, fmt, hint}; /// /// See the [module documentation](self) for details. #[doc(search_unbox)] -#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[derive(Copy, Debug, Hash)] +#[derive_const(PartialEq, PartialOrd, Eq, Ord)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "Result"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 0d801306984..103630aba0f 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -23,7 +23,8 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Eq> Eq for [T] {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<T: [const] Eq> const Eq for [T] {} /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). #[stable(feature = "rust1", since = "1.0.0")] @@ -34,7 +35,7 @@ impl<T: Ord> Ord for [T] { } #[inline] -fn as_underlying(x: ControlFlow<bool>) -> u8 { +const fn as_underlying(x: ControlFlow<bool>) -> u8 { // SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same // size (which isn't guaranteed but this is libcore). Because they have the same // size, it's a niched implementation, which in one byte means there can't be @@ -154,12 +155,16 @@ where } #[doc(hidden)] +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] // intermediate trait for specialization of slice's PartialOrd trait SlicePartialOrd: Sized { fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>; } #[doc(hidden)] +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] // intermediate trait for specialization of slice's PartialOrd chaining methods trait SliceChain: Sized { fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>; @@ -231,14 +236,17 @@ where } */ -impl<A: AlwaysApplicableOrd> SlicePartialOrd for A { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<A: [const] AlwaysApplicableOrd> const SlicePartialOrd for A { fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> { Some(SliceOrd::compare(left, right)) } } #[rustc_specialization_trait] -trait AlwaysApplicableOrd: SliceOrd + Ord {} +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +trait AlwaysApplicableOrd: [const] SliceOrd + [const] Ord {} macro_rules! always_applicable_ord { ($([$($p:tt)*] $t:ty,)*) => { @@ -257,6 +265,8 @@ always_applicable_ord! { } #[doc(hidden)] +#[const_trait] +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] // intermediate trait for specialization of slice's Ord trait SliceOrd: Sized { fn compare(left: &[Self], right: &[Self]) -> Ordering; @@ -282,17 +292,24 @@ impl<A: Ord> SliceOrd for A { /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same /// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. #[rustc_specialization_trait] -unsafe trait UnsignedBytewiseOrd: Ord {} +#[const_trait] +unsafe trait UnsignedBytewiseOrd: [const] Ord {} -unsafe impl UnsignedBytewiseOrd for bool {} -unsafe impl UnsignedBytewiseOrd for u8 {} -unsafe impl UnsignedBytewiseOrd for NonZero<u8> {} -unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {} -unsafe impl UnsignedBytewiseOrd for ascii::Char {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +unsafe impl const UnsignedBytewiseOrd for bool {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +unsafe impl const UnsignedBytewiseOrd for u8 {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +unsafe impl const UnsignedBytewiseOrd for NonZero<u8> {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +unsafe impl const UnsignedBytewiseOrd for Option<NonZero<u8>> {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +unsafe impl const UnsignedBytewiseOrd for ascii::Char {} // `compare_bytes` compares a sequence of unsigned bytes lexicographically, so // use it if the requirements for `UnsignedBytewiseOrd` are fulfilled. -impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A { +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<A: [const] Ord + [const] UnsignedBytewiseOrd> const SliceOrd for A { #[inline] fn compare(left: &[Self], right: &[Self]) -> Ordering { // Since the length of a slice is always less than or equal to @@ -317,7 +334,9 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A { } // Don't generate our own chaining loops for `memcmp`-able things either. -impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A { + +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl<A: [const] PartialOrd + [const] UnsignedBytewiseOrd> const SliceChain for A { #[inline] fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> { match SliceOrd::compare(left, right) { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 8e1bc0bae70..a8147d745f3 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -129,6 +129,8 @@ mod private_slice_index { #[unstable(feature = "new_range_api", issue = "125687")] impl Sealed for range::RangeInclusive<usize> {} #[unstable(feature = "new_range_api", issue = "125687")] + impl Sealed for range::RangeToInclusive<usize> {} + #[unstable(feature = "new_range_api", issue = "125687")] impl Sealed for range::RangeFrom<usize> {} impl Sealed for ops::IndexRange {} @@ -788,6 +790,45 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> { } } +/// The methods `index` and `index_mut` panic if the end of the range is out of bounds. +#[stable(feature = "inclusive_range", since = "1.26.0")] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl<T> const SliceIndex<[T]> for range::RangeToInclusive<usize> { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..=self.last).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..=self.last).get_mut(slice) + } + + #[inline] + 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.last).get_unchecked(slice) } + } + + #[inline] + 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.last).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..=self.last).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..=self.last).index_mut(slice) + } +} + /// Performs bounds checking of a range. /// /// This method is similar to [`Index::index`] for slices, but it returns a diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 4f228edf78e..a7cc943994c 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -32,7 +32,8 @@ impl const PartialEq for str { } #[stable(feature = "rust1", since = "1.0.0")] -impl Eq for str {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Eq for str {} /// Implements comparison operations on strings. /// @@ -677,11 +678,11 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::MAX { None } else { self.into_slice_range().get(slice) } + if self.last == usize::MAX { None } else { self.into_slice_range().get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } + if self.last == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { @@ -695,14 +696,14 @@ unsafe impl const SliceIndex<str> for range::RangeInclusive<usize> { } #[inline] fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::MAX { + if self.last == usize::MAX { str_index_overflow_fail(); } self.into_slice_range().index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::MAX { + if self.last == usize::MAX { str_index_overflow_fail(); } self.into_slice_range().index_mut(slice) diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 2cdee1803a9..3892f831076 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -23,7 +23,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: PartialEq),+> PartialEq for ($($T,)+) { + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$($T: [const] PartialEq),+> const PartialEq for ($($T,)+) { #[inline] fn eq(&self, other: &($($T,)+)) -> bool { $( ${ignore($T)} self.${index()} == other.${index()} )&&+ @@ -38,7 +39,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: Eq),+> Eq for ($($T,)+) + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$($T: [const] Eq),+> const Eq for ($($T,)+) {} } @@ -66,7 +68,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+) + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$($T: [const] PartialOrd),+> const PartialOrd for ($($T,)+) { #[inline] fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> { @@ -110,7 +113,8 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[stable(feature = "rust1", since = "1.0.0")] - impl<$($T: Ord),+> Ord for ($($T,)+) + #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] + impl<$($T: [const] Ord),+> const Ord for ($($T,)+) { #[inline] fn cmp(&self, other: &($($T,)+)) -> Ordering { diff --git a/library/coretests/tests/alloc.rs b/library/coretests/tests/alloc.rs index 72fdf82c1f8..a4af6fd32a1 100644 --- a/library/coretests/tests/alloc.rs +++ b/library/coretests/tests/alloc.rs @@ -56,6 +56,30 @@ fn layout_array_edge_cases() { } #[test] +fn layout_errors() { + let layout = Layout::new::<[u8; 2]>(); + // Should error if the alignment is not a power of two. + assert!(layout.align_to(3).is_err()); + + // The remaining assertions ensure that the methods error on arithmetic overflow as the + // alignment cannot overflow `isize`. + let size = layout.size(); + let size_max = isize::MAX as usize; + let align_max = size_max / size; + + assert!(layout.align_to(size_max + 1).is_err()); + + assert!(layout.repeat(align_max).is_ok()); + assert!(layout.repeat(align_max + 1).is_err()); + + assert!(layout.repeat_packed(align_max).is_ok()); + assert!(layout.repeat_packed(align_max + 1).is_err()); + + let next = Layout::from_size_align(size_max, 1).unwrap(); + assert!(layout.extend(next).is_err()); +} + +#[test] fn layout_debug_shows_log2_of_alignment() { // `Debug` is not stable, but here's what it does right now let layout = Layout::from_size_align(24576, 8192).unwrap(); diff --git a/library/coretests/tests/array.rs b/library/coretests/tests/array.rs index 30ccbbc3203..c4a8fc74fec 100644 --- a/library/coretests/tests/array.rs +++ b/library/coretests/tests/array.rs @@ -717,3 +717,10 @@ fn array_map_drops_unmapped_elements_on_panic() { assert_eq!(counter.load(Ordering::SeqCst), MAX); } } + +// This covers the `PartialEq::<[T]>::eq` impl for `[T; N]` when it returns false. +#[test] +fn array_eq() { + let not_true = [0u8] == [].as_slice(); + assert!(!not_true); +} diff --git a/library/coretests/tests/char.rs b/library/coretests/tests/char.rs index 852f073bae1..6f94065b2d9 100644 --- a/library/coretests/tests/char.rs +++ b/library/coretests/tests/char.rs @@ -220,6 +220,7 @@ fn test_escape_default() { } assert_eq!(string('\n'), "\\n"); assert_eq!(string('\r'), "\\r"); + assert_eq!(string('\t'), "\\t"); assert_eq!(string('\''), "\\'"); assert_eq!(string('"'), "\\\""); assert_eq!(string(' '), " "); @@ -417,3 +418,45 @@ fn eu_iterator_specializations() { check('\u{12340}'); check('\u{10FFFF}'); } + +#[test] +#[should_panic] +fn test_from_digit_radix_too_high() { + let _ = char::from_digit(0, 37); +} + +#[test] +fn test_from_digit_invalid_radix() { + assert!(char::from_digit(10, 9).is_none()); +} + +#[test] +#[should_panic] +fn test_to_digit_radix_too_low() { + let _ = 'a'.to_digit(1); +} + +#[test] +#[should_panic] +fn test_to_digit_radix_too_high() { + let _ = 'a'.to_digit(37); +} + +#[test] +fn test_as_ascii_invalid() { + assert!('❤'.as_ascii().is_none()); +} + +#[test] +#[should_panic] +fn test_encode_utf8_raw_buffer_too_small() { + let mut buf = [0u8; 1]; + let _ = char::encode_utf8_raw('ß'.into(), &mut buf); +} + +#[test] +#[should_panic] +fn test_encode_utf16_raw_buffer_too_small() { + let mut buf = [0u16; 1]; + let _ = char::encode_utf16_raw('𐐷'.into(), &mut buf); +} diff --git a/library/coretests/tests/cmp.rs b/library/coretests/tests/cmp.rs index 6c4e2146f91..55e35a4a725 100644 --- a/library/coretests/tests/cmp.rs +++ b/library/coretests/tests/cmp.rs @@ -215,19 +215,18 @@ fn cmp_default() { assert_eq!(Fool(false), Fool(true)); } -/* FIXME(#110395) mod const_cmp { use super::*; struct S(i32); - impl PartialEq for S { + impl const PartialEq for S { fn eq(&self, other: &Self) -> bool { self.0 == other.0 } } - impl PartialOrd for S { + impl const PartialOrd for S { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { let ret = match (self.0, other.0) { (a, b) if a > b => Ordering::Greater, @@ -247,4 +246,3 @@ mod const_cmp { const _: () = assert!(S(0) < S(1)); const _: () = assert!(S(1) > S(0)); } -*/ diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 4267fef50f8..d31eba863f5 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -17,12 +17,6 @@ const TOL: f128 = 1e-12; #[allow(unused)] const TOL_PRECISE: f128 = 1e-28; -/// First pattern over the mantissa -const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u128 = 0x00005555555555555555555555555555; - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. @@ -55,28 +49,6 @@ fn test_max_recip() { } #[test] -fn test_float_bits_conv() { - assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); - assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); - assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); - assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); - assert_biteq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); - assert_biteq!(f128::from_bits(0x40029000000000000000000000000000), 12.5); - assert_biteq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); - assert_biteq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f128::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f128::NAN.to_bits() ^ NAN_MASK2; - assert!(f128::from_bits(masked_nan1).is_nan()); - assert!(f128::from_bits(masked_nan2).is_nan()); - - assert_eq!(f128::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f128::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] fn test_from() { assert_biteq!(f128::from(false), 0.0); assert_biteq!(f128::from(true), 1.0); diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index d2818a6d768..302fd0861d7 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -19,12 +19,6 @@ const TOL_P2: f16 = 0.5; #[allow(unused)] const TOL_P4: f16 = 10.0; -/// First pattern over the mantissa -const NAN_MASK1: u16 = 0x02aa; - -/// Second pattern over the mantissa -const NAN_MASK2: u16 = 0x0155; - // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. @@ -53,27 +47,6 @@ fn test_max_recip() { } #[test] -fn test_float_bits_conv() { - assert_eq!((1f16).to_bits(), 0x3c00); - assert_eq!((12.5f16).to_bits(), 0x4a40); - assert_eq!((1337f16).to_bits(), 0x6539); - assert_eq!((-14.25f16).to_bits(), 0xcb20); - assert_biteq!(f16::from_bits(0x3c00), 1.0); - assert_biteq!(f16::from_bits(0x4a40), 12.5); - assert_biteq!(f16::from_bits(0x6539), 1337.0); - assert_biteq!(f16::from_bits(0xcb20), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f16::NAN.to_bits() ^ NAN_MASK2; - assert!(f16::from_bits(masked_nan1).is_nan()); - assert!(f16::from_bits(masked_nan2).is_nan()); - - assert_eq!(f16::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f16::from_bits(masked_nan2).to_bits(), masked_nan2); -} - -#[test] fn test_from() { assert_biteq!(f16::from(false), 0.0); assert_biteq!(f16::from(true), 1.0); diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 7b25f354da4..a1fe8b07650 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -2,12 +2,6 @@ use core::f32; use super::assert_biteq; -/// First pattern over the mantissa -const NAN_MASK1: u32 = 0x002a_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u32 = 0x0055_5555; - // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] @@ -25,25 +19,3 @@ fn test_mul_add() { assert_biteq!(f32::math::mul_add(8.9f32, inf, 3.2), inf); assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f32).to_bits(), 0x3f800000); - assert_eq!((12.5f32).to_bits(), 0x41480000); - assert_eq!((1337f32).to_bits(), 0x44a72000); - assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_biteq!(f32::from_bits(0x3f800000), 1.0); - assert_biteq!(f32::from_bits(0x41480000), 12.5); - assert_biteq!(f32::from_bits(0x44a72000), 1337.0); - assert_biteq!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f32::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f32::NAN.to_bits() ^ NAN_MASK2; - assert!(f32::from_bits(masked_nan1).is_nan()); - assert!(f32::from_bits(masked_nan2).is_nan()); - - assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); -} diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 099d85627a3..4c5a3d68d1f 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -2,12 +2,6 @@ use core::f64; use super::assert_biteq; -/// First pattern over the mantissa -const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa; - -/// Second pattern over the mantissa -const NAN_MASK2: u64 = 0x0005_5555_5555_5555; - // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] @@ -25,24 +19,3 @@ fn test_mul_add() { assert_biteq!(8.9f64.mul_add(inf, 3.2), inf); assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); } - -#[test] -fn test_float_bits_conv() { - assert_eq!((1f64).to_bits(), 0x3ff0000000000000); - assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - assert_eq!((1337f64).to_bits(), 0x4094e40000000000); - assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_biteq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_biteq!(f64::from_bits(0x4029000000000000), 12.5); - assert_biteq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_biteq!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - let masked_nan1 = f64::NAN.to_bits() ^ NAN_MASK1; - let masked_nan2 = f64::NAN.to_bits() ^ NAN_MASK2; - assert!(f64::from_bits(masked_nan1).is_nan()); - assert!(f64::from_bits(masked_nan2).is_nan()); - - assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); -} diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index c0439845a4a..31515561c63 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -30,6 +30,10 @@ trait TestableFloat: Sized { const EPS_ADD: Self; const EPS_MUL: Self; const EPS_DIV: Self; + const RAW_1: Self; + const RAW_12_DOT_5: Self; + const RAW_1337: Self; + const RAW_MINUS_14_DOT_25: Self; } impl TestableFloat for f16 { @@ -50,6 +54,10 @@ impl TestableFloat for f16 { const EPS_ADD: Self = if cfg!(miri) { 1e1 } else { 0.0 }; const EPS_MUL: Self = if cfg!(miri) { 1e3 } else { 0.0 }; const EPS_DIV: Self = if cfg!(miri) { 1e0 } else { 0.0 }; + const RAW_1: Self = Self::from_bits(0x3c00); + const RAW_12_DOT_5: Self = Self::from_bits(0x4a40); + const RAW_1337: Self = Self::from_bits(0x6539); + const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20); } impl TestableFloat for f32 { @@ -72,6 +80,10 @@ impl TestableFloat for f32 { const EPS_ADD: Self = if cfg!(miri) { 1e-3 } else { 0.0 }; const EPS_MUL: Self = if cfg!(miri) { 1e-1 } else { 0.0 }; const EPS_DIV: Self = if cfg!(miri) { 1e-4 } else { 0.0 }; + const RAW_1: Self = Self::from_bits(0x3f800000); + const RAW_12_DOT_5: Self = Self::from_bits(0x41480000); + const RAW_1337: Self = Self::from_bits(0x44a72000); + const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000); } impl TestableFloat for f64 { @@ -90,6 +102,10 @@ impl TestableFloat for f64 { const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; + const RAW_1: Self = Self::from_bits(0x3ff0000000000000); + const RAW_12_DOT_5: Self = Self::from_bits(0x4029000000000000); + const RAW_1337: Self = Self::from_bits(0x4094e40000000000); + const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000); } impl TestableFloat for f128 { @@ -108,6 +124,10 @@ impl TestableFloat for f128 { const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 }; + const RAW_1: Self = Self::from_bits(0x3fff0000000000000000000000000000); + const RAW_12_DOT_5: Self = Self::from_bits(0x40029000000000000000000000000000); + const RAW_1337: Self = Self::from_bits(0x40094e40000000000000000000000000); + const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000); } /// Determine the tolerance for values of the argument type. @@ -250,6 +270,8 @@ macro_rules! float_test { $( $( #[$f16_meta] )+ )? fn test_f16() { type $fty = f16; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } $test } @@ -257,6 +279,8 @@ macro_rules! float_test { $( $( #[$f32_meta] )+ )? fn test_f32() { type $fty = f32; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } $test } @@ -264,6 +288,8 @@ macro_rules! float_test { $( $( #[$f64_meta] )+ )? fn test_f64() { type $fty = f64; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } $test } @@ -271,6 +297,8 @@ macro_rules! float_test { $( $( #[$f128_meta] )+ )? fn test_f128() { type $fty = f128; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } $test } @@ -293,6 +321,8 @@ macro_rules! float_test { $( $( #[$f16_const_meta] )+ )? fn test_f16() { type $fty = f16; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } const { $test } } @@ -300,6 +330,8 @@ macro_rules! float_test { $( $( #[$f32_const_meta] )+ )? fn test_f32() { type $fty = f32; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } const { $test } } @@ -307,6 +339,8 @@ macro_rules! float_test { $( $( #[$f64_const_meta] )+ )? fn test_f64() { type $fty = f64; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } const { $test } } @@ -314,6 +348,8 @@ macro_rules! float_test { $( $( #[$f128_const_meta] )+ )? fn test_f128() { type $fty = f128; + #[allow(unused)] + const fn flt (x: $fty) -> $fty { x } const { $test } } } @@ -1479,3 +1515,30 @@ float_test! { assert_approx_eq!(a.algebraic_rem(b), a % b, Float::EPS_DIV); } } + +float_test! { + name: to_bits_conv, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test<Float> { + assert_biteq!(flt(1.0), Float::RAW_1); + assert_biteq!(flt(12.5), Float::RAW_12_DOT_5); + assert_biteq!(flt(1337.0), Float::RAW_1337); + assert_biteq!(flt(-14.25), Float::RAW_MINUS_14_DOT_25); + assert_biteq!(Float::RAW_1, 1.0); + assert_biteq!(Float::RAW_12_DOT_5, 12.5); + assert_biteq!(Float::RAW_1337, 1337.0); + assert_biteq!(Float::RAW_MINUS_14_DOT_25, -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + let masked_nan1 = Float::NAN.to_bits() ^ Float::NAN_MASK1; + let masked_nan2 = Float::NAN.to_bits() ^ Float::NAN_MASK2; + assert!(Float::from_bits(masked_nan1).is_nan()); + assert!(Float::from_bits(masked_nan2).is_nan()); + + assert_biteq!(Float::from_bits(masked_nan1), Float::from_bits(masked_nan1)); + assert_biteq!(Float::from_bits(masked_nan2), Float::from_bits(masked_nan2)); + } +} diff --git a/library/coretests/tests/fmt/builders.rs b/library/coretests/tests/fmt/builders.rs index ba4801f5912..156eebb1e9d 100644 --- a/library/coretests/tests/fmt/builders.rs +++ b/library/coretests/tests/fmt/builders.rs @@ -173,6 +173,21 @@ mod debug_struct { format!("{Bar:#?}") ); } + + #[test] + fn test_field_with() { + struct Foo; + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field_with("bar", |f| f.write_str("true")) + .field_with("baz", |f| f.write_str("false")) + .finish() + } + } + + assert_eq!("Foo {\n bar: true,\n baz: false,\n}", format!("{Foo:#?}")) + } } mod debug_tuple { diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index 16f116d2590..586e890befe 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -58,6 +58,36 @@ fn test_fmt_debug_of_raw_pointers() { } #[test] +fn test_fmt_debug_of_mut_reference() { + let mut x: u32 = 0; + + assert_eq!(format!("{:?}", &mut x), "0"); +} + +#[test] +fn test_default_write_impls() { + use core::fmt::Write; + + struct Buf(String); + + impl Write for Buf { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.0.write_str(s) + } + } + + let mut buf = Buf(String::new()); + buf.write_char('a').unwrap(); + + assert_eq!(buf.0, "a"); + + let mut buf = Buf(String::new()); + buf.write_fmt(format_args!("a")).unwrap(); + + assert_eq!(buf.0, "a"); +} + +#[test] fn test_estimated_capacity() { assert_eq!(format_args!("").estimated_capacity(), 0); assert_eq!(format_args!("{}", { "" }).estimated_capacity(), 0); diff --git a/library/coretests/tests/fmt/num.rs b/library/coretests/tests/fmt/num.rs index 4c145b484dd..052b16db521 100644 --- a/library/coretests/tests/fmt/num.rs +++ b/library/coretests/tests/fmt/num.rs @@ -323,3 +323,9 @@ fn test_format_debug_hex() { assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]"); assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]"); } + +#[test] +#[should_panic = "Formatting argument out of range"] +fn test_rt_width_too_long() { + let _ = format!("Hello {:width$}!", "x", width = u16::MAX as usize + 1); +} diff --git a/library/coretests/tests/hash/mod.rs b/library/coretests/tests/hash/mod.rs index 1f10a4733b0..043a3ee7423 100644 --- a/library/coretests/tests/hash/mod.rs +++ b/library/coretests/tests/hash/mod.rs @@ -53,12 +53,14 @@ fn test_writer_hasher() { assert_eq!(hash(&5_u16), 5); assert_eq!(hash(&5_u32), 5); assert_eq!(hash(&5_u64), 5); + assert_eq!(hash(&5_u128), 5); assert_eq!(hash(&5_usize), 5); assert_eq!(hash(&5_i8), 5); assert_eq!(hash(&5_i16), 5); assert_eq!(hash(&5_i32), 5); assert_eq!(hash(&5_i64), 5); + assert_eq!(hash(&5_i128), 5); assert_eq!(hash(&5_isize), 5); assert_eq!(hash(&false), 0); @@ -85,6 +87,17 @@ fn test_writer_hasher() { let ptr = ptr::without_provenance_mut::<i32>(5_usize); assert_eq!(hash(&ptr), 5); + // Use a newtype to test the `Hash::hash_slice` default implementation. + struct Byte(u8); + + impl Hash for Byte { + fn hash<H: Hasher>(&self, state: &mut H) { + state.write_u8(self.0) + } + } + + assert_eq!(hash(&[Byte(b'a')]), 97 + 1); + if cfg!(miri) { // Miri cannot hash pointers return; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b5658a9970f..5c519f3a499 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -13,8 +13,10 @@ #![feature(bool_to_result)] #![feature(bstr)] #![feature(cfg_target_has_reliable_f16_f128)] +#![feature(char_internals)] #![feature(char_max_len)] #![feature(clone_to_uninit)] +#![feature(const_cmp)] #![feature(const_convert)] #![feature(const_destruct)] #![feature(const_eval_select)] @@ -31,6 +33,7 @@ #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(cstr_display)] +#![feature(debug_closure_helpers)] #![feature(dec2flt)] #![feature(drop_guard)] #![feature(duration_constants)] @@ -81,6 +84,7 @@ #![feature(next_index)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(numfmt)] +#![feature(one_sided_range)] #![feature(option_reduce)] #![feature(pattern)] #![feature(peekable_next_if_map)] diff --git a/library/coretests/tests/num/bignum.rs b/library/coretests/tests/num/bignum.rs index f213fd5366c..6dfa496e018 100644 --- a/library/coretests/tests/num/bignum.rs +++ b/library/coretests/tests/num/bignum.rs @@ -168,25 +168,6 @@ fn test_div_rem_small() { } #[test] -fn test_div_rem() { - fn div_rem(n: u64, d: u64) -> (Big, Big) { - let mut q = Big::from_small(42); - let mut r = Big::from_small(42); - Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r); - (q, r) - } - assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0))); - assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1))); - assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1))); - assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0))); - assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4))); - assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25))); - assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0))); - assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee))); - assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0))); -} - -#[test] fn test_is_zero() { assert!(Big::from_small(0).is_zero()); assert!(!Big::from_small(3).is_zero()); diff --git a/library/coretests/tests/ops.rs b/library/coretests/tests/ops.rs index 501e0f33fe4..121718f2167 100644 --- a/library/coretests/tests/ops.rs +++ b/library/coretests/tests/ops.rs @@ -2,7 +2,8 @@ mod control_flow; mod from_residual; use core::ops::{ - Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, + Bound, Deref, DerefMut, OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeFrom, + RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; // Test the Range structs and syntax. @@ -71,6 +72,36 @@ fn test_range_to_inclusive() { } #[test] +fn test_range_contains() { + assert!(!(1u32..5).contains(&0u32)); + assert!((1u32..5).contains(&1u32)); + assert!((1u32..5).contains(&4u32)); + assert!(!(1u32..5).contains(&5u32)); + assert!(!(1u32..5).contains(&6u32)); +} + +#[test] +fn test_range_to_contains() { + assert!(!(1u32..=5).contains(&0)); + assert!((1u32..=5).contains(&1)); + assert!((1u32..=5).contains(&4)); + assert!((1u32..=5).contains(&5)); + assert!(!(1u32..=5).contains(&6)); +} + +// This test covers `RangeBounds::contains` when the start is excluded, +// which cannot be directly expressed by Rust's built-in range syntax. +#[test] +fn test_range_bounds_contains() { + let r = (Bound::Excluded(1u32), Bound::Included(5u32)); + assert!(!r.contains(&0)); + assert!(!r.contains(&1)); + assert!(r.contains(&3)); + assert!(r.contains(&5)); + assert!(!r.contains(&6)); +} + +#[test] fn test_range_is_empty() { assert!(!(0.0..10.0).is_empty()); assert!((-0.0..0.0).is_empty()); @@ -92,6 +123,34 @@ fn test_range_is_empty() { } #[test] +fn test_range_inclusive_end_bound() { + let mut r = 1u32..=1; + r.next().unwrap(); + assert!(!r.contains(&1)); +} + +#[test] +fn test_range_bounds() { + let r = (Bound::Included(1u32), Bound::Excluded(5u32)); + assert!(!r.contains(&0)); + assert!(r.contains(&1)); + assert!(r.contains(&3)); + assert!(!r.contains(&5)); + assert!(!r.contains(&6)); + + let r = (Bound::<u32>::Unbounded, Bound::Unbounded); + assert!(r.contains(&0)); + assert!(r.contains(&u32::MAX)); +} + +#[test] +fn test_one_sided_range_bound() { + assert!(matches!((..1u32).bound(), (OneSidedRangeBound::End, 1))); + assert!(matches!((1u32..).bound(), (OneSidedRangeBound::StartInclusive, 1))); + assert!(matches!((..=1u32).bound(), (OneSidedRangeBound::EndInclusive, 1))); +} + +#[test] fn test_bound_cloned_unbounded() { assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded); } @@ -240,3 +299,17 @@ fn deref_on_ref() { fn test_not_never() { if !return () {} } + +#[test] +fn test_fmt() { + let mut r = 1..=1; + assert_eq!(format!("{:?}", r), "1..=1"); + r.next().unwrap(); + assert_eq!(format!("{:?}", r), "1..=1 (exhausted)"); + + assert_eq!(format!("{:?}", 1..1), "1..1"); + assert_eq!(format!("{:?}", 1..), "1.."); + assert_eq!(format!("{:?}", ..1), "..1"); + assert_eq!(format!("{:?}", ..=1), "..=1"); + assert_eq!(format!("{:?}", ..), ".."); +} diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index c13fb96a67f..4d5138d539b 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -490,6 +490,14 @@ fn is_aligned() { } #[test] +#[should_panic = "is_aligned_to: align is not a power-of-two"] +fn invalid_is_aligned() { + let data = 42; + let ptr: *const i32 = &data; + assert!(ptr.is_aligned_to(3)); +} + +#[test] fn offset_from() { let mut a = [0; 5]; let ptr1: *mut i32 = &mut a[1]; @@ -936,12 +944,13 @@ fn test_const_swap_ptr() { assert!(*s1.0.ptr == 666); assert!(*s2.0.ptr == 1); - // Swap them back, byte-for-byte + // Swap them back, again as an array. + // FIXME(#146291): we should be swapping back at type `u8` but that currently does not work. unsafe { ptr::swap_nonoverlapping( - ptr::from_mut(&mut s1).cast::<u8>(), - ptr::from_mut(&mut s2).cast::<u8>(), - size_of::<A>(), + ptr::from_mut(&mut s1).cast::<T>(), + ptr::from_mut(&mut s2).cast::<T>(), + 1, ); } diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 57a980d6acd..21e82d43a80 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -95,6 +95,9 @@ impl Error { pub(crate) const ZERO_TIMEOUT: Self = const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); + + pub(crate) const NO_ADDRESSES: Self = + const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 1c55824ab90..7ff4af8ede8 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1257,6 +1257,108 @@ mod ref_keyword {} /// [`async`]: ../std/keyword.async.html mod return_keyword {} +#[doc(keyword = "become")] +// +/// Perform a tail-call of a function. +/// +/// <div class="warning"> +/// +/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly. +/// </div> +/// +/// When tail calling a function, instead of its stack frame being added to the +/// stack, the stack frame of the caller is directly replaced with the callee's. +/// This means that as long as a loop in a call graph only uses tail calls, the +/// stack growth will be bounded. +/// +/// This is useful for writing functional-style code (since it prevents recursion +/// from exhausting resources) or for code optimization (since a tail call +/// *might* be cheaper than a normal call, tail calls can be used in a similar +/// manner to computed goto). +/// +/// Example of using `become` to implement functional-style `fold`: +/// ``` +/// #![feature(explicit_tail_calls)] +/// #![expect(incomplete_features)] +/// +/// fn fold<T: Copy, S>(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S { +/// match slice { +/// // without `become`, on big inputs this could easily overflow the +/// // stack. using a tail call guarantees that the stack will not grow unboundedly +/// [first, rest @ ..] => become fold(rest, f(init, *first), f), +/// [] => init, +/// } +/// } +/// ``` +/// +/// Compilers can already perform "tail call optimization" -- they can replace normal +/// calls with tail calls, although there are no guarantees that this will be done. +/// However, to perform TCO, the call needs to be the last thing that happens +/// in the functions and be returned from it. This requirement is often broken +/// by drop code for locals, which is run after computing the return expression: +/// +/// ``` +/// fn example() { +/// let string = "meow".to_owned(); +/// println!("{string}"); +/// return help(); // this is *not* the last thing that happens in `example`... +/// } +/// +/// // ... because it is desugared to this: +/// fn example_desugared() { +/// let string = "meow".to_owned(); +/// println!("{string}"); +/// let tmp = help(); +/// drop(string); +/// return tmp; +/// } +/// +/// fn help() {} +/// ``` +/// +/// For this reason, `become` also changes the drop order, such that locals are +/// dropped *before* evaluating the call. +/// +/// In order to guarantee that the compiler can perform a tail call, `become` +/// currently has these requirements: +/// 1. callee and caller must have the same ABI, arguments, and return type +/// 2. callee and caller must not have varargs +/// 3. caller must not be marked with `#[track_caller]` +/// - callee is allowed to be marked with `#[track_caller]` as otherwise +/// adding `#[track_caller]` would be a breaking change. if callee is +/// marked with `#[track_caller]` a tail call is not guaranteed. +/// 4. callee and caller cannot be a closure +/// (unless it's coerced to a function pointer) +/// +/// It is possible to tail-call a function pointer: +/// ``` +/// #![feature(explicit_tail_calls)] +/// #![expect(incomplete_features)] +/// +/// #[derive(Copy, Clone)] +/// enum Inst { Inc, Dec } +/// +/// fn dispatch(stream: &[Inst], state: u32) -> u32 { +/// const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement]; +/// match stream { +/// [inst, rest @ ..] => become TABLE[*inst as usize](rest, state), +/// [] => state, +/// } +/// } +/// +/// fn increment(stream: &[Inst], state: u32) -> u32 { +/// become dispatch(stream, state + 1) +/// } +/// +/// fn decrement(stream: &[Inst], state: u32) -> u32 { +/// become dispatch(stream, state - 1) +/// } +/// +/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc]; +/// assert_eq!(dispatch(program, 0), 2); +/// ``` +mod become_keyword {} + #[doc(keyword = "self")] // /// The receiver of a method, or the current module. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 97db0d6ab75..33e3bf0c085 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -284,7 +284,6 @@ #![feature(core_float_math)] #![feature(decl_macro)] #![feature(deprecated_suggestion)] -#![feature(derive_const)] #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(doc_masked)] @@ -332,11 +331,7 @@ #![feature(cfg_select)] #![feature(char_internals)] #![feature(clone_to_uninit)] -#![feature(const_cmp)] #![feature(const_convert)] -#![feature(const_ops)] -#![feature(const_option_ops)] -#![feature(const_try)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(drop_guard)] @@ -350,6 +345,7 @@ #![feature(float_gamma)] #![feature(float_minimum_maximum)] #![feature(fmt_internals)] +#![feature(fn_ptr_trait)] #![feature(generic_atomic)] #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index ddd3b68dd2d..40f1a93e39d 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -34,7 +34,6 @@ pub use self::tcp::IntoIncoming; pub use self::tcp::{Incoming, TcpListener, TcpStream}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::udp::UdpSocket; -use crate::io::{self, ErrorKind}; mod ip_addr; mod socket_addr; @@ -67,23 +66,3 @@ pub enum Shutdown { #[stable(feature = "rust1", since = "1.0.0")] Both, } - -fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> -where - F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>, -{ - let addrs = match addr.to_socket_addrs() { - Ok(addrs) => addrs, - Err(e) => return f(Err(e)), - }; - let mut last_err = None; - for addr in addrs { - match f(Ok(&addr)) { - Ok(l) => return Ok(l), - Err(e) => last_err = Some(e), - } - } - Err(last_err.unwrap_or_else(|| { - io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses") - })) -} diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 10685b49319..ae50f531a71 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -167,7 +167,7 @@ impl TcpStream { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { - super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) + net_imp::TcpStream::connect(addr).map(TcpStream) } /// Opens a TCP connection to a remote host with a timeout. @@ -782,7 +782,7 @@ impl TcpListener { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { - super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) + net_imp::TcpListener::bind(addr).map(TcpListener) } /// Returns the local socket address of this listener. diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 03003037b29..7c7ef7b2f70 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -1,5 +1,5 @@ use crate::io::prelude::*; -use crate::io::{BorrowedBuf, IoSlice, IoSliceMut}; +use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut}; use crate::mem::MaybeUninit; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::net::*; diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index a97b3299774..72e292e3d15 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -120,7 +120,7 @@ impl UdpSocket { /// [`Ipv4Addr::UNSPECIFIED`] or [`Ipv6Addr::UNSPECIFIED`]. #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { - super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) + net_imp::UdpSocket::bind(addr).map(UdpSocket) } /// Receives a single datagram message on the socket. On success, returns the number @@ -677,7 +677,7 @@ impl UdpSocket { /// on the platform. #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { - super::each_addr(addr, |addr| self.0.connect(addr)) + self.0.connect(addr) } /// Sends data on the socket to the remote address to which it is connected. diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 91da3135f97..0638b36c54f 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -1,3 +1,4 @@ +use crate::io::ErrorKind; use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 19663e4a9df..70ba502d684 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3037,6 +3037,14 @@ impl Path { /// /// This is an alias to [`fs::canonicalize`]. /// + /// # Errors + /// + /// This method will return an error in the following situations, but is not + /// limited to just these cases: + /// + /// * `path` does not exist. + /// * A non-final component in path is not a directory. + /// /// # Examples /// /// ```no_run diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 712ce03f90b..8988126bd90 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -1,4 +1,5 @@ use crate::fmt; +use crate::panic::RefUnwindSafe; use crate::sync::nonpoison::{Condvar, Mutex}; /// A barrier enables multiple threads to synchronize the beginning @@ -31,6 +32,9 @@ pub struct Barrier { num_threads: usize, } +#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] +impl RefUnwindSafe for Barrier {} + // The inner state of a double barrier struct BarrierState { count: usize, diff --git a/library/std/src/sync/nonpoison/condvar.rs b/library/std/src/sync/nonpoison/condvar.rs index 49afdd87818..994fc6816a0 100644 --- a/library/std/src/sync/nonpoison/condvar.rs +++ b/library/std/src/sync/nonpoison/condvar.rs @@ -198,11 +198,10 @@ impl Condvar { /// the system time. This function is susceptible to spurious wakeups. /// Condition variables normally have a boolean predicate associated with /// them, and the predicate must always be checked each time this function - /// returns to protect against spurious wakeups. Additionally, it is - /// typically desirable for the timeout to not exceed some duration in - /// spite of spurious wakes, thus the sleep-duration is decremented by the - /// amount slept. Alternatively, use the `wait_timeout_while` method - /// to wait with a timeout while a predicate is true. + /// returns to protect against spurious wakeups. Furthermore, since the timeout + /// is given relative to the moment this function is called, it needs to be adjusted + /// when this function is called in a loop. The [`wait_timeout_while`] method + /// lets you wait with a timeout while a predicate is true, taking care of all these concerns. /// /// The returned [`WaitTimeoutResult`] value indicates if the timeout is /// known to have elapsed. diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs index 5dc2b510f3a..de625a6cc5f 100644 --- a/library/std/src/sync/poison/condvar.rs +++ b/library/std/src/sync/poison/condvar.rs @@ -269,11 +269,10 @@ impl Condvar { /// the system time. This function is susceptible to spurious wakeups. /// Condition variables normally have a boolean predicate associated with /// them, and the predicate must always be checked each time this function - /// returns to protect against spurious wakeups. Additionally, it is - /// typically desirable for the timeout to not exceed some duration in - /// spite of spurious wakes, thus the sleep-duration is decremented by the - /// amount slept. Alternatively, use the `wait_timeout_while` method - /// to wait with a timeout while a predicate is true. + /// returns to protect against spurious wakeups. Furthermore, since the timeout + /// is given relative to the moment this function is called, it needs to be adjusted + /// when this function is called in a loop. The [`wait_timeout_while`] method + /// lets you wait with a timeout while a predicate is true, taking care of all these concerns. /// /// The returned [`WaitTimeoutResult`] value indicates if the timeout is /// known to have elapsed. diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 8c115015580..2dbdc8a4e02 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -31,6 +31,7 @@ pub mod process; pub mod random; pub mod stdio; pub mod sync; +pub mod thread; pub mod thread_local; // FIXME(117276): remove this, move feature implementations into individual diff --git a/library/std/src/sys/net/connection/mod.rs b/library/std/src/sys/net/connection/mod.rs new file mode 100644 index 00000000000..7f9636a8ccf --- /dev/null +++ b/library/std/src/sys/net/connection/mod.rs @@ -0,0 +1,57 @@ +cfg_select! { + any( + all(target_family = "unix", not(target_os = "l4re")), + target_os = "windows", + target_os = "hermit", + all(target_os = "wasi", target_env = "p2"), + target_os = "solid_asp3", + ) => { + mod socket; + pub use socket::*; + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + pub use sgx::*; + } + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::*; + } + target_os = "xous" => { + mod xous; + pub use xous::*; + } + target_os = "uefi" => { + mod uefi; + pub use uefi::*; + } + _ => { + mod unsupported; + pub use unsupported::*; + } +} + +#[cfg_attr( + // Make sure that this is used on some platforms at least. + not(any(target_os = "linux", target_os = "windows")), + allow(dead_code) +)] +fn each_addr<A: crate::net::ToSocketAddrs, F, T>(addr: A, mut f: F) -> crate::io::Result<T> +where + F: FnMut(&crate::net::SocketAddr) -> crate::io::Result<T>, +{ + use crate::io::Error; + + let mut last_err = None; + for addr in addr.to_socket_addrs()? { + match f(&addr) { + Ok(l) => return Ok(l), + Err(e) => last_err = Some(e), + } + } + + match last_err { + Some(err) => Err(err), + None => Err(Error::NO_ADDRESSES), + } +} diff --git a/library/std/src/sys/net/connection/sgx.rs b/library/std/src/sys/net/connection/sgx.rs index 2389fd1bcb6..9b54571997d 100644 --- a/library/std/src/sys/net/connection/sgx.rs +++ b/library/std/src/sys/net/connection/sgx.rs @@ -1,3 +1,5 @@ +use crate::error; +use crate::fmt::{self, Write}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::Arc; @@ -5,7 +7,6 @@ use crate::sys::abi::usercalls; use crate::sys::fd::FileDesc; use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported}; use crate::time::Duration; -use crate::{error, fmt}; const DEFAULT_FAKE_TTL: u32 = 64; @@ -63,18 +64,52 @@ impl fmt::Debug for TcpStream { } } -fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> { - match result { - Ok(saddr) => Ok(saddr.to_string()), - // need to downcast twice because io::Error::into_inner doesn't return the original - // value if the conversion fails - Err(e) => { - if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() { - Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host) - } else { - Err(e) +/// Converts each address in `addr` into a hostname. +/// +/// SGX doesn't support DNS resolution but rather accepts hostnames in +/// the same place as socket addresses. So, to make e.g. +/// ```rust +/// TcpStream::connect("example.com:80")` +/// ``` +/// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead, +/// which contains the hostname being looked up. When `.to_socket_addrs()` +/// fails, we inspect the error and try recover the hostname from it. If that +/// succeeds, we thus continue with the hostname. +/// +/// This is a terrible hack and leads to buggy code. For instance, when users +/// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs` +/// implementation to select from a list of possible URLs, the only URL used +/// will be that of the last item tried. +// FIXME: This is a terrible, terrible hack. Fixing this requires Fortanix to +// add a method for resolving addresses. +fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T> +where + F: FnMut(&str) -> io::Result<T>, +{ + match addr.to_socket_addrs() { + Ok(addrs) => { + let mut last_err = None; + let mut encoded = String::new(); + for addr in addrs { + // Format the IP address as a string, reusing the buffer. + encoded.clear(); + write!(encoded, "{}", &addr).unwrap(); + + match f(&encoded) { + Ok(val) => return Ok(val), + Err(err) => last_err = Some(err), + } + } + + match last_err { + Some(err) => Err(err), + None => Err(io::Error::NO_ADDRESSES), } } + Err(err) => match err.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()) { + Some(NonIpSockAddr { host }) => f(host), + None => Err(err), + }, } } @@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { - let addr = io_err_to_addr(addr)?; - let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?; - Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) + pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { + each_addr(addr, |addr| { + let (fd, local_addr, peer_addr) = usercalls::connect_stream(addr)?; + Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) + }) } pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> { if dur == Duration::default() { return Err(io::Error::ZERO_TIMEOUT); } - Self::connect(Ok(addr)) // FIXME: ignoring timeout + Self::connect(addr) // FIXME: ignoring timeout } pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { @@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener { } impl TcpListener { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { - let addr = io_err_to_addr(addr)?; - let (fd, local_addr) = usercalls::bind_stream(&addr)?; - Ok(TcpListener { inner: Socket::new(fd, local_addr) }) + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { + each_addr(addr, |addr| { + let (fd, local_addr) = usercalls::bind_stream(addr)?; + Ok(TcpListener { inner: Socket::new(fd, local_addr) }) + }) } pub fn socket_addr(&self) -> io::Result<SocketAddr> { @@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> { unsupported() } @@ -436,7 +473,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index f49821657d9..5200eaa5786 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -304,7 +304,8 @@ impl Socket { } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - unimplemented!() + let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } // This is used by sys_common code to abstract over Windows and Unix. diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket/mod.rs index aa83ed65d4c..564f2e3a01f 100644 --- a/library/std/src/sys/net/connection/socket.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -3,8 +3,11 @@ mod tests; use crate::ffi::{c_int, c_void}; use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::net::{ + Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, +}; use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::net::connection::each_addr; use crate::sys_common::{AsInner, FromInner}; use crate::time::Duration; use crate::{cmp, fmt, mem, ptr}; @@ -342,14 +345,15 @@ pub struct TcpStream { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { - let addr = addr?; - + pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { init(); + return each_addr(addr, inner); - let sock = Socket::new(addr, c::SOCK_STREAM)?; - sock.connect(addr)?; - Ok(TcpStream { inner: sock }) + fn inner(addr: &SocketAddr) -> io::Result<TcpStream> { + let sock = Socket::new(addr, c::SOCK_STREAM)?; + sock.connect(addr)?; + Ok(TcpStream { inner: sock }) + } } pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { @@ -512,48 +516,45 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { - let addr = addr?; - + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { init(); - - let sock = Socket::new(addr, c::SOCK_STREAM)?; - - // On platforms with Berkeley-derived sockets, this allows to quickly - // rebind a socket, without needing to wait for the OS to clean up the - // previous one. - // - // On Windows, this allows rebinding sockets which are actively in use, - // which allows “socket hijacking”, so we explicitly don't set it here. - // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse - #[cfg(not(windows))] - setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; - - // Bind our new socket - let (addr, len) = socket_addr_to_c(addr); - cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; - - cfg_select! { - target_os = "horizon" => { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result<TcpListener> { + let sock = Socket::new(addr, c::SOCK_STREAM)?; + + // On platforms with Berkeley-derived sockets, this allows to quickly + // rebind a socket, without needing to wait for the OS to clean up the + // previous one. + // + // On Windows, this allows rebinding sockets which are actively in use, + // which allows “socket hijacking”, so we explicitly don't set it here. + // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse + #[cfg(not(windows))] + setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?; + + // Bind our new socket + let (addr, len) = socket_addr_to_c(addr); + cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; + + let backlog = if cfg!(target_os = "horizon") { // The 3DS doesn't support a big connection backlog. Sometimes // it allows up to about 37, but other times it doesn't even // accept 32. There may be a global limitation causing this. - let backlog = 20; - } - target_os = "haiku" => { + 20 + } else if cfg!(target_os = "haiku") { // Haiku does not support a queue length > 32 // https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81 - let backlog = 32; - } - _ => { + 32 + } else { // The default for all other platforms - let backlog = 128; - } - } + 128 + }; - // Start listening - cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; - Ok(TcpListener { inner: sock }) + // Start listening + cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; + Ok(TcpListener { inner: sock }) + } } #[inline] @@ -639,15 +640,16 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { - let addr = addr?; - + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { init(); + return each_addr(addr, inner); - let sock = Socket::new(addr, c::SOCK_DGRAM)?; - let (addr, len) = socket_addr_to_c(addr); - cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; - Ok(UdpSocket { inner: sock }) + fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> { + let sock = Socket::new(addr, c::SOCK_DGRAM)?; + let (addr, len) = socket_addr_to_c(addr); + cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?; + Ok(UdpSocket { inner: sock }) + } } #[inline] @@ -822,9 +824,13 @@ impl UdpSocket { Ok(ret as usize) } - pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> { - let (addr, len) = socket_addr_to_c(addr?); - cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop) + pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { + return each_addr(addr, |addr| inner(self, addr)); + + fn inner(this: &UdpSocket, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = socket_addr_to_c(addr); + cvt_r(|| unsafe { c::connect(this.inner.as_raw(), addr.as_ptr(), len) }).map(drop) + } } } diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 16e3487a174..00368042873 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -1,6 +1,7 @@ +use super::each_addr; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sync::{Arc, Mutex}; use crate::sys::unsupported; use crate::time::Duration; @@ -15,13 +16,17 @@ pub struct TcpStream { } impl TcpStream { - pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { - let inner = tcp::Tcp::connect(addr?, None)?; - Ok(Self { - inner, - read_timeout: Arc::new(Mutex::new(None)), - write_timeout: Arc::new(Mutex::new(None)), - }) + pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result<TcpStream> { + let inner = tcp::Tcp::connect(addr, None)?; + Ok(TcpStream { + inner, + read_timeout: Arc::new(Mutex::new(None)), + write_timeout: Arc::new(Mutex::new(None)), + }) + } } pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> { @@ -145,7 +150,7 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> { unsupported() } @@ -195,7 +200,7 @@ impl fmt::Debug for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> { unsupported() } @@ -315,7 +320,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/unsupported.rs b/library/std/src/sys/net/connection/unsupported.rs index da217439626..fbc86343272 100644 --- a/library/std/src/sys/net/connection/unsupported.rs +++ b/library/std/src/sys/net/connection/unsupported.rs @@ -1,13 +1,13 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::sys::unsupported; use crate::time::Duration; pub struct TcpStream(!); impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { + pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> { unsupported() } @@ -121,7 +121,7 @@ impl fmt::Debug for TcpStream { pub struct TcpListener(!); impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> { unsupported() } @@ -171,7 +171,7 @@ impl fmt::Debug for TcpListener { pub struct UdpSocket(!); impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> { unsupported() } @@ -291,7 +291,7 @@ impl UdpSocket { self.0 } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> { self.0 } } diff --git a/library/std/src/sys/net/connection/wasip1.rs b/library/std/src/sys/net/connection/wasip1.rs index 951dc65e5b4..cdfa25c8a44 100644 --- a/library/std/src/sys/net/connection/wasip1.rs +++ b/library/std/src/sys/net/connection/wasip1.rs @@ -2,7 +2,7 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs}; use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::WasiFd; use crate::sys::{err2io, unsupported}; @@ -60,7 +60,7 @@ impl FromRawFd for Socket { } impl TcpStream { - pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { + pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> { unsupported() } @@ -212,7 +212,7 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> { unsupported() } @@ -316,7 +316,7 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> { unsupported() } @@ -436,7 +436,7 @@ impl UdpSocket { unsupported() } - pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> { unsupported() } diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs index bdf1fcd9302..8818ef2ca9a 100644 --- a/library/std/src/sys/net/connection/xous/tcplistener.rs +++ b/library/std/src/sys/net/connection/xous/tcplistener.rs @@ -2,9 +2,10 @@ use core::convert::TryInto; use core::sync::atomic::{Atomic, AtomicBool, AtomicU16, AtomicUsize, Ordering}; use super::*; -use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::{fmt, io}; macro_rules! unimpl { @@ -25,16 +26,19 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { - let mut addr = *socketaddr?; - - let fd = TcpListener::bind_inner(&mut addr)?; - return Ok(TcpListener { - fd: Arc::new(AtomicU16::new(fd)), - local: addr, - handle_count: Arc::new(AtomicUsize::new(1)), - nonblocking: Arc::new(AtomicBool::new(false)), - }); + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result<TcpListener> { + let mut addr = *addr; + let fd = TcpListener::bind_inner(&mut addr)?; + Ok(TcpListener { + fd: Arc::new(AtomicU16::new(fd)), + local: addr, + handle_count: Arc::new(AtomicUsize::new(1)), + nonblocking: Arc::new(AtomicBool::new(false)), + }) + } } /// This returns the raw fd of a Listener, so that it can also be used by the diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 54524767452..4df75453d1f 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -3,9 +3,12 @@ use core::sync::atomic::{Atomic, AtomicBool, AtomicU32, AtomicUsize, Ordering}; use super::*; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::net::{ + IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, +}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::time::Duration; macro_rules! unimpl { @@ -79,8 +82,8 @@ impl TcpStream { } } - pub fn connect(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpStream> { - Self::connect_timeout(socketaddr?, Duration::ZERO) + pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> { + each_addr(addr, |addr| Self::connect_timeout(addr, Duration::ZERO)) } pub fn connect_timeout(addr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> { diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs index 2127d3267ed..ce54ea3b79e 100644 --- a/library/std/src/sys/net/connection/xous/udp.rs +++ b/library/std/src/sys/net/connection/xous/udp.rs @@ -3,9 +3,10 @@ use core::sync::atomic::{Atomic, AtomicUsize, Ordering}; use super::*; use crate::cell::Cell; -use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; use crate::os::xous::services; use crate::sync::Arc; +use crate::sys::net::connection::each_addr; use crate::time::Duration; use crate::{fmt, io}; @@ -32,40 +33,45 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { - let addr = socketaddr?; - // Construct the request - let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; - - // Serialize the StdUdpBind structure. This is done "manually" because we don't want to - // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. - let port_bytes = addr.port().to_le_bytes(); - connect_request.raw[0] = port_bytes[0]; - connect_request.raw[1] = port_bytes[1]; - match addr.ip() { - IpAddr::V4(addr) => { - connect_request.raw[2] = 4; - for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { - *dest = src; + pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { + return each_addr(addr, inner); + + fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> { + // Construct the request + let mut connect_request = ConnectRequest { raw: [0u8; 4096] }; + + // Serialize the StdUdpBind structure. This is done "manually" because we don't want to + // make an auto-serdes (like bincode or rkyv) crate a dependency of Xous. + let port_bytes = addr.port().to_le_bytes(); + connect_request.raw[0] = port_bytes[0]; + connect_request.raw[1] = port_bytes[1]; + match addr.ip() { + IpAddr::V4(addr) => { + connect_request.raw[2] = 4; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } } - } - IpAddr::V6(addr) => { - connect_request.raw[2] = 6; - for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { - *dest = src; + IpAddr::V6(addr) => { + connect_request.raw[2] = 6; + for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) { + *dest = src; + } } } - } - let response = crate::os::xous::ffi::lend_mut( - services::net_server(), - services::NetLendMut::StdUdpBind.into(), - &mut connect_request.raw, - 0, - 4096, - ); + let response = crate::os::xous::ffi::lend_mut( + services::net_server(), + services::NetLendMut::StdUdpBind.into(), + &mut connect_request.raw, + 0, + 4096, + ); + + let Ok((_, valid)) = response else { + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")); + }; - if let Ok((_, valid)) = response { // The first four bytes should be zero upon success, and will be nonzero // for an error. let response = connect_request.raw; @@ -87,8 +93,9 @@ impl UdpSocket { )); } } + let fd = response[1] as u16; - return Ok(UdpSocket { + Ok(UdpSocket { fd, local: *addr, remote: Cell::new(None), @@ -96,9 +103,8 @@ impl UdpSocket { write_timeout: Cell::new(0), handle_count: Arc::new(AtomicUsize::new(1)), nonblocking: Cell::new(false), - }); + }) } - Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")) } pub fn peer_addr(&self) -> io::Result<SocketAddr> { @@ -198,10 +204,11 @@ impl UdpSocket { self.peek_from(buf).map(|(len, _addr)| len) } - pub fn connect(&self, maybe_addr: io::Result<&SocketAddr>) -> io::Result<()> { - let addr = maybe_addr?; - self.remote.set(Some(*addr)); - Ok(()) + pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> { + each_addr(addr, |addr| { + self.remote.set(Some(*addr)); + Ok(()) + }) } pub fn send(&self, buf: &[u8]) -> io::Result<usize> { diff --git a/library/std/src/sys/net/mod.rs b/library/std/src/sys/net/mod.rs index 5df1fe138ab..dffc4ea7f81 100644 --- a/library/std/src/sys/net/mod.rs +++ b/library/std/src/sys/net/mod.rs @@ -1,46 +1,4 @@ -cfg_select! { - any( - all(target_family = "unix", not(target_os = "l4re")), - target_os = "windows", - target_os = "hermit", - all(target_os = "wasi", target_env = "p2"), - target_os = "solid_asp3", - ) => { - mod connection { - mod socket; - pub use socket::*; - } - } - all(target_vendor = "fortanix", target_env = "sgx") => { - mod connection { - mod sgx; - pub use sgx::*; - } - } - all(target_os = "wasi", target_env = "p1") => { - mod connection { - mod wasip1; - pub use wasip1::*; - } - } - target_os = "xous" => { - mod connection { - mod xous; - pub use xous::*; - } - } - target_os = "uefi" => { - mod connection { - mod uefi; - pub use uefi::*; - } - } - _ => { - mod connection { - mod unsupported; - pub use unsupported::*; - } - } -} - +/// This module contains the implementations of `TcpStream`, `TcpListener` and +/// `UdpSocket` as well as related functionality like DNS resolving. +mod connection; pub use connection::*; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index fb8d69b7375..3ddf6e5acb0 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -25,7 +25,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod time; pub fn unsupported<T>() -> crate::io::Result<T> { diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 0fe713a503b..9681964ed9b 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -3,7 +3,7 @@ use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; use crate::sys::unsupported; -use crate::{fmt, io, str}; +use crate::{fmt, io}; pub fn errno() -> i32 { unsafe { hermit_abi::get_errno() } diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 89a427ab88b..f76a5f96c87 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -25,15 +25,8 @@ impl Timespec { Timespec { t: timespec { tv_sec, tv_nsec } } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { - // FIXME: const PartialOrd - let mut cmp = self.t.tv_sec - other.t.tv_sec; - if cmp == 0 { - cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64; - } - - if cmp >= 0 { + fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { + if self >= other { Ok(if self.t.tv_nsec >= other.t.tv_nsec { Duration::new( (self.t.tv_sec - other.t.tv_sec) as u64, @@ -53,22 +46,20 @@ impl Timespec { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { + fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?; // Nano calculations can't overflow because nanos are <1B which fit // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; + let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); + if nsec >= NSEC_PER_SEC.try_into().unwrap() { + nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); secs = secs.checked_add(1)?; } Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { + fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?; // Similar to above, nanos can't overflow. @@ -222,18 +213,15 @@ impl SystemTime { SystemTime(time) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { self.0.sub_timespec(&other.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add_duration(other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub_duration(other)?)) } } diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs index 57247cffad3..b8c4d7740c4 100644 --- a/library/std/src/sys/pal/sgx/abi/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/mod.rs @@ -67,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 let tls_guard = unsafe { tls.activate() }; if secondary { - let join_notifier = super::thread::Thread::entry(); + let join_notifier = crate::sys::thread::Thread::entry(); drop(tls_guard); drop(join_notifier); diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 4a297b6823f..9a33873af58 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -13,7 +13,6 @@ mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod thread_parking; pub mod time; pub mod waitqueue; diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs index 603dae952ab..db4cf2804bf 100644 --- a/library/std/src/sys/pal/sgx/time.rs +++ b/library/std/src/sys/pal/sgx/time.rs @@ -32,22 +32,15 @@ impl SystemTime { SystemTime(usercalls::insecure_time()) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add(*other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 0011cf256df..9ca6dc58118 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -10,10 +10,8 @@ pub mod itron { pub mod error; pub mod spin; pub mod task; - pub mod thread; pub mod thread_parking; pub mod time; - use super::unsupported; } // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as @@ -22,7 +20,7 @@ pub(crate) mod error; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub use self::itron::{thread, thread_parking}; +pub use self::itron::thread_parking; pub mod time; // SAFETY: must be called only once during runtime initialization. diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index e35e60df1a0..c39d715c6a6 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -39,8 +39,7 @@ impl SystemTime { Self(t) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { if self.0 >= other.0 { Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64))) } else { @@ -48,13 +47,11 @@ impl SystemTime { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?)) } } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index c7b17777258..dd0155265da 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -9,7 +9,6 @@ pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; #[allow(non_upper_case_globals)] #[path = "../unix/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 8911a2ee519..ebd311db1e1 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -17,7 +17,6 @@ pub mod helpers; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod time; #[cfg(test)] diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs deleted file mode 100644 index 47a48008c76..00000000000 --- a/library/std/src/sys/pal/uefi/thread.rs +++ /dev/null @@ -1,66 +0,0 @@ -use super::unsupported; -use crate::ffi::CStr; -use crate::io; -use crate::num::NonZero; -use crate::ptr::NonNull; -use crate::time::{Duration, Instant}; - -pub struct Thread(!); - -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new( - _stack: usize, - _name: Option<&str>, - _p: Box<dyn FnOnce()>, - ) -> io::Result<Thread> { - unsupported() - } - - pub fn yield_now() { - // do nothing - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(dur: Duration) { - let boot_services: NonNull<r_efi::efi::BootServices> = - crate::os::uefi::env::boot_services().expect("can't sleep").cast(); - let mut dur_ms = dur.as_micros(); - // ceil up to the nearest microsecond - if dur.subsec_nanos() % 1000 > 0 { - dur_ms += 1; - } - - while dur_ms > 0 { - let ms = crate::cmp::min(dur_ms, usize::MAX as u128); - let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) }; - dur_ms -= ms; - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - - pub fn join(self) { - self.0 - } -} - -pub(crate) fn current_os_id() -> Option<u64> { - None -} - -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - // UEFI is single threaded - Ok(NonZero::new(1).unwrap()) -} diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 36ce3f7ef96..c6636626fd5 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -80,32 +80,19 @@ impl SystemTime { .unwrap_or_else(|| panic!("time not implemented on this platform")) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { - let temp = self.0.checked_add(*other)?; + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + let temp = Self(self.0.checked_add(*other)?); // Check if can be represented in UEFI - // FIXME: const PartialOrd - let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs(); - if cmp == 0 { - cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64; - } - - if cmp <= 0 { Some(SystemTime(temp)) } else { None } + if temp <= MAX_UEFI_TIME { Some(temp) } else { None } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { - Some(SystemTime(self.0.checked_sub(*other)?)) + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + self.0.checked_sub(*other).map(Self) } } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index ac5c823a1bf..dd1059fe04a 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -17,7 +17,6 @@ pub mod os; pub mod pipe; pub mod stack_overflow; pub mod sync; -pub mod thread; pub mod thread_parking; pub mod time; @@ -55,7 +54,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. if cfg!(target_vendor = "apple") { - thread::Thread::set_name(&c"main"); + crate::sys::thread::set_name(c"main"); } unsafe fn sanitize_standard_fds() { diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 328fe0bc960..bd7f74fea6a 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -38,18 +38,15 @@ impl SystemTime { SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { self.t.sub_timespec(&other.t) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime { t: self.t.checked_add_duration(other)? }) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime { t: self.t.checked_sub_duration(other)? }) } } @@ -136,15 +133,8 @@ impl Timespec { Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap() } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { - // FIXME: const PartialOrd - let mut cmp = self.tv_sec - other.tv_sec; - if cmp == 0 { - cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64; - } - - if cmp >= 0 { + pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { + if self >= other { // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM // to optimize it into a branchless form (see also #75545): // @@ -179,8 +169,7 @@ impl Timespec { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?; // Nano calculations can't overflow because nanos are <1B which fit @@ -190,11 +179,10 @@ impl Timespec { nsec -= NSEC_PER_SEC as u32; secs = secs.checked_add(1)?; } - Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) }) + Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?; // Similar to above, nanos can't overflow. @@ -203,7 +191,7 @@ impl Timespec { nsec += NSEC_PER_SEC as i32; secs = secs.checked_sub(1)?; } - Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) }) + Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) } #[allow(dead_code)] diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index c8cf75b876c..a3b980a3f3d 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -22,11 +22,24 @@ #![allow(dead_code, unused_macros)] #![forbid(unsafe_op_in_unsafe_fn)] -use crate::ffi::CStr; -use crate::marker::PhantomData; -use crate::sync::atomic::{self, Atomic, AtomicPtr, Ordering}; +use crate::ffi::{CStr, c_char, c_void}; +use crate::marker::{FnPtr, PhantomData}; +use crate::sync::atomic::{Atomic, AtomicPtr, Ordering}; use crate::{mem, ptr}; +// We currently only test `dlsym!`, but that doesn't work on all platforms, so +// we gate the tests to only the platforms where it is actually used. +// +// FIXME(joboet): add more tests, reorganise the whole module and get rid of +// `#[allow(dead_code, unused_macros)]`. +#[cfg(any( + target_vendor = "apple", + all(target_os = "linux", target_env = "gnu"), + target_os = "freebsd", +))] +#[cfg(test)] +mod tests; + // We can use true weak linkage on ELF targets. #[cfg(all(unix, not(target_vendor = "apple")))] pub(crate) macro weak { @@ -64,7 +77,7 @@ impl<F: Copy> ExternWeak<F> { pub(crate) macro dlsym { (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( - dlsym!( + dlsym!( #[link_name = stringify!($name)] fn $name($($param : $t),*) -> $ret; ); @@ -73,21 +86,39 @@ pub(crate) macro dlsym { #[link_name = $sym:expr] fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty; ) => ( - static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = - DlsymWeak::new(concat!($sym, '\0')); + static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = { + let Ok(name) = CStr::from_bytes_with_nul(concat!($sym, '\0').as_bytes()) else { + panic!("symbol name may not contain NUL") + }; + + // SAFETY: Whoever calls the function pointer returned by `get()` + // is responsible for ensuring that the signature is correct. Just + // like with extern blocks, this is syntactically enforced by making + // the function pointer be unsafe. + unsafe { DlsymWeak::new(name) } + }; + let $name = &DLSYM; ) } + pub(crate) struct DlsymWeak<F> { - name: &'static str, + /// A pointer to the nul-terminated name of the symbol. + // Use a pointer instead of `&'static CStr` to save space. + name: *const c_char, func: Atomic<*mut libc::c_void>, _marker: PhantomData<F>, } -impl<F> DlsymWeak<F> { - pub(crate) const fn new(name: &'static str) -> Self { +impl<F: FnPtr> DlsymWeak<F> { + /// # Safety + /// + /// If the signature of `F` does not match the signature of the symbol (if + /// it exists), calling the function pointer returned by `get()` is + /// undefined behaviour. + pub(crate) const unsafe fn new(name: &'static CStr) -> Self { DlsymWeak { - name, + name: name.as_ptr(), func: AtomicPtr::new(ptr::without_provenance_mut(1)), _marker: PhantomData, } @@ -95,62 +126,59 @@ impl<F> DlsymWeak<F> { #[inline] pub(crate) fn get(&self) -> Option<F> { - unsafe { - // Relaxed is fine here because we fence before reading through the - // pointer (see the comment below). - match self.func.load(Ordering::Relaxed) { - func if func.addr() == 1 => self.initialize(), - func if func.is_null() => None, - func => { - let func = mem::transmute_copy::<*mut libc::c_void, F>(&func); - // The caller is presumably going to read through this value - // (by calling the function we've dlsymed). This means we'd - // need to have loaded it with at least C11's consume - // ordering in order to be guaranteed that the data we read - // from the pointer isn't from before the pointer was - // stored. Rust has no equivalent to memory_order_consume, - // so we use an acquire fence (sorry, ARM). - // - // Now, in practice this likely isn't needed even on CPUs - // where relaxed and consume mean different things. The - // symbols we're loading are probably present (or not) at - // init, and even if they aren't the runtime dynamic loader - // is extremely likely have sufficient barriers internally - // (possibly implicitly, for example the ones provided by - // invoking `mprotect`). - // - // That said, none of that's *guaranteed*, and so we fence. - atomic::fence(Ordering::Acquire); - Some(func) - } - } + // The caller is presumably going to read through this value + // (by calling the function we've dlsymed). This means we'd + // need to have loaded it with at least C11's consume + // ordering in order to be guaranteed that the data we read + // from the pointer isn't from before the pointer was + // stored. Rust has no equivalent to memory_order_consume, + // so we use an acquire load (sorry, ARM). + // + // Now, in practice this likely isn't needed even on CPUs + // where relaxed and consume mean different things. The + // symbols we're loading are probably present (or not) at + // init, and even if they aren't the runtime dynamic loader + // is extremely likely have sufficient barriers internally + // (possibly implicitly, for example the ones provided by + // invoking `mprotect`). + // + // That said, none of that's *guaranteed*, so we use acquire. + match self.func.load(Ordering::Acquire) { + func if func.addr() == 1 => self.initialize(), + func if func.is_null() => None, + // SAFETY: + // `func` is not null and `F` implements `FnPtr`, thus this + // transmutation is well-defined. It is the responsibility of the + // creator of this `DlsymWeak` to ensure that calling the resulting + // function pointer does not result in undefined behaviour (though + // the `dlsym!` macro delegates this responsibility to the caller + // of the function by using `unsafe` function pointers). + // FIXME: use `transmute` once it stops complaining about generics. + func => Some(unsafe { mem::transmute_copy::<*mut c_void, F>(&func) }), } } // Cold because it should only happen during first-time initialization. #[cold] - unsafe fn initialize(&self) -> Option<F> { - assert_eq!(size_of::<F>(), size_of::<*mut libc::c_void>()); - - let val = unsafe { fetch(self.name) }; - // This synchronizes with the acquire fence in `get`. + fn initialize(&self) -> Option<F> { + // SAFETY: `self.name` was created from a `&'static CStr` and is + // therefore a valid C string pointer. + let val = unsafe { libc::dlsym(libc::RTLD_DEFAULT, self.name) }; + // This synchronizes with the acquire load in `get`. self.func.store(val, Ordering::Release); if val.is_null() { None } else { + // SAFETY: see the comment in `get`. + // FIXME: use `transmute` once it stops complaining about generics. Some(unsafe { mem::transmute_copy::<*mut libc::c_void, F>(&val) }) } } } -unsafe fn fetch(name: &str) -> *mut libc::c_void { - let name = match CStr::from_bytes_with_nul(name.as_bytes()) { - Ok(cstr) => cstr, - Err(..) => return ptr::null_mut(), - }; - unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) } -} +unsafe impl<F> Send for DlsymWeak<F> {} +unsafe impl<F> Sync for DlsymWeak<F> {} #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { diff --git a/library/std/src/sys/pal/unix/weak/tests.rs b/library/std/src/sys/pal/unix/weak/tests.rs new file mode 100644 index 00000000000..d807ba64e35 --- /dev/null +++ b/library/std/src/sys/pal/unix/weak/tests.rs @@ -0,0 +1,32 @@ +use super::*; + +#[test] +fn dlsym_existing() { + const TEST_STRING: &'static CStr = c"Ferris!"; + + // Try to find a symbol that definitely exists. + dlsym! { + fn strlen(cs: *const c_char) -> usize; + } + + dlsym! { + #[link_name = "strlen"] + fn custom_name(cs: *const c_char) -> usize; + } + + let strlen = strlen.get().unwrap(); + assert_eq!(unsafe { strlen(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes()); + + let custom_name = custom_name.get().unwrap(); + assert_eq!(unsafe { custom_name(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes()); +} + +#[test] +fn dlsym_missing() { + // Try to find a symbol that definitely does not exist. + dlsym! { + fn test_symbol_that_does_not_exist() -> i32; + } + + assert!(test_symbol_that_does_not_exist.get().is_none()); +} diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs index 0c387917044..6d67b538a96 100644 --- a/library/std/src/sys/pal/unsupported/time.rs +++ b/library/std/src/sys/pal/unsupported/time.rs @@ -31,22 +31,15 @@ impl SystemTime { panic!("time not implemented on this platform") } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add(*other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/wasip1/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs index 61dd1c3f98b..ae5da3c1f77 100644 --- a/library/std/src/sys/pal/wasip1/mod.rs +++ b/library/std/src/sys/pal/wasip1/mod.rs @@ -20,7 +20,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod time; #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/pal/wasip1/thread.rs b/library/std/src/sys/pal/wasip1/thread.rs deleted file mode 100644 index e062b49bd7a..00000000000 --- a/library/std/src/sys/pal/wasip1/thread.rs +++ /dev/null @@ -1,214 +0,0 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use crate::ffi::CStr; -use crate::num::NonZero; -use crate::time::{Duration, Instant}; -use crate::{io, mem}; - -cfg_select! { - target_feature = "atomics" => { - use crate::cmp; - use crate::ptr; - use crate::sys::os; - // Add a few symbols not in upstream `libc` just yet. - mod libc { - pub use crate::ffi; - pub use libc::*; - - // defined in wasi-libc - // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108 - #[repr(C)] - union pthread_attr_union { - __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], - __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], - __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }], - } - - #[repr(C)] - pub struct pthread_attr_t { - __u: pthread_attr_union, - } - - #[allow(non_camel_case_types)] - pub type pthread_t = *mut ffi::c_void; - - pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84; - - unsafe extern "C" { - pub fn pthread_create( - native: *mut pthread_t, - attr: *const pthread_attr_t, - f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void, - value: *mut ffi::c_void, - ) -> ffi::c_int; - pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int; - pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int; - pub fn pthread_attr_setstacksize( - attr: *mut pthread_attr_t, - stack_size: libc::size_t, - ) -> ffi::c_int; - pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int; - pub fn pthread_detach(thread: pthread_t) -> ffi::c_int; - } - } - - pub struct Thread { - id: libc::pthread_t, - } - - impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } - } - } - _ => { - pub struct Thread(!); - } -} - -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - cfg_select! { - target_feature = "atomics" => { - pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> { - let p = Box::into_raw(Box::new(p)); - let mut native: libc::pthread_t = unsafe { mem::zeroed() }; - let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() }; - assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0); - - let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); - - match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); - } - }; - - let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) }; - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - unsafe { drop(Box::from_raw(p)); } - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); - } - ptr::null_mut() - } - } - } - _ => { - pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> { - crate::sys::unsupported() - } - } - } - - pub fn yield_now() { - let ret = unsafe { wasi::sched_yield() }; - debug_assert_eq!(ret, Ok(())); - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(dur: Duration) { - let mut nanos = dur.as_nanos(); - while nanos > 0 { - const USERDATA: wasi::Userdata = 0x0123_45678; - - let clock = wasi::SubscriptionClock { - id: wasi::CLOCKID_MONOTONIC, - timeout: u64::try_from(nanos).unwrap_or(u64::MAX), - precision: 0, - flags: 0, - }; - nanos -= u128::from(clock.timeout); - - let in_ = wasi::Subscription { - userdata: USERDATA, - u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } }, - }; - unsafe { - let mut event: wasi::Event = mem::zeroed(); - let res = wasi::poll_oneoff(&in_, &mut event, 1); - match (res, event) { - ( - Ok(1), - wasi::Event { - userdata: USERDATA, - error: wasi::ERRNO_SUCCESS, - type_: wasi::EVENTTYPE_CLOCK, - .. - }, - ) => {} - _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), - } - } - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - - pub fn join(self) { - cfg_select! { - target_feature = "atomics" => { - let id = mem::ManuallyDrop::new(self).id; - let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; - if ret != 0 { - rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } - _ => { - self.0 - } - } - } -} - -pub(crate) fn current_os_id() -> Option<u64> { - None -} - -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - cfg_select! { - target_feature = "atomics" => { - match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { - -1 => Err(io::Error::last_os_error()), - cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT), - } - } - _ => crate::sys::unsupported(), - } -} diff --git a/library/std/src/sys/pal/wasip1/time.rs b/library/std/src/sys/pal/wasip1/time.rs index 892661b312b..0d8d0b59ac1 100644 --- a/library/std/src/sys/pal/wasip1/time.rs +++ b/library/std/src/sys/pal/wasip1/time.rs @@ -43,34 +43,23 @@ impl SystemTime { SystemTime(current_time(wasi::CLOCKID_REALTIME)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { + pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { SystemTime(Duration::from_nanos(ts)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { - // FIXME: const TryInto - let ns = self.0.as_nanos(); - if ns <= u64::MAX as u128 { Some(ns as u64) } else { None } + pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { + self.0.as_nanos().try_into().ok() } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add(*other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 5f3fb6d6ddf..c1d89da2677 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -14,7 +14,6 @@ pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod time; #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/pal/wasip2/thread.rs b/library/std/src/sys/pal/wasip2/thread.rs deleted file mode 100644 index ad52918f15a..00000000000 --- a/library/std/src/sys/pal/wasip2/thread.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::num::NonZero; -use crate::time::{Duration, Instant}; - -pub struct Thread(!); - -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; - -impl Thread { - pub unsafe fn new( - _stack: usize, - _name: Option<&str>, - _p: Box<dyn FnOnce()>, - ) -> io::Result<Thread> { - // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled - // there is no support for threads, not even experimentally, not even in - // wasi-libc. Thus this is unconditionally unsupported. - crate::sys::unsupported() - } - - pub fn yield_now() { - // no API for this in WASIp2, but there's also no threads, so that's - // sort of expected. - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(dur: Duration) { - // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is - // entirely drained. - let mut remaining = dur.as_nanos(); - while remaining > 0 { - let amt = u64::try_from(remaining).unwrap_or(u64::MAX); - wasip2::clocks::monotonic_clock::subscribe_duration(amt).block(); - remaining -= u128::from(amt); - } - } - - pub fn sleep_until(deadline: Instant) { - match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { - // If the point in time we're sleeping to fits within a 64-bit - // number of nanoseconds then directly use `subscribe_instant`. - Ok(deadline) => { - wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); - } - // ... otherwise we're sleeping for 500+ years relative to the - // "start" of what the system is using as a clock so speed/accuracy - // is not so much of a concern. Use `sleep` instead. - Err(_) => { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - } - } - - pub fn join(self) { - self.0 - } -} - -pub(crate) fn current_os_id() -> Option<u64> { - None -} - -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - crate::sys::unsupported() -} diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs index f1f6839774b..43489183994 100644 --- a/library/std/src/sys/pal/wasip2/time.rs +++ b/library/std/src/sys/pal/wasip2/time.rs @@ -25,7 +25,7 @@ impl Instant { Some(Instant(self.0.checked_sub(*other)?)) } - pub(super) fn as_duration(&self) -> &Duration { + pub(crate) fn as_duration(&self) -> &Duration { &self.0 } } @@ -36,34 +36,23 @@ impl SystemTime { SystemTime(Duration::new(now.seconds, now.nanoseconds)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { + pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime { SystemTime(Duration::from_nanos(ts)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { - // FIXME: const TryInto - let ns = self.0.as_nanos(); - if ns <= u64::MAX as u128 { Some(ns as u64) } else { None } + pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> { + self.0.as_nanos().try_into().ok() } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add(*other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs deleted file mode 100644 index 42a7dbdf8b8..00000000000 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::ffi::CStr; -use crate::io; -use crate::num::NonZero; -use crate::sys::unsupported; -use crate::time::{Duration, Instant}; - -pub struct Thread(!); - -pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new( - _stack: usize, - _name: Option<&str>, - _p: Box<dyn FnOnce()>, - ) -> io::Result<Thread> { - unsupported() - } - - pub fn yield_now() {} - - pub fn set_name(_name: &CStr) {} - - pub fn sleep(dur: Duration) { - #[cfg(target_arch = "wasm32")] - use core::arch::wasm32 as wasm; - #[cfg(target_arch = "wasm64")] - use core::arch::wasm64 as wasm; - - use crate::cmp; - - // Use an atomic wait to block the current thread artificially with a - // timeout listed. Note that we should never be notified (return value - // of 0) or our comparison should never fail (return value of 1) so we - // should always only resume execution through a timeout (return value - // 2). - let mut nanos = dur.as_nanos(); - while nanos > 0 { - let amt = cmp::min(i64::MAX as u128, nanos); - let mut x = 0; - let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) }; - debug_assert_eq!(val, 2); - nanos -= amt; - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - - pub fn join(self) {} -} - -pub(crate) fn current_os_id() -> Option<u64> { - None -} - -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - unsupported() -} - -pub mod guard { - pub type Guard = !; - pub unsafe fn current() -> Option<Guard> { - None - } - pub unsafe fn init() -> Option<Guard> { - None - } -} diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 346c9ff88c9..a20cd0e9ac7 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -23,18 +23,9 @@ pub mod pipe; #[path = "../unsupported/time.rs"] pub mod time; -cfg_select! { - target_feature = "atomics" => { - #[path = "atomics/futex.rs"] - pub mod futex; - #[path = "atomics/thread.rs"] - pub mod thread; - } - _ => { - #[path = "../unsupported/thread.rs"] - pub mod thread; - } -} +#[cfg(target_feature = "atomics")] +#[path = "atomics/futex.rs"] +pub mod futex; #[path = "../unsupported/common.rs"] #[deny(unsafe_op_in_unsafe_fn)] diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3b6a86cbc8f..3357946b8f7 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -20,7 +20,6 @@ pub mod futex; pub mod handle; pub mod os; pub mod pipe; -pub mod thread; pub mod time; cfg_select! { not(target_vendor = "uwp") => { @@ -48,9 +47,9 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) { unsafe { stack_overflow::init(); - // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already + // Normally, `thread::spawn` will call `set_name` but since this thread already // exists, we have to call it ourselves. - thread::Thread::set_name_wide(wide_str!("main")); + crate::sys::thread::set_name_wide(wide_str!("main")); } } diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs index a948c07e0a3..0d31b80e56a 100644 --- a/library/std/src/sys/pal/windows/time.rs +++ b/library/std/src/sys/pal/windows/time.rs @@ -72,8 +72,7 @@ impl SystemTime { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - const fn from_intervals(intervals: i64) -> SystemTime { + fn from_intervals(intervals: i64) -> SystemTime { SystemTime { t: c::FILETIME { dwLowDateTime: intervals as u32, @@ -82,13 +81,11 @@ impl SystemTime { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - const fn intervals(&self) -> i64 { + fn intervals(&self) -> i64 { (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { let me = self.intervals(); let other = other.intervals(); if me >= other { @@ -98,14 +95,12 @@ impl SystemTime { } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?; Some(SystemTime::from_intervals(intervals)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?; Some(SystemTime::from_intervals(intervals)) } @@ -155,18 +150,15 @@ impl Hash for SystemTime { } } -#[rustc_const_unstable(feature = "const_system_time", issue = "144517")] -const fn checked_dur2intervals(dur: &Duration) -> Option<i64> { - // FIXME: const TryInto - let secs = dur - .as_secs() +fn checked_dur2intervals(dur: &Duration) -> Option<i64> { + dur.as_secs() .checked_mul(INTERVALS_PER_SEC)? - .checked_add(dur.subsec_nanos() as u64 / 100)?; - if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None } + .checked_add(dur.subsec_nanos() as u64 / 100)? + .try_into() + .ok() } -#[rustc_const_unstable(feature = "const_system_time", issue = "144517")] -const fn intervals2dur(intervals: u64) -> Duration { +fn intervals2dur(intervals: u64) -> Duration { Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32) } @@ -232,7 +224,7 @@ mod perf_counter { } /// A timer you can wait on. -pub(super) struct WaitableTimer { +pub(crate) struct WaitableTimer { handle: c::HANDLE, } impl WaitableTimer { diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 042c4ff862f..e673157e0eb 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -5,7 +5,6 @@ use crate::os::xous::ffi::exit; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -pub mod thread; pub mod time; #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs index d737416436e..ae8be81c0b7 100644 --- a/library/std/src/sys/pal/xous/time.rs +++ b/library/std/src/sys/pal/xous/time.rs @@ -43,22 +43,15 @@ impl SystemTime { SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) } } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - // FIXME: ok_or_else with const closures - match self.0.checked_sub(other.0) { - Some(duration) => Ok(duration), - None => Err(other.0 - self.0), - } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { + self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_add(*other)?)) } - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { + pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { Some(SystemTime(self.0.checked_sub(*other)?)) } } diff --git a/library/std/src/sys/platform_version/darwin/public_extern.rs b/library/std/src/sys/platform_version/darwin/public_extern.rs index 967cdb4920f..c0848d94798 100644 --- a/library/std/src/sys/platform_version/darwin/public_extern.rs +++ b/library/std/src/sys/platform_version/darwin/public_extern.rs @@ -77,6 +77,10 @@ use super::{current_version, pack_i32_os_version}; // NOTE: This symbol has a workaround in the compiler's symbol mangling to avoid mangling it, while // still not exposing it from non-cdylib (like `#[no_mangle]` would). #[rustc_std_internal_symbol] +// NOTE: Making this a weak symbol might not be entirely the right solution for this, `compiler_rt` +// doesn't do that, it instead makes the symbol have "hidden" visibility. But since this is placed +// in `libstd`, which might be used as a dylib, we cannot do the same here. +#[linkage = "weak"] // extern "C" is correct, Clang assumes the function cannot unwind: // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/clang/lib/CodeGen/CGObjC.cpp#L3980 // @@ -145,6 +149,7 @@ pub(super) extern "C" fn __isPlatformVersionAtLeast( /// Old entry point for availability. Used when compiling with older Clang versions. // SAFETY: Same as for `__isPlatformVersionAtLeast`. #[rustc_std_internal_symbol] +#[linkage = "weak"] pub(super) extern "C" fn __isOSVersionAtLeast(major: i32, minor: i32, subminor: i32) -> i32 { let version = pack_i32_os_version(major, minor, subminor); (version <= current_version()) as i32 diff --git a/library/std/src/sys/platform_version/darwin/tests.rs b/library/std/src/sys/platform_version/darwin/tests.rs index 76dc4482c98..17b2cc18ec0 100644 --- a/library/std/src/sys/platform_version/darwin/tests.rs +++ b/library/std/src/sys/platform_version/darwin/tests.rs @@ -28,21 +28,21 @@ fn compare_against_sw_vers() { let subminor: i32 = sw_vers.next().unwrap_or("0").parse().unwrap(); assert_eq!(sw_vers.count(), 0); + // Test directly against the lookup + assert_eq!(lookup_version().get(), pack_os_version(major as _, minor as _, subminor as _)); + // Current version is available assert_eq!(__isOSVersionAtLeast(major, minor, subminor), 1); // One lower is available - assert_eq!(__isOSVersionAtLeast(major, minor, subminor.saturating_sub(1)), 1); - assert_eq!(__isOSVersionAtLeast(major, minor.saturating_sub(1), subminor), 1); - assert_eq!(__isOSVersionAtLeast(major.saturating_sub(1), minor, subminor), 1); + assert_eq!(__isOSVersionAtLeast(major, minor, (subminor as u32).saturating_sub(1) as i32), 1); + assert_eq!(__isOSVersionAtLeast(major, (minor as u32).saturating_sub(1) as i32, subminor), 1); + assert_eq!(__isOSVersionAtLeast((major as u32).saturating_sub(1) as i32, minor, subminor), 1); // One higher isn't available assert_eq!(__isOSVersionAtLeast(major, minor, subminor + 1), 0); assert_eq!(__isOSVersionAtLeast(major, minor + 1, subminor), 0); assert_eq!(__isOSVersionAtLeast(major + 1, minor, subminor), 0); - - // Test directly against the lookup - assert_eq!(lookup_version().get(), pack_os_version(major as _, minor as _, subminor as _)); } #[test] diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs index 49e15d65f25..17d99cdb385 100644 --- a/library/std/src/sys/sync/once/queue.rs +++ b/library/std/src/sys/sync/once/queue.rs @@ -276,7 +276,9 @@ fn wait( // If the managing thread happens to signal and unpark us before we // can park ourselves, the result could be this thread never gets // unparked. Luckily `park` comes with the guarantee that if it got - // an `unpark` just before on an unparked thread it does not park. + // an `unpark` just before on an unparked thread it does not park. Crucially, we know + // the `unpark` must have happened between the `compare_exchange_weak` above and here, + // and there's no other `park` in that code that could steal our token. // SAFETY: we retrieved this handle on the current thread above. unsafe { node.thread.park() } } diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/thread/hermit.rs index cc4734b6819..4d9f3b114c2 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/thread/hermit.rs @@ -1,10 +1,5 @@ -#![allow(dead_code)] - -use super::hermit_abi; -use crate::ffi::CStr; -use crate::mem::ManuallyDrop; use crate::num::NonZero; -use crate::time::{Duration, Instant}; +use crate::time::Duration; use crate::{io, ptr}; pub type Tid = hermit_abi::Tid; @@ -68,57 +63,30 @@ impl Thread { } } - #[inline] - pub fn yield_now() { - unsafe { - hermit_abi::yield_now(); - } - } - - #[inline] - pub fn set_name(_name: &CStr) { - // nope - } - - #[inline] - pub fn sleep(dur: Duration) { - let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; - let micros = u64::try_from(micros).unwrap_or(u64::MAX); - - unsafe { - hermit_abi::usleep(micros); - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn join(self) { unsafe { let _ = hermit_abi::join(self.tid); } } +} - #[inline] - pub fn id(&self) -> Tid { - self.tid - } - - #[inline] - pub fn into_id(self) -> Tid { - ManuallyDrop::new(self).tid - } +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) } } -pub(crate) fn current_os_id() -> Option<u64> { - None +#[inline] +pub fn sleep(dur: Duration) { + let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; + let micros = u64::try_from(micros).unwrap_or(u64::MAX); + + unsafe { + hermit_abi::usleep(micros); + } } -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) } +#[inline] +pub fn yield_now() { + unsafe { + hermit_abi::yield_now(); + } } diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs new file mode 100644 index 00000000000..6bb7fc1a20e --- /dev/null +++ b/library/std/src/sys/thread/mod.rs @@ -0,0 +1,152 @@ +cfg_select! { + target_os = "hermit" => { + mod hermit; + pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{current_os_id, set_name}; + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + + // SGX should protect in-enclave data from outside attackers, so there + // must not be any data leakage to the OS, particularly no 1-1 mapping + // between SGX thread names and OS thread names. Hence `set_name` is + // intentionally a no-op. + // + // Note that the internally visible SGX thread name is already provided + // by the platform-agnostic Rust thread code. This can be observed in + // the [`std::thread::tests::test_named_thread`] test, which succeeds + // as-is with the SGX target. + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{available_parallelism, set_name}; + } + target_os = "solid_asp3" => { + mod solid; + pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{available_parallelism, current_os_id, set_name}; + } + target_os = "teeos" => { + mod teeos; + pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{available_parallelism, current_os_id, set_name}; + } + target_os = "uefi" => { + mod uefi; + pub use uefi::{available_parallelism, sleep}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; + } + target_family = "unix" => { + mod unix; + pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + #[cfg(not(any( + target_env = "newlib", + target_os = "l4re", + target_os = "emscripten", + target_os = "redox", + target_os = "hurd", + target_os = "aix", + )))] + pub use unix::set_name; + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + ))] + pub use unix::sleep_until; + #[expect(dead_code)] + mod unsupported; + #[cfg(any( + target_env = "newlib", + target_os = "l4re", + target_os = "emscripten", + target_os = "redox", + target_os = "hurd", + target_os = "aix", + ))] + pub use unsupported::set_name; + } + all(target_os = "wasi", target_env = "p1") => { + mod wasip1; + pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now}; + #[cfg(target_feature = "atomics")] + pub use wasip1::{Thread, available_parallelism}; + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{current_os_id, set_name}; + #[cfg(not(target_feature = "atomics"))] + pub use unsupported::{Thread, available_parallelism}; + } + all(target_os = "wasi", target_env = "p2") => { + mod wasip2; + pub use wasip2::{sleep, sleep_until}; + #[expect(dead_code)] + mod unsupported; + // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled + // there is no support for threads, not even experimentally, not even in + // wasi-libc. Thus this is unconditionally unsupported. + pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; + } + all(target_family = "wasm", target_feature = "atomics") => { + mod wasm; + pub use wasm::sleep; + + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE}; + } + target_os = "windows" => { + mod windows; + pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + } + target_os = "xous" => { + mod xous; + pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + + #[expect(dead_code)] + mod unsupported; + pub use unsupported::{current_os_id, set_name}; + } + _ => { + mod unsupported; + pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE}; + } +} + +#[cfg(not(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", + all(target_os = "wasi", target_env = "p2"), +)))] +pub fn sleep_until(deadline: crate::time::Instant) { + use crate::time::Instant; + + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + sleep(delay); + } +} diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/thread/sgx.rs index 1f613badcd7..f20ef7d86b9 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/thread/sgx.rs @@ -1,11 +1,8 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? -use super::abi::{thread, usercalls}; -use super::unsupported; -use crate::ffi::CStr; use crate::io; -use crate::num::NonZero; -use crate::time::{Duration, Instant}; +use crate::sys::pal::abi::{thread, usercalls}; +use crate::time::Duration; pub struct Thread(task_queue::JoinHandle); @@ -108,51 +105,27 @@ impl Thread { Ok(Thread(handle)) } - pub(super) fn entry() -> JoinNotifier { + pub(crate) fn entry() -> JoinNotifier { let mut pending_tasks = task_queue::lock(); let task = rtunwrap!(Some, pending_tasks.pop()); drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary task.run() } - pub fn yield_now() { - let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO)); - rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock); - } - - /// SGX should protect in-enclave data from the outside (attacker), - /// so there should be no data leakage to the OS, - /// and therefore also no 1-1 mapping between SGX thread names and OS thread names. - /// - /// This is why the method is intentionally No-Op. - pub fn set_name(_name: &CStr) { - // Note that the internally visible SGX thread name is already provided - // by the platform-agnostic (target-agnostic) Rust thread code. - // This can be observed in the [`std::thread::tests::test_named_thread`] test, - // which succeeds as-is with the SGX target. - } - - pub fn sleep(dur: Duration) { - usercalls::wait_timeout(0, dur, || true); - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn join(self) { self.0.wait(); } } -pub(crate) fn current_os_id() -> Option<u64> { +pub fn current_os_id() -> Option<u64> { Some(thread::current().addr().get() as u64) } -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - unsupported() +pub fn sleep(dur: Duration) { + usercalls::wait_timeout(0, dur, || true); +} + +pub fn yield_now() { + let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO)); + rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock); } diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/thread/solid.rs index 4e14cb3cbca..46a84faa802 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/thread/solid.rs @@ -1,16 +1,14 @@ //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and //! `exd_tsk` are available. -use super::error::{ItronError, expect_success, expect_success_aborting}; -use super::time::dur2reltims; -use super::{abi, task}; use crate::cell::UnsafeCell; -use crate::ffi::CStr; use crate::mem::ManuallyDrop; -use crate::num::NonZero; use crate::ptr::NonNull; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; -use crate::time::{Duration, Instant}; +use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting}; +use crate::sys::pal::itron::time::dur2reltims; +use crate::sys::pal::itron::{abi, task}; +use crate::time::Duration; use crate::{hint, io}; pub struct Thread { @@ -195,28 +193,6 @@ impl Thread { Ok(Self { p_inner, task: new_task }) } - pub fn yield_now() { - expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq"); - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(dur: Duration) { - for timeout in dur2reltims(dur) { - expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn join(self) { // Safety: `ThreadInner` is alive at this point let inner = unsafe { self.p_inner.as_ref() }; @@ -361,10 +337,12 @@ unsafe fn terminate_and_delete_current_task() -> ! { unsafe { crate::hint::unreachable_unchecked() }; } -pub(crate) fn current_os_id() -> Option<u64> { - None +pub fn yield_now() { + expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq"); } -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - super::unsupported() +pub fn sleep(dur: Duration) { + for timeout in dur2reltims(dur) { + expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); + } } diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/thread/teeos.rs index 1812d11e692..cad100395c9 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/thread/teeos.rs @@ -1,12 +1,18 @@ -use crate::ffi::CStr; use crate::mem::{self, ManuallyDrop}; -use crate::num::NonZero; use crate::sys::os; -use crate::time::{Duration, Instant}; +use crate::time::Duration; use crate::{cmp, io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024; +unsafe extern "C" { + safe fn TEE_Wait(timeout: u32) -> u32; +} + +fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { + libc::PTHREAD_STACK_MIN.try_into().expect("Infallible") +} + pub struct Thread { id: libc::pthread_t, } @@ -16,10 +22,6 @@ pub struct Thread { unsafe impl Send for Thread {} unsafe impl Sync for Thread {} -unsafe extern "C" { - pub fn TEE_Wait(timeout: u32) -> u32; -} - impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new( @@ -74,7 +76,7 @@ impl Thread { } else { // The new thread will start running earliest after the next yield. // We add a yield here, so that the user does not have to. - Thread::yield_now(); + yield_now(); Ok(Thread { id: native }) }; @@ -91,36 +93,6 @@ impl Thread { } } - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - /// This does not do anything on teeos - pub fn set_name(_name: &CStr) { - // Both pthread_setname_np and prctl are not available to the TA, - // so we can't implement this currently. If the need arises please - // contact the teeos rustzone team. - } - - /// only main thread could wait for sometime in teeos - pub fn sleep(dur: Duration) { - let sleep_millis = dur.as_millis(); - let final_sleep: u32 = - if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 }; - unsafe { - let _ = TEE_Wait(final_sleep); - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - /// must join, because no pthread_detach supported pub fn join(self) { let id = self.into_id(); @@ -128,10 +100,6 @@ impl Thread { assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); } - pub fn id(&self) -> libc::pthread_t { - self.id - } - pub fn into_id(self) -> libc::pthread_t { ManuallyDrop::new(self).id } @@ -144,16 +112,15 @@ impl Drop for Thread { } } -pub(crate) fn current_os_id() -> Option<u64> { - None -} - -// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on -// teeos, so this function always returns an Error! -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - Err(io::Error::UNKNOWN_THREAD_COUNT) +pub fn yield_now() { + let ret = unsafe { libc::sched_yield() }; + debug_assert_eq!(ret, 0); } -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN.try_into().expect("Infallible") +/// only main thread could wait for sometime in teeos +pub fn sleep(dur: Duration) { + let sleep_millis = dur.as_millis(); + let final_sleep: u32 = + if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 }; + TEE_Wait(final_sleep); } diff --git a/library/std/src/sys/thread/uefi.rs b/library/std/src/sys/thread/uefi.rs new file mode 100644 index 00000000000..94f67d7ace2 --- /dev/null +++ b/library/std/src/sys/thread/uefi.rs @@ -0,0 +1,25 @@ +use crate::io; +use crate::num::NonZero; +use crate::ptr::NonNull; +use crate::time::Duration; + +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + // UEFI is single threaded + Ok(NonZero::new(1).unwrap()) +} + +pub fn sleep(dur: Duration) { + let boot_services: NonNull<r_efi::efi::BootServices> = + crate::os::uefi::env::boot_services().expect("can't sleep").cast(); + let mut dur_ms = dur.as_micros(); + // ceil up to the nearest microsecond + if dur.subsec_nanos() % 1000 > 0 { + dur_ms += 1; + } + + while dur_ms > 0 { + let ms = crate::cmp::min(dur_ms, usize::MAX as u128); + let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) }; + dur_ms -= ms; + } +} diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/thread/unix.rs index 3389b8c0c8a..2d2c4f90212 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/thread/unix.rs @@ -1,3 +1,11 @@ +#[cfg(not(any( + target_env = "newlib", + target_os = "l4re", + target_os = "emscripten", + target_os = "redox", + target_os = "hurd", + target_os = "aix", +)))] use crate::ffi::CStr; use crate::mem::{self, ManuallyDrop}; use crate::num::NonZero; @@ -6,7 +14,7 @@ use crate::sys::weak::dlsym; #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))] use crate::sys::weak::weak; use crate::sys::{os, stack_overflow}; -use crate::time::{Duration, Instant}; +use crate::time::Duration; use crate::{cmp, io, ptr}; #[cfg(not(any( target_os = "l4re", @@ -121,273 +129,6 @@ impl Thread { } } - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - #[cfg(target_os = "android")] - pub fn set_name(name: &CStr) { - const PR_SET_NAME: libc::c_int = 15; - unsafe { - let res = libc::prctl( - PR_SET_NAME, - name.as_ptr(), - 0 as libc::c_ulong, - 0 as libc::c_ulong, - 0 as libc::c_ulong, - ); - // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. - debug_assert_eq!(res, 0); - } - } - - #[cfg(any( - target_os = "linux", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "nuttx", - target_os = "cygwin" - ))] - pub fn set_name(name: &CStr) { - unsafe { - cfg_select! { - any(target_os = "linux", target_os = "cygwin") => { - // Linux and Cygwin limits the allowed length of the name. - const TASK_COMM_LEN: usize = 16; - let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); - } - _ => { - // FreeBSD, DragonFly BSD and NuttX do not enforce length limits. - } - }; - // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, - // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0. - let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); - // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. - debug_assert_eq!(res, 0); - } - } - - #[cfg(target_os = "openbsd")] - pub fn set_name(name: &CStr) { - unsafe { - libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); - } - } - - #[cfg(target_vendor = "apple")] - pub fn set_name(name: &CStr) { - unsafe { - let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); - let res = libc::pthread_setname_np(name.as_ptr()); - // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. - debug_assert_eq!(res, 0); - } - } - - #[cfg(target_os = "netbsd")] - pub fn set_name(name: &CStr) { - unsafe { - let res = libc::pthread_setname_np( - libc::pthread_self(), - c"%s".as_ptr(), - name.as_ptr() as *mut libc::c_void, - ); - debug_assert_eq!(res, 0); - } - } - - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] - pub fn set_name(name: &CStr) { - weak!( - fn pthread_setname_np( - thread: libc::pthread_t, - name: *const libc::c_char, - ) -> libc::c_int; - ); - - if let Some(f) = pthread_setname_np.get() { - #[cfg(target_os = "nto")] - const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize; - #[cfg(any(target_os = "solaris", target_os = "illumos"))] - const THREAD_NAME_MAX: usize = 32; - - let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name); - let res = unsafe { f(libc::pthread_self(), name.as_ptr()) }; - debug_assert_eq!(res, 0); - } - } - - #[cfg(target_os = "fuchsia")] - pub fn set_name(name: &CStr) { - use super::fuchsia::*; - unsafe { - zx_object_set_property( - zx_thread_self(), - ZX_PROP_NAME, - name.as_ptr() as *const libc::c_void, - name.to_bytes().len(), - ); - } - } - - #[cfg(target_os = "haiku")] - pub fn set_name(name: &CStr) { - unsafe { - let thread_self = libc::find_thread(ptr::null_mut()); - let res = libc::rename_thread(thread_self, name.as_ptr()); - // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. - debug_assert_eq!(res, libc::B_OK); - } - } - - #[cfg(target_os = "vxworks")] - pub fn set_name(name: &CStr) { - let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name); - let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) }; - debug_assert_eq!(res, libc::OK); - } - - #[cfg(any( - target_env = "newlib", - target_os = "l4re", - target_os = "emscripten", - target_os = "redox", - target_os = "hurd", - target_os = "aix", - ))] - pub fn set_name(_name: &CStr) { - // Newlib and Emscripten have no way to set a thread name. - } - - #[cfg(not(target_os = "espidf"))] - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as _; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - let ts_ptr = &raw mut ts; - if libc::nanosleep(ts_ptr, ts_ptr) == -1 { - assert_eq!(os::errno(), libc::EINTR); - secs += ts.tv_sec as u64; - nsecs = ts.tv_nsec; - } else { - nsecs = 0; - } - } - } - } - - #[cfg(target_os = "espidf")] - pub fn sleep(dur: Duration) { - // ESP-IDF does not have `nanosleep`, so we use `usleep` instead. - // As per the documentation of `usleep`, it is expected to support - // sleep times as big as at least up to 1 second. - // - // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its - // `usleep` implementation - // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210), - // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow - // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default). - const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1; - - // Add any nanoseconds smaller than a microsecond as an extra microsecond - // so as to comply with the `std::thread::sleep` contract which mandates - // implementations to sleep for _at least_ the provided `dur`. - // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of - // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second - // (i.e. < 1_000_000_000) - let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; - - while micros > 0 { - let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 }; - unsafe { - libc::usleep(st); - } - - micros -= st as u128; - } - } - - // Any unix that has clock_nanosleep - // If this list changes update the MIRI chock_nanosleep shim - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "dragonfly", - target_os = "hurd", - target_os = "fuchsia", - target_os = "vxworks", - ))] - pub fn sleep_until(deadline: Instant) { - let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { - // The deadline is further in the future then can be passed to - // clock_nanosleep. We have to use Self::sleep instead. This might - // happen on 32 bit platforms, especially closer to 2038. - let now = Instant::now(); - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - return; - }; - - unsafe { - // When we get interrupted (res = EINTR) call clock_nanosleep again - loop { - let res = libc::clock_nanosleep( - super::time::Instant::CLOCK_ID, - libc::TIMER_ABSTIME, - &ts, - core::ptr::null_mut(), // not required with TIMER_ABSTIME - ); - - if res == 0 { - break; - } else { - assert_eq!( - res, - libc::EINTR, - "timespec is in range, - clockid is valid and kernel should support it" - ); - } - } - } - } - - // Any unix that does not have clock_nanosleep - #[cfg(not(any( - target_os = "freebsd", - target_os = "netbsd", - target_os = "linux", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "dragonfly", - target_os = "hurd", - target_os = "fuchsia", - target_os = "vxworks", - )))] - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn join(self) { let id = self.into_id(); let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; @@ -410,84 +151,6 @@ impl Drop for Thread { } } -pub(crate) fn current_os_id() -> Option<u64> { - // Most Unix platforms have a way to query an integer ID of the current thread, all with - // slightly different spellings. - // - // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed - // for process inspection (debuggers, trace, `top`, etc.). - cfg_select! { - // Most platforms have a function returning a `pid_t` or int, which is an `i32`. - any(target_os = "android", target_os = "linux") => { - use crate::sys::weak::syscall; - - // `libc::gettid` is only available on glibc 2.30+, but the syscall is available - // since Linux 2.4.11. - syscall!(fn gettid() -> libc::pid_t;); - - // SAFETY: FFI call with no preconditions. - let id: libc::pid_t = unsafe { gettid() }; - Some(id as u64) - } - target_os = "nto" => { - // SAFETY: FFI call with no preconditions. - let id: libc::pid_t = unsafe { libc::gettid() }; - Some(id as u64) - } - target_os = "openbsd" => { - // SAFETY: FFI call with no preconditions. - let id: libc::pid_t = unsafe { libc::getthrid() }; - Some(id as u64) - } - target_os = "freebsd" => { - // SAFETY: FFI call with no preconditions. - let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() }; - Some(id as u64) - } - target_os = "netbsd" => { - // SAFETY: FFI call with no preconditions. - let id: libc::lwpid_t = unsafe { libc::_lwp_self() }; - Some(id as u64) - } - any(target_os = "illumos", target_os = "solaris") => { - // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID. - // SAFETY: FFI call with no preconditions. - let id: libc::pthread_t = unsafe { libc::pthread_self() }; - Some(id as u64) - } - target_vendor = "apple" => { - // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread. - let mut id = 0u64; - // SAFETY: `thread_id` is a valid pointer, no other preconditions. - let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) }; - if status == 0 { - Some(id) - } else { - None - } - } - // Other platforms don't have an OS thread ID or don't have a way to access it. - _ => None, - } -} - -#[cfg(any( - target_os = "linux", - target_os = "nto", - target_os = "solaris", - target_os = "illumos", - target_os = "vxworks", - target_os = "cygwin", - target_vendor = "apple", -))] -fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { - let mut result = [0; MAX_WITH_NUL]; - for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) { - *dst = *src as libc::c_char; - } - result -} - pub fn available_parallelism() -> io::Result<NonZero<usize>> { cfg_select! { any( @@ -668,6 +331,318 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { } } +pub fn current_os_id() -> Option<u64> { + // Most Unix platforms have a way to query an integer ID of the current thread, all with + // slightly different spellings. + // + // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed + // for process inspection (debuggers, trace, `top`, etc.). + cfg_select! { + // Most platforms have a function returning a `pid_t` or int, which is an `i32`. + any(target_os = "android", target_os = "linux") => { + use crate::sys::pal::weak::syscall; + + // `libc::gettid` is only available on glibc 2.30+, but the syscall is available + // since Linux 2.4.11. + syscall!(fn gettid() -> libc::pid_t;); + + // SAFETY: FFI call with no preconditions. + let id: libc::pid_t = unsafe { gettid() }; + Some(id as u64) + } + target_os = "nto" => { + // SAFETY: FFI call with no preconditions. + let id: libc::pid_t = unsafe { libc::gettid() }; + Some(id as u64) + } + target_os = "openbsd" => { + // SAFETY: FFI call with no preconditions. + let id: libc::pid_t = unsafe { libc::getthrid() }; + Some(id as u64) + } + target_os = "freebsd" => { + // SAFETY: FFI call with no preconditions. + let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() }; + Some(id as u64) + } + target_os = "netbsd" => { + // SAFETY: FFI call with no preconditions. + let id: libc::lwpid_t = unsafe { libc::_lwp_self() }; + Some(id as u64) + } + any(target_os = "illumos", target_os = "solaris") => { + // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID. + // SAFETY: FFI call with no preconditions. + let id: libc::pthread_t = unsafe { libc::pthread_self() }; + Some(id as u64) + } + target_vendor = "apple" => { + // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread. + let mut id = 0u64; + // SAFETY: `thread_id` is a valid pointer, no other preconditions. + let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) }; + if status == 0 { + Some(id) + } else { + None + } + } + // Other platforms don't have an OS thread ID or don't have a way to access it. + _ => None, + } +} + +#[cfg(any( + target_os = "linux", + target_os = "nto", + target_os = "solaris", + target_os = "illumos", + target_os = "vxworks", + target_os = "cygwin", + target_vendor = "apple", +))] +fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] { + let mut result = [0; MAX_WITH_NUL]; + for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) { + *dst = *src as libc::c_char; + } + result +} + +#[cfg(target_os = "android")] +pub fn set_name(name: &CStr) { + const PR_SET_NAME: libc::c_int = 15; + unsafe { + let res = libc::prctl( + PR_SET_NAME, + name.as_ptr(), + 0 as libc::c_ulong, + 0 as libc::c_ulong, + 0 as libc::c_ulong, + ); + // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. + debug_assert_eq!(res, 0); + } +} + +#[cfg(any( + target_os = "linux", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "nuttx", + target_os = "cygwin" +))] +pub fn set_name(name: &CStr) { + unsafe { + cfg_select! { + any(target_os = "linux", target_os = "cygwin") => { + // Linux and Cygwin limits the allowed length of the name. + const TASK_COMM_LEN: usize = 16; + let name = truncate_cstr::<{ TASK_COMM_LEN }>(name); + } + _ => { + // FreeBSD, DragonFly BSD and NuttX do not enforce length limits. + } + }; + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux, + // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0. + let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); + // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. + debug_assert_eq!(res, 0); + } +} + +#[cfg(target_os = "openbsd")] +pub fn set_name(name: &CStr) { + unsafe { + libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr()); + } +} + +#[cfg(target_vendor = "apple")] +pub fn set_name(name: &CStr) { + unsafe { + let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name); + let res = libc::pthread_setname_np(name.as_ptr()); + // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. + debug_assert_eq!(res, 0); + } +} + +#[cfg(target_os = "netbsd")] +pub fn set_name(name: &CStr) { + unsafe { + let res = libc::pthread_setname_np( + libc::pthread_self(), + c"%s".as_ptr(), + name.as_ptr() as *mut libc::c_void, + ); + debug_assert_eq!(res, 0); + } +} + +#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] +pub fn set_name(name: &CStr) { + weak!( + fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int; + ); + + if let Some(f) = pthread_setname_np.get() { + #[cfg(target_os = "nto")] + const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize; + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + const THREAD_NAME_MAX: usize = 32; + + let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name); + let res = unsafe { f(libc::pthread_self(), name.as_ptr()) }; + debug_assert_eq!(res, 0); + } +} + +#[cfg(target_os = "fuchsia")] +pub fn set_name(name: &CStr) { + use crate::sys::pal::fuchsia::*; + unsafe { + zx_object_set_property( + zx_thread_self(), + ZX_PROP_NAME, + name.as_ptr() as *const libc::c_void, + name.to_bytes().len(), + ); + } +} + +#[cfg(target_os = "haiku")] +pub fn set_name(name: &CStr) { + unsafe { + let thread_self = libc::find_thread(ptr::null_mut()); + let res = libc::rename_thread(thread_self, name.as_ptr()); + // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked. + debug_assert_eq!(res, libc::B_OK); + } +} + +#[cfg(target_os = "vxworks")] +pub fn set_name(name: &CStr) { + let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name); + let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) }; + debug_assert_eq!(res, libc::OK); +} + +#[cfg(not(target_os = "espidf"))] +pub fn sleep(dur: Duration) { + let mut secs = dur.as_secs(); + let mut nsecs = dur.subsec_nanos() as _; + + // If we're awoken with a signal then the return value will be -1 and + // nanosleep will fill in `ts` with the remaining time. + unsafe { + while secs > 0 || nsecs > 0 { + let mut ts = libc::timespec { + tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, + tv_nsec: nsecs, + }; + secs -= ts.tv_sec as u64; + let ts_ptr = &raw mut ts; + if libc::nanosleep(ts_ptr, ts_ptr) == -1 { + assert_eq!(os::errno(), libc::EINTR); + secs += ts.tv_sec as u64; + nsecs = ts.tv_nsec; + } else { + nsecs = 0; + } + } + } +} + +#[cfg(target_os = "espidf")] +pub fn sleep(dur: Duration) { + // ESP-IDF does not have `nanosleep`, so we use `usleep` instead. + // As per the documentation of `usleep`, it is expected to support + // sleep times as big as at least up to 1 second. + // + // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its + // `usleep` implementation + // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210), + // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow + // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default). + const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1; + + // Add any nanoseconds smaller than a microsecond as an extra microsecond + // so as to comply with the `std::thread::sleep` contract which mandates + // implementations to sleep for _at least_ the provided `dur`. + // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of + // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second + // (i.e. < 1_000_000_000) + let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 }; + + while micros > 0 { + let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 }; + unsafe { + libc::usleep(st); + } + + micros -= st as u128; + } +} + +// Any unix that has clock_nanosleep +// If this list changes update the MIRI chock_nanosleep shim +#[cfg(any( + target_os = "freebsd", + target_os = "netbsd", + target_os = "linux", + target_os = "android", + target_os = "solaris", + target_os = "illumos", + target_os = "dragonfly", + target_os = "hurd", + target_os = "fuchsia", + target_os = "vxworks", +))] +pub fn sleep_until(deadline: crate::time::Instant) { + use crate::time::Instant; + + let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else { + // The deadline is further in the future then can be passed to + // clock_nanosleep. We have to use Self::sleep instead. This might + // happen on 32 bit platforms, especially closer to 2038. + let now = Instant::now(); + if let Some(delay) = deadline.checked_duration_since(now) { + sleep(delay); + } + return; + }; + + unsafe { + // When we get interrupted (res = EINTR) call clock_nanosleep again + loop { + let res = libc::clock_nanosleep( + crate::sys::time::Instant::CLOCK_ID, + libc::TIMER_ABSTIME, + &ts, + core::ptr::null_mut(), // not required with TIMER_ABSTIME + ); + + if res == 0 { + break; + } else { + assert_eq!( + res, + libc::EINTR, + "timespec is in range, + clockid is valid and kernel should support it" + ); + } + } + } +} + +pub fn yield_now() { + let ret = unsafe { libc::sched_yield() }; + debug_assert_eq!(ret, 0); +} + #[cfg(any(target_os = "android", target_os = "linux"))] mod cgroups { //! Currently not covered diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/thread/unsupported.rs index 34d9b5ec70c..a5001efa3b4 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/thread/unsupported.rs @@ -1,8 +1,7 @@ -use super::unsupported; use crate::ffi::CStr; use crate::io; use crate::num::NonZero; -use crate::time::{Duration, Instant}; +use crate::time::Duration; pub struct Thread(!); @@ -15,23 +14,7 @@ impl Thread { _name: Option<&str>, _p: Box<dyn FnOnce()>, ) -> io::Result<Thread> { - unsupported() - } - - pub fn yield_now() { - // do nothing - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(_dur: Duration) { - panic!("can't sleep"); - } - - pub fn sleep_until(_deadline: Instant) { - panic!("can't sleep"); + Err(io::Error::UNSUPPORTED_PLATFORM) } pub fn join(self) { @@ -39,10 +22,22 @@ impl Thread { } } -pub(crate) fn current_os_id() -> Option<u64> { +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + Err(io::Error::UNKNOWN_THREAD_COUNT) +} + +pub fn current_os_id() -> Option<u64> { None } -pub fn available_parallelism() -> io::Result<NonZero<usize>> { - unsupported() +pub fn yield_now() { + // do nothing +} + +pub fn set_name(_name: &CStr) { + // nope +} + +pub fn sleep(_dur: Duration) { + panic!("can't sleep"); } diff --git a/library/std/src/sys/thread/wasip1.rs b/library/std/src/sys/thread/wasip1.rs new file mode 100644 index 00000000000..83001fad49c --- /dev/null +++ b/library/std/src/sys/thread/wasip1.rs @@ -0,0 +1,185 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +#[cfg(target_feature = "atomics")] +use crate::io; +use crate::mem; +#[cfg(target_feature = "atomics")] +use crate::num::NonZero; +#[cfg(target_feature = "atomics")] +use crate::sys::os; +use crate::time::Duration; +#[cfg(target_feature = "atomics")] +use crate::{cmp, ptr}; + +// Add a few symbols not in upstream `libc` just yet. +#[cfg(target_feature = "atomics")] +mod libc { + pub use libc::*; + + pub use crate::ffi; + + // defined in wasi-libc + // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108 + #[repr(C)] + union pthread_attr_union { + __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], + __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }], + __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }], + } + + #[repr(C)] + pub struct pthread_attr_t { + __u: pthread_attr_union, + } + + #[allow(non_camel_case_types)] + pub type pthread_t = *mut ffi::c_void; + + pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84; + + unsafe extern "C" { + pub fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void, + value: *mut ffi::c_void, + ) -> ffi::c_int; + pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int; + pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int; + pub fn pthread_attr_setstacksize( + attr: *mut pthread_attr_t, + stack_size: libc::size_t, + ) -> ffi::c_int; + pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int; + pub fn pthread_detach(thread: pthread_t) -> ffi::c_int; + } +} + +#[cfg(target_feature = "atomics")] +pub struct Thread { + id: libc::pthread_t, +} + +#[cfg(target_feature = "atomics")] +impl Drop for Thread { + fn drop(&mut self) { + let ret = unsafe { libc::pthread_detach(self.id) }; + debug_assert_eq!(ret, 0); + } +} + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; + +#[cfg(target_feature = "atomics")] +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new( + stack: usize, + _name: Option<&str>, + p: Box<dyn FnOnce()>, + ) -> io::Result<Thread> { + let p = Box::into_raw(Box::new(p)); + let mut native: libc::pthread_t = unsafe { mem::zeroed() }; + let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() }; + assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0); + + let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE); + + match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { + 0 => {} + n => { + assert_eq!(n, libc::EINVAL); + // EINVAL means |stack_size| is either too small or not a + // multiple of the system page size. Because it's definitely + // >= PTHREAD_STACK_MIN, it must be an alignment issue. + // Round up to the nearest page and try again. + let page_size = os::page_size(); + let stack_size = + (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); + assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); + } + }; + + let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) }; + // Note: if the thread creation fails and this assert fails, then p will + // be leaked. However, an alternative design could cause double-free + // which is clearly worse. + assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0); + + return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + unsafe { + drop(Box::from_raw(p)); + } + Err(io::Error::from_raw_os_error(ret)) + } else { + Ok(Thread { id: native }) + }; + + extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { + unsafe { + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); + } + ptr::null_mut() + } + } + + pub fn join(self) { + let id = mem::ManuallyDrop::new(self).id; + let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + if ret != 0 { + rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret)); + } + } +} + +#[cfg(target_feature = "atomics")] +pub fn available_parallelism() -> io::Result<NonZero<usize>> { + match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { + -1 => Err(io::Error::last_os_error()), + cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT), + } +} + +pub fn yield_now() { + let ret = unsafe { wasi::sched_yield() }; + debug_assert_eq!(ret, Ok(())); +} + +pub fn sleep(dur: Duration) { + let mut nanos = dur.as_nanos(); + while nanos > 0 { + const USERDATA: wasi::Userdata = 0x0123_45678; + + let clock = wasi::SubscriptionClock { + id: wasi::CLOCKID_MONOTONIC, + timeout: u64::try_from(nanos).unwrap_or(u64::MAX), + precision: 0, + flags: 0, + }; + nanos -= u128::from(clock.timeout); + + let in_ = wasi::Subscription { + userdata: USERDATA, + u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } }, + }; + unsafe { + let mut event: wasi::Event = mem::zeroed(); + let res = wasi::poll_oneoff(&in_, &mut event, 1); + match (res, event) { + ( + Ok(1), + wasi::Event { + userdata: USERDATA, + error: wasi::ERRNO_SUCCESS, + type_: wasi::EVENTTYPE_CLOCK, + .. + }, + ) => {} + _ => panic!("thread::sleep(): unexpected result of poll_oneoff"), + } + } + } +} diff --git a/library/std/src/sys/thread/wasip2.rs b/library/std/src/sys/thread/wasip2.rs new file mode 100644 index 00000000000..420cad2a5e4 --- /dev/null +++ b/library/std/src/sys/thread/wasip2.rs @@ -0,0 +1,32 @@ +use crate::time::{Duration, Instant}; + +pub fn sleep(dur: Duration) { + // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is + // entirely drained. + let mut remaining = dur.as_nanos(); + while remaining > 0 { + let amt = u64::try_from(remaining).unwrap_or(u64::MAX); + wasip2::clocks::monotonic_clock::subscribe_duration(amt).block(); + remaining -= u128::from(amt); + } +} + +pub fn sleep_until(deadline: Instant) { + match u64::try_from(deadline.into_inner().as_duration().as_nanos()) { + // If the point in time we're sleeping to fits within a 64-bit + // number of nanoseconds then directly use `subscribe_instant`. + Ok(deadline) => { + wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block(); + } + // ... otherwise we're sleeping for 500+ years relative to the + // "start" of what the system is using as a clock so speed/accuracy + // is not so much of a concern. Use `sleep` instead. + Err(_) => { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + sleep(delay); + } + } + } +} diff --git a/library/std/src/sys/thread/wasm.rs b/library/std/src/sys/thread/wasm.rs new file mode 100644 index 00000000000..e843bc992ba --- /dev/null +++ b/library/std/src/sys/thread/wasm.rs @@ -0,0 +1,23 @@ +use crate::cmp; +use crate::time::Duration; + +pub fn sleep(dur: Duration) { + #[cfg(target_arch = "wasm32")] + use core::arch::wasm32 as wasm; + #[cfg(target_arch = "wasm64")] + use core::arch::wasm64 as wasm; + + // Use an atomic wait to block the current thread artificially with a + // timeout listed. Note that we should never be notified (return value + // of 0) or our comparison should never fail (return value of 1) so we + // should always only resume execution through a timeout (return value + // 2). + let mut nanos = dur.as_nanos(); + while nanos > 0 { + let amt = cmp::min(i64::MAX as u128, nanos); + let mut x = 0; + let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) }; + debug_assert_eq!(val, 2); + nanos -= amt; + } +} diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/thread/windows.rs index b0e38220a2d..a5640c51c4a 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/thread/windows.rs @@ -1,14 +1,14 @@ use core::ffi::c_void; -use super::time::WaitableTimer; -use super::to_u16s; use crate::ffi::CStr; use crate::num::NonZero; use crate::os::windows::io::{AsRawHandle, HandleOrNull}; use crate::sys::handle::Handle; +use crate::sys::pal::time::WaitableTimer; +use crate::sys::pal::{dur2timeout, to_u16s}; use crate::sys::{c, stack_overflow}; use crate::sys_common::FromInner; -use crate::time::{Duration, Instant}; +use crate::time::Duration; use crate::{io, ptr}; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -62,24 +62,6 @@ impl Thread { } } - pub fn set_name(name: &CStr) { - if let Ok(utf8) = name.to_str() { - if let Ok(utf16) = to_u16s(utf8) { - unsafe { - // SAFETY: the vec returned by `to_u16s` ends with a zero value - Self::set_name_wide(&utf16) - } - }; - }; - } - - /// # Safety - /// - /// `name` must end with a zero value - pub unsafe fn set_name_wide(name: &[u16]) { - unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) }; - } - pub fn join(self) { let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; if rc == c::WAIT_FAILED { @@ -87,37 +69,6 @@ impl Thread { } } - pub fn yield_now() { - // This function will return 0 if there are no other threads to execute, - // but this also means that the yield was useless so this isn't really a - // case that needs to be worried about. - unsafe { - c::SwitchToThread(); - } - } - - pub fn sleep(dur: Duration) { - fn high_precision_sleep(dur: Duration) -> Result<(), ()> { - let timer = WaitableTimer::high_resolution()?; - timer.set(dur)?; - timer.wait() - } - // Attempt to use high-precision sleep (Windows 10, version 1803+). - // On error fallback to the standard `Sleep` function. - // Also preserves the zero duration behavior of `Sleep`. - if dur.is_zero() || high_precision_sleep(dur).is_err() { - unsafe { c::Sleep(super::dur2timeout(dur)) } - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn handle(&self) -> &Handle { &self.handle } @@ -127,14 +78,6 @@ impl Thread { } } -pub(crate) fn current_os_id() -> Option<u64> { - // SAFETY: FFI call with no preconditions. - let id: u32 = unsafe { c::GetCurrentThreadId() }; - - // A return value of 0 indicates failed lookup. - if id == 0 { None } else { Some(id.into()) } -} - pub fn available_parallelism() -> io::Result<NonZero<usize>> { let res = unsafe { let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); @@ -146,3 +89,52 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> { cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }), } } + +pub fn current_os_id() -> Option<u64> { + // SAFETY: FFI call with no preconditions. + let id: u32 = unsafe { c::GetCurrentThreadId() }; + + // A return value of 0 indicates failed lookup. + if id == 0 { None } else { Some(id.into()) } +} + +pub fn set_name(name: &CStr) { + if let Ok(utf8) = name.to_str() { + if let Ok(utf16) = to_u16s(utf8) { + unsafe { + // SAFETY: the vec returned by `to_u16s` ends with a zero value + set_name_wide(&utf16) + } + }; + }; +} + +/// # Safety +/// +/// `name` must end with a zero value +pub unsafe fn set_name_wide(name: &[u16]) { + unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) }; +} + +pub fn sleep(dur: Duration) { + fn high_precision_sleep(dur: Duration) -> Result<(), ()> { + let timer = WaitableTimer::high_resolution()?; + timer.set(dur)?; + timer.wait() + } + // Attempt to use high-precision sleep (Windows 10, version 1803+). + // On error fallback to the standard `Sleep` function. + // Also preserves the zero duration behavior of `Sleep`. + if dur.is_zero() || high_precision_sleep(dur).is_err() { + unsafe { c::Sleep(dur2timeout(dur)) } + } +} + +pub fn yield_now() { + // This function will return 0 if there are no other threads to execute, + // but this also means that the yield was useless so this isn't really a + // case that needs to be worried about. + unsafe { + c::SwitchToThread(); + } +} diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/thread/xous.rs index 92803c94c6e..133e15a0928 100644 --- a/library/std/src/sys/pal/xous/thread.rs +++ b/library/std/src/sys/thread/xous.rs @@ -1,6 +1,5 @@ use core::arch::asm; -use crate::ffi::CStr; use crate::io; use crate::num::NonZero; use crate::os::xous::ffi::{ @@ -8,7 +7,7 @@ use crate::os::xous::ffi::{ map_memory, update_memory_flags, }; use crate::os::xous::services::{TicktimerScalar, ticktimer_server}; -use crate::time::{Duration, Instant}; +use crate::time::Duration; pub struct Thread { tid: ThreadId, @@ -110,46 +109,29 @@ impl Thread { Ok(Thread { tid }) } - pub fn yield_now() { - do_yield(); - } - - pub fn set_name(_name: &CStr) { - // nope - } - - pub fn sleep(dur: Duration) { - // Because the sleep server works on units of `usized milliseconds`, split - // the messages up into these chunks. This means we may run into issues - // if you try to sleep a thread for more than 49 days on a 32-bit system. - let mut millis = dur.as_millis(); - while millis > 0 { - let sleep_duration = - if millis > (usize::MAX as _) { usize::MAX } else { millis as usize }; - blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into()) - .expect("failed to send message to ticktimer server"); - millis -= sleep_duration as u128; - } - } - - pub fn sleep_until(deadline: Instant) { - let now = Instant::now(); - - if let Some(delay) = deadline.checked_duration_since(now) { - Self::sleep(delay); - } - } - pub fn join(self) { join_thread(self.tid).unwrap(); } } -pub(crate) fn current_os_id() -> Option<u64> { - None -} - pub fn available_parallelism() -> io::Result<NonZero<usize>> { // We're unicore right now. Ok(unsafe { NonZero::new_unchecked(1) }) } + +pub fn yield_now() { + do_yield(); +} + +pub fn sleep(dur: Duration) { + // Because the sleep server works on units of `usized milliseconds`, split + // the messages up into these chunks. This means we may run into issues + // if you try to sleep a thread for more than 49 days on a 32-bit system. + let mut millis = dur.as_millis(); + while millis > 0 { + let sleep_duration = if millis > (usize::MAX as _) { usize::MAX } else { millis as usize }; + blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into()) + .expect("failed to send message to ticktimer server"); + millis -= sleep_duration as u128; + } +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index b6059c28cec..4d09b2b4e9d 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -550,7 +550,7 @@ impl Builder { } if let Some(name) = their_thread.cname() { - imp::Thread::set_name(name); + imp::set_name(name); } let f = f.into_inner(); @@ -763,7 +763,7 @@ where /// [`Mutex`]: crate::sync::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { - imp::Thread::yield_now() + imp::yield_now() } /// Determines whether the current thread is unwinding because of panic. @@ -884,7 +884,7 @@ pub fn sleep_ms(ms: u32) { /// ``` #[stable(feature = "thread_sleep", since = "1.4.0")] pub fn sleep(dur: Duration) { - imp::Thread::sleep(dur) + imp::sleep(dur) } /// Puts the current thread to sleep until the specified deadline has passed. @@ -983,7 +983,7 @@ pub fn sleep(dur: Duration) { /// ``` #[unstable(feature = "thread_sleep_until", issue = "113752")] pub fn sleep_until(deadline: Instant) { - imp::Thread::sleep_until(deadline) + imp::sleep_until(deadline) } /// Used to ensure that `park` and `park_timeout` do not unwind, as that can @@ -1021,13 +1021,23 @@ impl Drop for PanicGuard { /// specifying a maximum time to block the thread for. /// /// * The [`unpark`] method on a [`Thread`] atomically makes the token available -/// if it wasn't already. Because the token is initially absent, [`unpark`] -/// followed by [`park`] will result in the second call returning immediately. -/// -/// The API is typically used by acquiring a handle to the current thread, -/// placing that handle in a shared data structure so that other threads can -/// find it, and then `park`ing in a loop. When some desired condition is met, another -/// thread calls [`unpark`] on the handle. +/// if it wasn't already. Because the token can be held by a thread even if it is currently not +/// parked, [`unpark`] followed by [`park`] will result in the second call returning immediately. +/// However, note that to rely on this guarantee, you need to make sure that your `unpark` happens +/// after all `park` that may be done by other data structures! +/// +/// The API is typically used by acquiring a handle to the current thread, placing that handle in a +/// shared data structure so that other threads can find it, and then `park`ing in a loop. When some +/// desired condition is met, another thread calls [`unpark`] on the handle. The last bullet point +/// above guarantees that even if the `unpark` occurs before the thread is finished `park`ing, it +/// will be woken up properly. +/// +/// Note that the coordination via the shared data structure is crucial: If you `unpark` a thread +/// without first establishing that it is about to be `park`ing within your code, that `unpark` may +/// get consumed by a *different* `park` in the same thread, leading to a deadlock. This also means +/// you must not call unknown code between setting up for parking and calling `park`; for instance, +/// if you invoke `println!`, that may itself call `park` and thus consume your `unpark` and cause a +/// deadlock. /// /// The motivation for this design is twofold: /// @@ -1058,21 +1068,24 @@ impl Drop for PanicGuard { /// /// ``` /// use std::thread; -/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}}; +/// use std::sync::atomic::{Ordering, AtomicBool}; /// use std::time::Duration; /// -/// let flag = Arc::new(AtomicBool::new(false)); -/// let flag2 = Arc::clone(&flag); +/// static QUEUED: AtomicBool = AtomicBool::new(false); +/// static FLAG: AtomicBool = AtomicBool::new(false); /// /// let parked_thread = thread::spawn(move || { +/// println!("Thread spawned"); +/// // Signal that we are going to `park`. Between this store and our `park`, there may +/// // be no other `park`, or else that `park` could consume our `unpark` token! +/// QUEUED.store(true, Ordering::Release); /// // We want to wait until the flag is set. We *could* just spin, but using /// // park/unpark is more efficient. -/// while !flag2.load(Ordering::Relaxed) { -/// println!("Parking thread"); +/// while !FLAG.load(Ordering::Acquire) { +/// // We can *not* use `println!` here since that could use thread parking internally. /// thread::park(); /// // We *could* get here spuriously, i.e., way before the 10ms below are over! /// // But that is no problem, we are in a loop until the flag is set anyway. -/// println!("Thread unparked"); /// } /// println!("Flag received"); /// }); @@ -1080,11 +1093,22 @@ impl Drop for PanicGuard { /// // Let some time pass for the thread to be spawned. /// thread::sleep(Duration::from_millis(10)); /// +/// // Ensure the thread is about to park. +/// // This is crucial! It guarantees that the `unpark` below is not consumed +/// // by some other code in the parked thread (e.g. inside `println!`). +/// while !QUEUED.load(Ordering::Acquire) { +/// // Spinning is of course inefficient; in practice, this would more likely be +/// // a dequeue where we have no work to do if there's nobody queued. +/// std::hint::spin_loop(); +/// } +/// /// // Set the flag, and let the thread wake up. -/// // There is no race condition here, if `unpark` +/// // There is no race condition here: if `unpark` /// // happens first, `park` will return immediately. +/// // There is also no other `park` that could consume this token, +/// // since we waited until the other thread got queued. /// // Hence there is no risk of a deadlock. -/// flag.store(true, Ordering::Relaxed); +/// FLAG.store(true, Ordering::Release); /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// @@ -1494,10 +1518,14 @@ impl Thread { /// ``` /// use std::thread; /// use std::time::Duration; + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// static QUEUED: AtomicBool = AtomicBool::new(false); /// /// let parked_thread = thread::Builder::new() /// .spawn(|| { /// println!("Parking thread"); + /// QUEUED.store(true, Ordering::Release); /// thread::park(); /// println!("Thread unparked"); /// }) @@ -1506,6 +1534,15 @@ impl Thread { /// // Let some time pass for the thread to be spawned. /// thread::sleep(Duration::from_millis(10)); /// + /// // Wait until the other thread is queued. + /// // This is crucial! It guarantees that the `unpark` below is not consumed + /// // by some other code in the parked thread (e.g. inside `println!`). + /// while !QUEUED.load(Ordering::Acquire) { + /// // Spinning is of course inefficient; in practice, this would more likely be + /// // a dequeue where we have no work to do if there's nobody queued. + /// std::hint::spin_loop(); + /// } + /// /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index ae889f1e778..2117f5f93ce 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -287,6 +287,8 @@ fn test_park_unpark_called_other_thread() { for _ in 0..10 { let th = thread::current(); + // Here we rely on `thread::spawn` (specifically the part that runs after spawning + // the thread) to not consume the parking token. let _guard = thread::spawn(move || { super::sleep(Duration::from_millis(50)); th.unpark(); @@ -316,6 +318,8 @@ fn test_park_timeout_unpark_called_other_thread() { for _ in 0..10 { let th = thread::current(); + // Here we rely on `thread::spawn` (specifically the part that runs after spawning + // the thread) to not consume the parking token. let _guard = thread::spawn(move || { super::sleep(Duration::from_millis(50)); th.unpark(); diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 84fbb4c2fe4..31187adb6fe 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -551,13 +551,8 @@ impl SystemTime { /// println!("{difference:?}"); /// ``` #[stable(feature = "time2", since = "1.8.0")] - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> { - // FIXME: map_err in const - match self.0.sub_time(&earlier.0) { - Ok(time) => Ok(time), - Err(err) => Err(SystemTimeError(err)), - } + pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> { + self.0.sub_time(&earlier.0).map_err(SystemTimeError) } /// Returns the difference from this system time to the @@ -594,8 +589,7 @@ impl SystemTime { /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. #[stable(feature = "time_checked_add", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_add(&self, duration: Duration) -> Option<SystemTime> { + pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> { self.0.checked_add_duration(&duration).map(SystemTime) } @@ -603,15 +597,13 @@ impl SystemTime { /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None` /// otherwise. #[stable(feature = "time_checked_add", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn checked_sub(&self, duration: Duration) -> Option<SystemTime> { + pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> { self.0.checked_sub_duration(&duration).map(SystemTime) } } #[stable(feature = "time2", since = "1.8.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "143802")] -impl const Add<Duration> for SystemTime { +impl Add<Duration> for SystemTime { type Output = SystemTime; /// # Panics @@ -624,16 +616,14 @@ impl const Add<Duration> for SystemTime { } #[stable(feature = "time_augmented_assignment", since = "1.9.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "143802")] -impl const AddAssign<Duration> for SystemTime { +impl AddAssign<Duration> for SystemTime { fn add_assign(&mut self, other: Duration) { *self = *self + other; } } #[stable(feature = "time2", since = "1.8.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "143802")] -impl const Sub<Duration> for SystemTime { +impl Sub<Duration> for SystemTime { type Output = SystemTime; fn sub(self, dur: Duration) -> SystemTime { @@ -642,8 +632,7 @@ impl const Sub<Duration> for SystemTime { } #[stable(feature = "time_augmented_assignment", since = "1.9.0")] -#[rustc_const_unstable(feature = "const_ops", issue = "143802")] -impl const SubAssign<Duration> for SystemTime { +impl SubAssign<Duration> for SystemTime { fn sub_assign(&mut self, other: Duration) { *self = *self - other; } @@ -710,8 +699,7 @@ impl SystemTimeError { /// ``` #[must_use] #[stable(feature = "time2", since = "1.8.0")] - #[rustc_const_unstable(feature = "const_system_time", issue = "144517")] - pub const fn duration(&self) -> Duration { + pub fn duration(&self) -> Duration { self.0 } } diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index c29d803b25e..3acd0670914 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -193,13 +193,13 @@ fn test_atanh() { #[test] fn test_gamma() { // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(1.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(2.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(3.0f32.gamma(), 2.0f32, APPROX_DELTA); assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA); assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt(), APPROX_DELTA); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA); assert_eq!(0.0f32.gamma(), f32::INFINITY); assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); assert!((-1.0f32).gamma().is_nan()); diff --git a/library/std/tests/sync/barrier.rs b/library/std/tests/sync/barrier.rs index 8aefff9d507..a66bd629699 100644 --- a/library/std/tests/sync/barrier.rs +++ b/library/std/tests/sync/barrier.rs @@ -1,3 +1,4 @@ +use std::panic::RefUnwindSafe; use std::sync::mpsc::{TryRecvError, channel}; use std::sync::{Arc, Barrier}; use std::thread; @@ -33,3 +34,11 @@ fn test_barrier() { } assert!(leader_found); } + +/// Asserts that `Barrier` is ref unwind safe. +/// +/// See <https://github.com/rust-lang/rust/issues/146087>. +const _: () = { + const fn check_ref_unwind_safe<T: RefUnwindSafe>() {} + check_ref_unwind_safe::<Barrier>(); +}; diff --git a/library/std/tests/sync/condvar.rs b/library/std/tests/sync/condvar.rs index 1d712a64300..1b1c33efad5 100644 --- a/library/std/tests/sync/condvar.rs +++ b/library/std/tests/sync/condvar.rs @@ -17,7 +17,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: notify_one, test_body: { @@ -38,7 +38,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: notify_all, test_body: { @@ -79,7 +79,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: test_mutex_arc_condvar, test_body: { @@ -116,7 +116,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_while, test_body: { @@ -141,7 +141,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_timeout_wait, test_body: { @@ -164,7 +164,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_timeout_while_wait, test_body: { @@ -180,7 +180,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_timeout_while_instant_satisfy, test_body: { @@ -197,7 +197,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_timeout_while_wake, test_body: { @@ -226,7 +226,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads. nonpoison_and_poison_unwrap_test!( name: wait_timeout_wake, test_body: { diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index ac1dbebcc5c..23112e10284 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -58,6 +58,9 @@ fn result_unwrap<T, E: std::fmt::Debug>(x: Result<T, E>) -> T { /// a no-op (the identity function). /// /// The test names will be prefiex with `poison_` or `nonpoison_`. +/// +/// Important: most attributes (except `cfg`) will not work properly! (They are only applied to the first test.) +/// See <https://github.com/rust-lang/rust/pull/146433> for more information. macro_rules! nonpoison_and_poison_unwrap_test { ( name: $name:ident, diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs index 612c75c7aef..2445764001b 100644 --- a/library/std/tests/sync/mutex.rs +++ b/library/std/tests/sync/mutex.rs @@ -266,7 +266,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[cfg(panic = "unwind")] // Requires unwinding support. nonpoison_and_poison_unwrap_test!( name: test_panics, test_body: { @@ -297,7 +297,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[cfg(panic = "unwind")] // Requires unwinding support. nonpoison_and_poison_unwrap_test!( name: test_mutex_arc_access_in_unwind, test_body: { diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index eca15d2a4ad..65d8bac7194 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -50,7 +50,7 @@ nonpoison_and_poison_unwrap_test!( // FIXME: On macOS we use a provenance-incorrect implementation and Miri // catches that issue with a chance of around 1/1000. // See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] +#[cfg(not(all(miri, target_os = "macos")))] nonpoison_and_poison_unwrap_test!( name: frob, test_body: { @@ -124,7 +124,7 @@ nonpoison_and_poison_unwrap_test!( } ); -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +#[cfg(panic = "unwind")] // Requires unwinding support. nonpoison_and_poison_unwrap_test!( name: test_rw_arc_access_in_unwind, test_body: { @@ -315,7 +315,7 @@ nonpoison_and_poison_unwrap_test!( // FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. // See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] +#[cfg(not(all(miri, target_os = "macos")))] nonpoison_and_poison_unwrap_test!( name: test_downgrade_observe, test_body: { @@ -362,7 +362,7 @@ nonpoison_and_poison_unwrap_test!( // FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. // See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] +#[cfg(not(all(miri, target_os = "macos")))] nonpoison_and_poison_unwrap_test!( name: test_downgrade_atomic, test_body: { diff --git a/library/std_detect/src/detect/os/linux/aarch64.rs b/library/std_detect/src/detect/os/linux/aarch64.rs index 87a9d6ebb88..b733b8a9eb2 100644 --- a/library/std_detect/src/detect/os/linux/aarch64.rs +++ b/library/std_detect/src/detect/os/linux/aarch64.rs @@ -140,7 +140,7 @@ struct AtHwcap { impl From<auxvec::AuxVec> for AtHwcap { /// Reads AtHwcap from the auxiliary vector. fn from(auxv: auxvec::AuxVec) -> Self { - AtHwcap { + let mut cap = AtHwcap { fp: bit::test(auxv.hwcap, 0), asimd: bit::test(auxv.hwcap, 1), // evtstrm: bit::test(auxv.hwcap, 2), @@ -207,39 +207,50 @@ impl From<auxvec::AuxVec> for AtHwcap { // smef32f32: bit::test(auxv.hwcap2, 29), smefa64: bit::test(auxv.hwcap2, 30), wfxt: bit::test(auxv.hwcap2, 31), - // ebf16: bit::test(auxv.hwcap2, 32), - // sveebf16: bit::test(auxv.hwcap2, 33), - cssc: bit::test(auxv.hwcap2, 34), - // rprfm: bit::test(auxv.hwcap2, 35), - sve2p1: bit::test(auxv.hwcap2, 36), - sme2: bit::test(auxv.hwcap2, 37), - sme2p1: bit::test(auxv.hwcap2, 38), - // smei16i32: bit::test(auxv.hwcap2, 39), - // smebi32i32: bit::test(auxv.hwcap2, 40), - smeb16b16: bit::test(auxv.hwcap2, 41), - smef16f16: bit::test(auxv.hwcap2, 42), - mops: bit::test(auxv.hwcap2, 43), - hbc: bit::test(auxv.hwcap2, 44), - sveb16b16: bit::test(auxv.hwcap2, 45), - lrcpc3: bit::test(auxv.hwcap2, 46), - lse128: bit::test(auxv.hwcap2, 47), - fpmr: bit::test(auxv.hwcap2, 48), - lut: bit::test(auxv.hwcap2, 49), - faminmax: bit::test(auxv.hwcap2, 50), - f8cvt: bit::test(auxv.hwcap2, 51), - f8fma: bit::test(auxv.hwcap2, 52), - f8dp4: bit::test(auxv.hwcap2, 53), - f8dp2: bit::test(auxv.hwcap2, 54), - f8e4m3: bit::test(auxv.hwcap2, 55), - f8e5m2: bit::test(auxv.hwcap2, 56), - smelutv2: bit::test(auxv.hwcap2, 57), - smef8f16: bit::test(auxv.hwcap2, 58), - smef8f32: bit::test(auxv.hwcap2, 59), - smesf8fma: bit::test(auxv.hwcap2, 60), - smesf8dp4: bit::test(auxv.hwcap2, 61), - smesf8dp2: bit::test(auxv.hwcap2, 62), - // pauthlr: bit::test(auxv.hwcap2, ??), + ..Default::default() + }; + + // Hardware capabilities from bits 32 to 63 should only + // be tested on LP64 targets with 64 bits `usize`. + // On ILP32 targets like `aarch64-unknown-linux-gnu_ilp32`, + // these hardware capabilities will default to `false`. + // https://github.com/rust-lang/rust/issues/146230 + #[cfg(target_pointer_width = "64")] + { + // cap.ebf16: bit::test(auxv.hwcap2, 32); + // cap.sveebf16: bit::test(auxv.hwcap2, 33); + cap.cssc = bit::test(auxv.hwcap2, 34); + // cap.rprfm: bit::test(auxv.hwcap2, 35); + cap.sve2p1 = bit::test(auxv.hwcap2, 36); + cap.sme2 = bit::test(auxv.hwcap2, 37); + cap.sme2p1 = bit::test(auxv.hwcap2, 38); + // cap.smei16i32 = bit::test(auxv.hwcap2, 39); + // cap.smebi32i32 = bit::test(auxv.hwcap2, 40); + cap.smeb16b16 = bit::test(auxv.hwcap2, 41); + cap.smef16f16 = bit::test(auxv.hwcap2, 42); + cap.mops = bit::test(auxv.hwcap2, 43); + cap.hbc = bit::test(auxv.hwcap2, 44); + cap.sveb16b16 = bit::test(auxv.hwcap2, 45); + cap.lrcpc3 = bit::test(auxv.hwcap2, 46); + cap.lse128 = bit::test(auxv.hwcap2, 47); + cap.fpmr = bit::test(auxv.hwcap2, 48); + cap.lut = bit::test(auxv.hwcap2, 49); + cap.faminmax = bit::test(auxv.hwcap2, 50); + cap.f8cvt = bit::test(auxv.hwcap2, 51); + cap.f8fma = bit::test(auxv.hwcap2, 52); + cap.f8dp4 = bit::test(auxv.hwcap2, 53); + cap.f8dp2 = bit::test(auxv.hwcap2, 54); + cap.f8e4m3 = bit::test(auxv.hwcap2, 55); + cap.f8e5m2 = bit::test(auxv.hwcap2, 56); + cap.smelutv2 = bit::test(auxv.hwcap2, 57); + cap.smef8f16 = bit::test(auxv.hwcap2, 58); + cap.smef8f32 = bit::test(auxv.hwcap2, 59); + cap.smesf8fma = bit::test(auxv.hwcap2, 60); + cap.smesf8dp4 = bit::test(auxv.hwcap2, 61); + cap.smesf8dp2 = bit::test(auxv.hwcap2, 62); + // cap.pauthlr = bit::test(auxv.hwcap2, ??); } + cap } } diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 2a32a7dd76e..fe749847b7c 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -6,7 +6,7 @@ version = "0.0.0" edition = "2024" [dependencies] -getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } +getopts = { version = "0.2.24", default-features = false, features = ['rustc-dep-of-std'] } std = { path = "../std", public = true } core = { path = "../core", public = true } diff --git a/package-lock.json b/package-lock.json index def0cfa86a5..d0297bf70b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "browser-ui-test": "^0.22.0", + "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", "eslint-js": "github:eslint/js", @@ -485,9 +485,9 @@ } }, "node_modules/browser-ui-test": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.0.tgz", - "integrity": "sha512-p/C02TMybTDKsAjpGOdnyNC0Q25KDae/fKMnvHaqcJ0tXRqNKwndW2Ltq7HTmin5xqg8GGOmysEgWTZkXu6pfA==", + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.2.tgz", + "integrity": "sha512-eNB/PN2yDGe5n5IwE3ld/N6A39jM1oRzJmT5nOVQqrvoZEtcd9JSggDQPNVUnMEyuGcD4OEOWMsEa4oJppAmDQ==", "license": "MIT", "dependencies": { "css-unit-converter": "^1.1.2", diff --git a/package.json b/package.json index 976d6303634..04e0f6af19a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.22.0", + "browser-ui-test": "^0.22.2", "es-check": "^6.2.1", "eslint": "^8.57.1", "eslint-js": "github:eslint/js", diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index 9daf9faac14..b111a20f8d8 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -14,6 +14,10 @@ compiletest-use-stage0-libtest = false [llvm] download-ci-llvm = false +# Most users installing from source want to build all parts of the project from source. +[gcc] +download-ci-gcc = false + [rust] # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`). # Make sure they don't get set when installing from source. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0b75e85772f..1458b0beefa 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1383,14 +1383,17 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } } - // Build jemalloc on AArch64 with support for page sizes up to 64K - // See: https://github.com/rust-lang/rust/pull/135081 // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the tool build step. - if builder.config.jemalloc(target) - && target.starts_with("aarch64") - && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() - { - cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16"); + if builder.config.jemalloc(target) && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() { + // Build jemalloc on AArch64 with support for page sizes up to 64K + // See: https://github.com/rust-lang/rust/pull/135081 + if target.starts_with("aarch64") { + cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16"); + } + // Build jemalloc on LoongArch with support for page sizes up to 16K + else if target.starts_with("loongarch") { + cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14"); + } } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 820dda5a652..99a1062109a 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -88,6 +88,7 @@ impl Step for Docs { tarball.set_product_name("Rust Documentation"); tarball.add_bulk_dir(builder.doc_out(host), dest); tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular); + tarball.add_file(builder.src.join("src/doc/sitemap.txt"), dest, FileType::Regular); Some(tarball.generate()) } @@ -589,6 +590,8 @@ impl Step for Rustc { // Debugger scripts builder.ensure(DebuggerScripts { sysroot: image.to_owned(), target }); + generate_target_spec_json_schema(builder, image); + // HTML copyright files let file_list = builder.ensure(super::run::GenerateCopyright); for file in file_list { @@ -617,6 +620,28 @@ impl Step for Rustc { } } +fn generate_target_spec_json_schema(builder: &Builder<'_>, sysroot: &Path) { + // Since we run rustc in bootstrap, we need to ensure that we use the host compiler. + // We do this by using the stage 1 compiler, which is always compiled for the host, + // even in a cross build. + let stage1_host = builder.compiler(1, builder.host_target); + let mut rustc = command(builder.rustc(stage1_host)).fail_fast(); + rustc + .env("RUSTC_BOOTSTRAP", "1") + .args(["--print=target-spec-json-schema", "-Zunstable-options"]); + let schema = rustc.run_capture(builder).stdout(); + + let schema_dir = tmpdir(builder); + t!(fs::create_dir_all(&schema_dir)); + let schema_file = schema_dir.join("target-spec-json-schema.json"); + t!(std::fs::write(&schema_file, schema)); + + let dst = sysroot.join("etc"); + t!(fs::create_dir_all(&dst)); + + builder.install(&schema_file, &dst, FileType::Regular); +} + /// Copies debugger scripts for `target` into the given compiler `sysroot`. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct DebuggerScripts { diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 77c9622a9bf..717dea37e9e 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -32,6 +32,10 @@ pub struct GccOutput { impl GccOutput { /// Install the required libgccjit library file(s) to the specified `path`. pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) { + if builder.config.dry_run() { + return; + } + // At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol). // However, at runtime, it will by default look for libgccjit.so.0. // So when we install the built libgccjit.so file to the target `directory`, we add it there @@ -39,8 +43,16 @@ impl GccOutput { let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string(); target_filename.push_str(".0"); + // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink. + // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink, + // which wouldn't work. + let actual_libgccjit_path = t!( + self.libgccjit.canonicalize(), + format!("Cannot find libgccjit at {}", self.libgccjit.display()) + ); + let dst = directory.join(target_filename); - builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary); + builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4f839bdf7b8..723ba80eaf8 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2086,11 +2086,25 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} } // Get paths from cmd args - let paths = match &builder.config.cmd { + let mut paths = match &builder.config.cmd { Subcommand::Test { .. } => &builder.config.paths[..], _ => &[], }; + // in rustdoc-js mode, allow filters to be rs files or js files. + // use a late-initialized Vec to avoid cloning for other modes. + let mut paths_v; + if mode == "rustdoc-js" { + paths_v = paths.to_vec(); + for p in &mut paths_v { + if let Some(ext) = p.extension() + && ext == "js" + { + p.set_extension("rs"); + } + } + paths = &paths_v; + } // Get test-args by striping suite path let mut test_args: Vec<&str> = paths .iter() diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 6870bf3eddc..dcc4898cae1 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -228,12 +228,18 @@ pub fn prepare_tool_cargo( // own copy cargo.env("LZMA_API_STATIC", "1"); - // Build jemalloc on AArch64 with support for page sizes up to 64K - // See: https://github.com/rust-lang/rust/pull/135081 // Note that `miri` always uses jemalloc. As such, there is no checking of the jemalloc build flag. // See also the "JEMALLOC_SYS_WITH_LG_PAGE" setting in the compile build step. - if target.starts_with("aarch64") && env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() { - cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16"); + if env::var_os("JEMALLOC_SYS_WITH_LG_PAGE").is_none() { + // Build jemalloc on AArch64 with support for page sizes up to 64K + // See: https://github.com/rust-lang/rust/pull/135081 + if target.starts_with("aarch64") { + cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "16"); + } + // Build jemalloc on LoongArch with support for page sizes up to 16K + else if target.starts_with("loongarch") { + cargo.env("JEMALLOC_SYS_WITH_LG_PAGE", "14"); + } } // CFG_RELEASE is needed by rustfmt (and possibly other tools) which diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 89a0ab7711e..229adf71459 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1805,7 +1805,7 @@ mod snapshot { insta::assert_snapshot!( ctx.config("check") .path("compiler") - .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)"); + .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (75 crates)"); } #[test] @@ -1831,7 +1831,7 @@ mod snapshot { ctx.config("check") .path("compiler") .stage(1) - .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)"); + .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (75 crates)"); } #[test] @@ -1845,7 +1845,7 @@ mod snapshot { [build] llvm <host> [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> - [check] rustc 1 <host> -> rustc 2 <host> (74 crates) + [check] rustc 1 <host> -> rustc 2 <host> (75 crates) "); } @@ -1861,7 +1861,7 @@ mod snapshot { [build] rustc 0 <host> -> rustc 1 <host> [build] rustc 1 <host> -> std 1 <host> [check] rustc 1 <host> -> std 1 <target1> - [check] rustc 1 <host> -> rustc 2 <target1> (74 crates) + [check] rustc 1 <host> -> rustc 2 <target1> (75 crates) [check] rustc 1 <host> -> rustc 2 <target1> [check] rustc 1 <host> -> Rustdoc 2 <target1> [check] rustc 1 <host> -> rustc_codegen_cranelift 2 <target1> @@ -1957,7 +1957,7 @@ mod snapshot { ctx.config("check") .paths(&["library", "compiler"]) .args(&args) - .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (74 crates)"); + .render_steps(), @"[check] rustc 0 <host> -> rustc 1 <host> (75 crates)"); } #[test] diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 5999348a7fe..05a5dfc0bc5 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -422,10 +422,10 @@ impl std::str::FromStr for RustcLto { #[derive(Default, Clone)] pub enum GccCiMode { /// Build GCC from the local `src/gcc` submodule. - #[default] BuildLocally, /// Try to download GCC from CI. /// If it is not available on CI, it will be built locally instead. + #[default] DownloadFromCi, } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 04cf63f1c6d..68202500d97 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -287,7 +287,7 @@ than building it. if !has_target { panic!( - "No such target exists in the target list,\n\ + "{target_str}: No such target exists in the target list,\n\ make sure to correctly specify the location \ of the JSON specification file \ for custom targets!\n\ diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 01309072927..03b39882e30 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -541,4 +541,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Added a new option `rust.break-on-ice` to control if internal compiler errors cause a debug break on Windows.", }, + ChangeInfo { + change_id: 146435, + severity: ChangeSeverity::Info, + summary: "The default value of the `gcc.download-ci-gcc` option has been changed to `true`.", + }, ]; diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index 777c8601aa1..db2369097d6 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -43,6 +43,7 @@ pub static CRATES: &[&str] = &[ "rustc-hash", "self_cell", "serde", + "serde_derive_internals", "sha2", "smallvec", "stable_deref_trait", diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 7e6a59aaf89..54b13c4397f 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -38,7 +38,7 @@ ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ --enable-lld \ - --set rust.debuginfo-level-tests=1 \ + --set rust.debuginfo-level-tests=2 \ --set llvm.use-linker=lld \ --set target.x86_64-unknown-linux-gnu.linker=clang \ --set target.x86_64-unknown-linux-gnu.cc=clang \ diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 7e0fb5794f4..b7d7151b171 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,9 +2,7 @@ set -euo pipefail -# https://github.com/rust-lang/rust/pull/144443 -# https://github.com/rust-lang/rust/pull/145928 -LINUX_VERSION=8851e27d2cb947ea8bbbe8e812068f7bf5cbd00b +LINUX_VERSION=v6.17-rc5 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 57ed4473660565d9357fcae176b358d7e8724eb +Subproject f17a018b9989430967d1c58e9a12c51169abc74 diff --git a/src/doc/reference b/src/doc/reference -Subproject 89f67b3c1b904cbcd9ed55e443d6fc67c8ca276 +Subproject b3ce60628c6f55ab8ff3dba9f3d20203df1c0de diff --git a/src/doc/robots.txt b/src/doc/robots.txt index 3a2552e9a15..71a60f89c14 100644 --- a/src/doc/robots.txt +++ b/src/doc/robots.txt @@ -9,3 +9,5 @@ Disallow: /beta/book/first-edition/ Disallow: /beta/book/second-edition/ Disallow: /nightly/book/first-edition/ Disallow: /nightly/book/second-edition/ + +Sitemap: https://doc.rust-lang.org/sitemap.txt diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject ad27f82c18464525c761a4a8db2e01785da59e1 +Subproject dd26bc8e726dc2e73534c8972d4dccd1bed7495 diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index 6eabb999fb0..2dd695b7a47 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'rust-lang/rustc-dev-guide' runs-on: ubuntu-latest env: - MDBOOK_VERSION: 0.4.48 + MDBOOK_VERSION: 0.4.52 MDBOOK_LINKCHECK2_VERSION: 0.9.1 MDBOOK_MERMAID_VERSION: 0.12.6 MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }} diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index f412399cc8c..df2bac877b6 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -a1dbb443527bd126452875eb5d5860c1d001d761 +2f3f27bf79ec147fec9d2e7980605307a74067f4 diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index f3957724967..f1a406a1c29 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -73,7 +73,7 @@ You might also find the following sites useful: - [compiler-team] -- the home-base for the Rust compiler team, with description of the team procedures, active working groups, and the team calendar. - [std-dev-guide] -- a similar guide for developing the standard library. -- [The t-compiler zulip][z] +- [The t-compiler Zulip][z] - The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals - The [Rust reference][rr], even though it doesn't specifically talk about diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md index 65fbf752d79..4ddb58b0c39 100644 --- a/src/doc/rustc-dev-guide/src/appendix/code-index.md +++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md @@ -13,7 +13,7 @@ Item | Kind | Short description | Chapter | `DefId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/def_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html) `Diag` | struct | A struct for a compiler diagnostic, such as an error or lint | [Emitting Diagnostics] | [compiler/rustc_errors/src/diagnostic.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Diag.html) `DocContext` | struct | A state container used by rustdoc when crawling through a crate to gather its documentation | [Rustdoc] | [src/librustdoc/core.rs](https://github.com/rust-lang/rust/blob/master/src/librustdoc/core.rs) -`HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir/src/hir_id.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html) +`HirId` | struct | One of four types of HIR node identifiers | [Identifiers in the HIR] | [compiler/rustc_hir_id/src/lib.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.HirId.html) `Lexer` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] | [compiler/rustc_parse/src/lexer/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/lexer/struct.Lexer.html) `NodeId` | struct | One of four types of HIR node identifiers. Being phased out | [Identifiers in the HIR] | [compiler/rustc_ast/src/ast.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/node_id/struct.NodeId.html) `P` | struct | An owned immutable smart pointer. By contrast, `&T` is not owned, and `Box<T>` is not immutable. | None | [compiler/rustc_ast/src/ptr.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ptr/struct.P.html) diff --git a/src/doc/rustc-dev-guide/src/backend/debugging.md b/src/doc/rustc-dev-guide/src/backend/debugging.md index 4f8712dfaf3..3dc95f25d4a 100644 --- a/src/doc/rustc-dev-guide/src/backend/debugging.md +++ b/src/doc/rustc-dev-guide/src/backend/debugging.md @@ -183,7 +183,7 @@ The quick summary is: ### Getting help and asking questions If you have some questions, head over to the [rust-lang Zulip] and -specifically the `#t-compiler/wg-llvm` stream. +specifically the `#t-compiler/wg-llvm` channel. [rust-lang Zulip]: https://rust-lang.zulipchat.com/ diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index edd2aa6c5f6..f4514470418 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -367,7 +367,7 @@ error: layout_of(&'a u32) = Layout { error: aborting due to previous error ``` -[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/stable_mir/abi/struct.Layout.html +[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_public/abi/struct.Layout.html ## Configuring CodeLLDB for debugging `rustc` diff --git a/src/doc/rustc-dev-guide/src/compiler-src.md b/src/doc/rustc-dev-guide/src/compiler-src.md index d67bacb1b33..27b40f1fe01 100644 --- a/src/doc/rustc-dev-guide/src/compiler-src.md +++ b/src/doc/rustc-dev-guide/src/compiler-src.md @@ -153,7 +153,8 @@ The bulk of [`rustdoc`] is in [`librustdoc`]. However, the [`rustdoc`] binary itself is [`src/tools/rustdoc`], which does nothing except call [`rustdoc::main`]. There is also `JavaScript` and `CSS` for the docs in [`src/tools/rustdoc-js`] -and [`src/tools/rustdoc-themes`]. +and [`src/tools/rustdoc-themes`]. The type definitions for `--output-format=json` +are in a separate crate in [`src/rustdoc-json-types`]. You can read more about [`rustdoc`] in [this chapter][rustdoc-chapter]. @@ -162,6 +163,7 @@ You can read more about [`rustdoc`] in [this chapter][rustdoc-chapter]. [`src/tools/rustdoc-js`]: https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc-js [`src/tools/rustdoc-themes`]: https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc-themes [`src/tools/rustdoc`]: https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc +[`src/rustdoc-json-types`]: https://github.com/rust-lang/rust/tree/master/src/rustdoc-json-types [rustdoc-chapter]: ./rustdoc.md ## Tests diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md index 9922ee7ddf2..6be52833f39 100644 --- a/src/doc/rustc-dev-guide/src/compiler-team.md +++ b/src/doc/rustc-dev-guide/src/compiler-team.md @@ -12,7 +12,7 @@ contributions to rustc and its design. Currently the compiler team chats in Zulip: - Team chat occurs in the [`t-compiler`][zulip-t-compiler] stream on the Zulip instance -- There are also a number of other associated Zulip streams, +- There are also a number of other associated Zulip channels, such as [`t-compiler/help`][zulip-help], where people can ask for help with rustc development, or [`t-compiler/meetings`][zulip-meetings], where the team holds their weekly triage and steering meetings. diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 963bef3af8d..3d196ae2308 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -26,8 +26,7 @@ conditions that trigger the bug, or part of the error message if there is any. An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**. -Opening an issue is as easy as following [this -link](https://github.com/rust-lang/rust/issues/new/choose) and filling out the fields +Opening an issue is as easy as following [thi link][create an issue] and filling out the fields in the appropriate provided template. ## Bug fixes or "normal" code changes @@ -75,7 +74,7 @@ Example of things that might require MCPs include major refactorings, changes to important types, or important changes to how the compiler does something, or smaller user-facing changes. -**When in doubt, ask on [zulip]. It would be a shame to put a lot of work +**When in doubt, ask on [Zulip]. It would be a shame to put a lot of work into a PR that ends up not getting merged!** [See this document][mcpinfo] for more info on MCPs. @@ -127,7 +126,7 @@ when contributing to Rust under [the git section](./git.md). > from), and work with the compiler team to see if we can help you **break down a large potentially > unreviewable PR into a series of smaller more individually reviewable PRs**. > -> You can communicate with the compiler team by creating a [#t-compiler thread on zulip][t-compiler] +> You can communicate with the compiler team by creating a [#t-compiler thread on Zulip][t-compiler] > to discuss your proposed changes. > > Communicating with the compiler team beforehand helps in several ways: @@ -154,11 +153,14 @@ The CI in rust-lang/rust applies your patches directly against the current maste not against the commit your branch is based on. This can lead to unexpected failures if your branch is outdated, even when there are no explicit merge conflicts. -Before submitting or updating a PR, make sure to update your branch -as mentioned [here](git.md#keeping-things-up-to-date) if it's significantly -behind the master branch (e.g., more than 100 commits behind). -This fetches the latest master branch and rebases your changes on top of it, -ensuring your PR is tested against the latest code. +Update your branch only when needed: when you have merge conflicts, upstream CI is broken and blocking your green PR, or a maintainer requests it. +Avoid updating an already-green PR under review unless necessary. +During review, make incremental commits to address feedback. +Prefer to squash or rebase only at the end, or when a reviewer requests it. + +When updating, use `git push --force-with-lease` and leave a brief comment explaining what changed. +Some repos prefer merging from `upstream/master` instead of rebasing; follow the project's conventions. +See [keeping things up to date](git.md#keeping-things-up-to-date) for detailed instructions. After rebasing, it's recommended to [run the relevant tests locally](tests/intro.md) to catch any issues before CI runs. @@ -372,6 +374,11 @@ You can also use `rustdoc` directly to check small fixes. For example, `rustdoc src/doc/reference.md` will render reference to `doc/reference.html`. The CSS might be messed up, but you can verify that the HTML is right. +Please notice that we don't accept typography/spellcheck fixes to **internal documentation** +as it's usually not worth the churn or the review time. +Examples of internal documentation is code comments and rustc api docs. +However, feel free to fix those if accompanied by other improvements in the same PR. + ### Contributing to rustc-dev-guide Contributions to the [rustc-dev-guide] are always welcome, and can be made directly at @@ -434,7 +441,8 @@ Just a few things to keep in mind: #### ⚠️ Note: Where to contribute `rustc-dev-guide` changes -For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, see [the rustc-dev-guide working group documentation](https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes). +For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, +see [the rustc-dev-guide working group documentation]. ## Issue triage @@ -451,6 +459,7 @@ Please see <https://forge.rust-lang.org/release/issue-triaging.html>. [regression-]: https://github.com/rust-lang/rust/labels?q=regression [relnotes]: https://github.com/rust-lang/rust/labels/relnotes [S-tracking-]: https://github.com/rust-lang/rust/labels?q=s-tracking +[the rustc-dev-guide working group documentation]: https://forge.rust-lang.org/wg-rustc-dev-guide/index.html#where-to-contribute-rustc-dev-guide-changes ### Rfcbot labels @@ -498,3 +507,4 @@ This section has moved to the ["About this guide"] chapter. [RFC 1574]: https://github.com/rust-lang/rfcs/blob/master/text/1574-more-api-documentation-conventions.md#appendix-a-full-conventions-text [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/ [rdgrepo]: https://github.com/rust-lang/rustc-dev-guide +[create an issue]: https://github.com/rust-lang/rust/issues/new/choose diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 38ba33112f2..0b341a40f1d 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -102,7 +102,7 @@ These identifiers can be converted into one another through the `TyCtxt`. [`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html [`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html -[`HirId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir_id/struct.HirId.html +[`HirId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/struct.HirId.html [`BodyId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.BodyId.html [Node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html [`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html diff --git a/src/doc/rustc-dev-guide/src/notification-groups/arm.md b/src/doc/rustc-dev-guide/src/notification-groups/arm.md index 3abc32c6888..5b79030d20d 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/arm.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/arm.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing ARM-related issues as well as suggestions on how to resolve interesting questions regarding our ARM support. -The group also has an associated Zulip stream ([`#t-compiler/arm`]) +The group also has an associated Zulip channel ([`#t-compiler/arm`]) where people can go to pose questions and discuss ARM-specific topics. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md index 100dbdf9f2b..9e4086c884e 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/emscripten.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing Emscripten-related issues as well as suggestions on how to resolve interesting questions regarding our Emscripten support. -The group also has an associated Zulip stream ([`#t-compiler/wasm`]) +The group also has an associated Zulip channel ([`#t-compiler/wasm`]) where people can go to pose questions and discuss Emscripten-specific topics. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md index 1b31297b600..7c8a3cdf8a6 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/risc-v.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing RISC-V-related issues as well as suggestions on how to resolve interesting questions regarding our RISC-V support. -The group also has an associated Zulip stream ([`#t-compiler/risc-v`]) +The group also has an associated Zulip channel ([`#t-compiler/risc-v`]) where people can go to pose questions and discuss RISC-V-specific topics. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md index 696f2038e1a..ed1de9196de 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/rust-for-linux.md @@ -12,7 +12,7 @@ and features. The RfL maintainers should then ideally provide support for resolving the breakage or decide to temporarily accept the breakage and unblock CI by temporarily removing the RfL CI jobs. -The group also has an associated Zulip stream ([`#rust-for-linux`]) +The group also has an associated Zulip channel ([`#rust-for-linux`]) where people can go to ask questions and discuss topics related to Rust for Linux. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md index e438ee4bd09..88b9465be01 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/wasi.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/wasi.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing WASI-related issues as well as suggestions on how to resolve interesting questions regarding our WASI support. -The group also has an associated Zulip stream ([`#t-compiler/wasm`]) +The group also has an associated Zulip channel ([`#t-compiler/wasm`]) where people can go to pose questions and discuss WASI-specific topics. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md index c8b674cb93f..6f52b04251f 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/wasm.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/wasm.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing WebAssembly-related issues as well as suggestions on how to resolve interesting questions regarding our WASM support. -The group also has an associated Zulip stream ([`#t-compiler/wasm`]) +The group also has an associated Zulip channel ([`#t-compiler/wasm`]) where people can go to pose questions and discuss WASM-specific topics. diff --git a/src/doc/rustc-dev-guide/src/notification-groups/windows.md b/src/doc/rustc-dev-guide/src/notification-groups/windows.md index e615a2cbd8d..d245208e2ab 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/windows.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/windows.md @@ -9,7 +9,7 @@ This list will be used to ask for help both in diagnosing and testing Windows-related issues as well as suggestions on how to resolve interesting questions regarding our Windows support. -The group also has an associated Zulip stream ([`#t-compiler/windows`]) +The group also has an associated Zulip channel ([`#t-compiler/windows`]) where people can go to pose questions and discuss Windows-specific topics. diff --git a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md index e08f7709506..10e9452eda3 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md +++ b/src/doc/rustc-dev-guide/src/rustdoc-internals/rustdoc-json-test-suite.md @@ -1,3 +1,83 @@ # The `rustdoc-json` test suite -> **FIXME**: This section is a stub. It will be populated by [PR #2422](https://github.com/rust-lang/rustc-dev-guide/pull/2422/). +This page is specifically about the test suite named `rustdoc-json`, which tests rustdoc's [json output]. +For other test suites used for testing rustdoc, see [§Rustdoc test suites](../tests/compiletest.md#rustdoc-test-suites). + +Tests are run with compiletest, and have access to the usual set of [directives](../tests/directives.md). +Frequenly used directives here are: + +- [`//@ aux-build`][aux-build] to have dependencies. +- `//@ edition: 2021` (or some other edition). +- `//@ compile-flags: --document-hidden-items` to enable [document private items]. + +Each crate's json output is checked by 2 programs: [jsondoclint](#jsondocck) and [jsondocck](#jsondocck). + +## jsondoclint + +[jsondoclint] checks that all [`Id`]s exist in the `index` (or `paths`). +This makes sure there are no dangling [`Id`]s. + +<!-- TODO: It does some more things too? +Also, talk about how it works + --> + +## jsondocck + +[jsondocck] processes direcives given in comments, to assert that the values in the output are expected. +It's alot like [htmldocck](./rustdoc-test-suite.md) in that way. + +It uses [JSONPath] as a query language, which takes a path, and returns a *list* of values that that path is said to match to. + +### Directives + +- `//@ has <path>`: Checks `<path>` exists, i.e. matches at least 1 value. +- `//@ !has <path>`: Checks `<path>` doesn't exist, i.e. matches 0 values. +- `//@ has <path> <value>`: Check `<path>` exists, and at least 1 of the matches is equal to the given `<value>` +- `//@ !has <path> <value>`: Checks `<path>` exists, but none of the matches equal the given `<value>`. +- `//@ is <path> <value>`: Check `<path>` matches exactly one value, and it's equal to the given `<value>`. +- `//@ is <path> <value> <value>...`: Check that `<path>` matches to exactly every given `<value>`. + Ordering doesn't matter here. +- `//@ !is <path> <value>`: Check `<path>` matches exactly one value, and that value is not equal to the given `<value>`. +- `//@ count <path> <number>`: Check that `<path>` matches to `<number>` of values. +- `//@ set <name> = <path>`: Check that `<path>` matches exactly one value, and store that value to the variable called `<name>`. + +These are defined in [`directive.rs`]. + +### Values + +Values can be either JSON values, or variables. + +- JSON values are JSON literals, e.g. `true`, `"string"`, `{"key": "value"}`. + These often need to be quoted using `'`, to be processed as 1 value. See [§Argument spliting](#argument-spliting) +- Variables can be used to store the value in one path, and use it in later queries. + They are set with the `//@ set <name> = <path>` directive, and accessed with `$<name>` + + ```rust + //@ set foo = $some.path + //@ is $.some.other.path $foo + ``` + +### Argument spliting + +Arguments to directives are split using the [shlex] crate, which implements POSIX shell escaping. +This is because both `<path>` and `<value>` arguments to [directives](#directives) frequently have both +whitespace and quote marks. + +To use the `@ is` with a `<path>` of `$.index[?(@.docs == "foo")].some.field` and a value of `"bar"` [^why_quote], you'd write: + +```rust +//@ is '$.is[?(@.docs == "foo")].some.field' '"bar"' +``` + +[^why_quote]: The value needs to be `"bar"` *after* shlex splitting, because we + it needs to be a JSON string value. + +[json output]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#json-output +[jsondocck]: https://github.com/rust-lang/rust/tree/master/src/tools/jsondocck +[jsondoclint]: https://github.com/rust-lang/rust/tree/master/src/tools/jsondoclint +[aux-build]: ../tests/compiletest.md#building-auxiliary-crates +[`Id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/struct.Id.html +[document private items]: https://doc.rust-lang.org/nightly/rustdoc/command-line-arguments.html#--document-private-items-show-items-that-are-not-public +[`directive.rs`]: https://github.com/rust-lang/rust/blob/master/src/tools/jsondocck/src/directive.rs +[shlex]: https://docs.rs/shlex/1.3.0/shlex/index.html +[JSONPath]: https://www.rfc-editor.org/rfc/rfc9535.html diff --git a/src/doc/rustc-dev-guide/src/rustdoc.md b/src/doc/rustc-dev-guide/src/rustdoc.md index 9290fcd3b41..6127a894a0f 100644 --- a/src/doc/rustc-dev-guide/src/rustdoc.md +++ b/src/doc/rustc-dev-guide/src/rustdoc.md @@ -107,7 +107,7 @@ This comes with several caveats: in particular, rustdoc *cannot* run any parts o require type-checking bodies; for example it cannot generate `.rlib` files or run most lints. We want to move away from this model eventually, but we need some alternative for [the people using it][async-std]; see [various][zulip stop accepting broken code] -[previous][rustdoc meeting 2024-07-08] [zulip][compiler meeting 2023-01-26] [discussion][notriddle rfc]. +[previous][rustdoc meeting 2024-07-08] [Zulip][compiler meeting 2023-01-26] [discussion][notriddle rfc]. For examples of code that breaks if this hack is removed, see [`tests/rustdoc-ui/error-in-impl-trait`]. diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md index 8eb37bbe20b..702d3cfa6d5 100644 --- a/src/doc/rustc-dev-guide/src/serialization.md +++ b/src/doc/rustc-dev-guide/src/serialization.md @@ -106,7 +106,7 @@ type wrapper, like [`ty::Predicate`] and manually implementing `Encodable` and [`Encodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_serialize/trait.Encodable.html [`Encoder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_serialize/trait.Encoder.html [`RefDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/codec/trait.RefDecodable.html -[`rustc_middle`]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_type_ir/codec.rs.html#21 +[`rustc_middle`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/index.html [`ty::Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/predicate/struct.Predicate.html [`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html [`TyDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.TyDecodable.html diff --git a/src/doc/rustc-dev-guide/src/solve/caching.md b/src/doc/rustc-dev-guide/src/solve/caching.md index e568d47ca25..cb7403de4e0 100644 --- a/src/doc/rustc-dev-guide/src/solve/caching.md +++ b/src/doc/rustc-dev-guide/src/solve/caching.md @@ -106,7 +106,7 @@ We can implement this optimization in the future. [`provisional_result`]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L57 [initial-prov-result]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L366-L370 [fixpoint]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/compiler/rustc_trait_selection/src/solve/search_graph.rs#L425-L446 -[^2]: summarizing the relevant [zulip thread] +[^2]: summarizing the relevant [Zulip thread] [zulip thread]: https://rust-lang.zulipchat.com/#narrow/stream/364551-t-types.2Ftrait-system-refactor/topic/global.20cache [unstable-result-ex]: https://github.com/rust-lang/rust/blob/7606c13961ddc1174b70638e934df0439b7dc515/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs#L4-L16 diff --git a/src/doc/rustc-dev-guide/src/solve/the-solver.md b/src/doc/rustc-dev-guide/src/solve/the-solver.md index 006fb649d22..0e095b55437 100644 --- a/src/doc/rustc-dev-guide/src/solve/the-solver.md +++ b/src/doc/rustc-dev-guide/src/solve/the-solver.md @@ -71,6 +71,6 @@ fails. ## Learning more The solver should be fairly self-contained. I hope that the above information provides a -good foundation when looking at the code itself. Please reach out on zulip if you get stuck +good foundation when looking at the code itself. Please reach out on Zulip if you get stuck while doing so or there are some quirks and design decisions which were unclear and deserve better comments or should be mentioned here. diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md index e399930fc52..7b9e1eb5629 100644 --- a/src/doc/rustc-dev-guide/src/stabilization_guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md @@ -82,7 +82,7 @@ Most importantly, remove the code which flags an error if the feature-gate is no gate_all!(pub_restricted, "`pub(restricted)` syntax is experimental"); ``` -This `gate_feature_post!` macro prints an error if the `pub_restricted` feature is not enabled. It is not needed now that `#[pub_restricted]` is stable. +The `gate_all!` macro reports an error if the `pub_restricted` feature is not enabled. It is not needed now that `pub(restricted)` is stable. For more subtle features, you may find code like this: diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 4ff6b7cb10f..4be78fac4ec 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -36,9 +36,9 @@ directive. The following is a list of compiletest directives. Directives are linked to sections that describe the command in more detail if available. This list may not be exhaustive. Directives can generally be found by browsing the -`TestProps` structure found in [`header.rs`] from the compiletest source. +`TestProps` structure found in [`directives.rs`] from the compiletest source. -[`header.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/header.rs +[`directives.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/directives.rs ### Assembly @@ -374,7 +374,7 @@ the directive's backing store (holds the command's current value) at runtime. To add a new directive property: 1. Look for the `pub struct TestProps` declaration in - [`src/tools/compiletest/src/header.rs`] and add the new public property to + [`src/tools/compiletest/src/directives.rs`] and add the new public property to the end of the declaration. 2. Look for the `impl TestProps` implementation block immediately following the struct declaration and initialize the new property to its default value. @@ -383,7 +383,7 @@ To add a new directive property: When `compiletest` encounters a test file, it parses the file a line at a time by calling every parser defined in the `Config` struct's implementation block, -also in [`src/tools/compiletest/src/header.rs`] (note that the `Config` struct's +also in [`src/tools/compiletest/src/directives.rs`] (note that the `Config` struct's declaration block is found in [`src/tools/compiletest/src/common.rs`]). `TestProps`'s `load_from()` method will try passing the current line of text to each parser, which, in turn typically checks to see if the line begins with a @@ -406,7 +406,7 @@ and their associated parsers immediately above to see how they are used to avoid writing additional parsing code unnecessarily. As a concrete example, here is the implementation for the -`parse_failure_status()` parser, in [`src/tools/compiletest/src/header.rs`]: +`parse_failure_status()` parser, in [`src/tools/compiletest/src/directives.rs`]: ```diff @@ -232,6 +232,7 @@ pub struct TestProps { @@ -508,6 +508,6 @@ example, `//@ failure-status: 1`, `self.props.failure_status` will evaluate to 1, as `parse_failure_status()` will have overridden the `TestProps` default value, for that test specifically. -[`src/tools/compiletest/src/header.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/header.rs +[`src/tools/compiletest/src/directives.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/directives.rs [`src/tools/compiletest/src/common.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/common.rs [`src/tools/compiletest/src/runtest.rs`]: https://github.com/rust-lang/rust/tree/master/src/tools/compiletest/src/runtest.rs diff --git a/src/doc/rustc-dev-guide/src/traits/chalk.md b/src/doc/rustc-dev-guide/src/traits/chalk.md index 844f42b9879..ca5ed525917 100644 --- a/src/doc/rustc-dev-guide/src/traits/chalk.md +++ b/src/doc/rustc-dev-guide/src/traits/chalk.md @@ -5,7 +5,7 @@ Its goal is to enable a lot of trait system features and bug fixes that are hard to implement (e.g. GATs or specialization). If you would like to help in hacking on the new solver, drop by on the rust-lang Zulip in the [`#t-types`] -stream and say hello! +channel and say hello! [Types team]: https://github.com/rust-lang/types-team [`#t-types`]: https://rust-lang.zulipchat.com/#narrow/stream/144729-t-types diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index 2243205f129..24982a209fd 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -239,13 +239,13 @@ differently. It uses canonical queries for trait solving which use [`take_and_reset_region_constraints`] at the end. This extracts all of the outlives constraints added during the canonical query. This is required as the NLL solver must not only know *what* regions outlive each other, -but also *where*. Finally, the NLL solver invokes [`take_region_var_origins`], +but also *where*. Finally, the NLL solver invokes [`get_region_var_infos`], providing all region variables to the solver. -[`resolve_regions_and_report_errors`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.resolve_regions_and_report_errors +[`resolve_regions_and_report_errors`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html#method.resolve_regions_and_report_errors [`lexical_region_resolve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/lexical_region_resolve/index.html [`take_and_reset_region_constraints`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.take_and_reset_region_constraints -[`take_region_var_origins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.take_region_var_origins +[`get_region_var_infos`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.get_region_var_infos ## Lexical region resolution diff --git a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md index db15467a47a..45635ebfa15 100644 --- a/src/doc/rustc-dev-guide/src/typing_parameter_envs.md +++ b/src/doc/rustc-dev-guide/src/typing_parameter_envs.md @@ -2,11 +2,14 @@ ## Typing Environments -When interacting with the type system there are a few variables to consider that can affect the results of trait solving. The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). +When interacting with the type system there are a few variables to consider that can affect the results of trait solving. +The set of in-scope where clauses, and what phase of the compiler type system operations are being performed in (the [`ParamEnv`][penv] and [`TypingMode`][tmode] structs respectively). -When an environment to perform type system operations in has not yet been created, the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type. +When an environment to perform type system operations in has not yet been created, +the [`TypingEnv`][tenv] can be used to bundle all of the external context required into a single type. -Once a context to perform type system operations in has been created (e.g. an [`ObligationCtxt`][ocx] or [`FnCtxt`][fnctxt]) a `TypingEnv` is typically not stored anywhere as only the `TypingMode` is a property of the whole environment, whereas different `ParamEnv`s can be used on a per-goal basis. +Once a context to perform type system operations in has been created (e.g. an [`ObligationCtxt`][ocx] or [`FnCtxt`][fnctxt]) a `TypingEnv` is typically not stored anywhere as only the `TypingMode` is a property of the whole environment, +whereas different `ParamEnv`s can be used on a per-goal basis. [ocx]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/struct.ObligationCtxt.html [fnctxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html @@ -15,9 +18,14 @@ Once a context to perform type system operations in has been created (e.g. an [` ### What is a `ParamEnv` -The [`ParamEnv`][penv] is a list of in-scope where-clauses, it typically corresponds to a specific item's where clauses. Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, such as `ConstArgHasType` or (some) implied bounds. +The [`ParamEnv`][penv] is a list of in-scope where-clauses, +it typically corresponds to a specific item's where clauses. +Some clauses are not explicitly written but are instead implicitly added in the [`predicates_of`][predicates_of] query, +such as `ConstArgHasType` or (some) implied bounds. -In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. +In most cases `ParamEnv`s are initially created via the [`param_env` query][query] which returns a `ParamEnv` derived from the provided item's where clauses. +A `ParamEnv` can also be created with arbitrary sets of clauses that are not derived from a specific item, +such as in [`compare_method_predicate_entailment`][method_pred_entailment] where we create a hybrid `ParamEnv` consisting of the impl's where clauses and the trait definition's function's where clauses. --- @@ -30,7 +38,9 @@ where <T as Trait>::Assoc: Clone, {} ``` -If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. This would allow things such as [normalization], evaluating generic constants, and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc. +If we were conceptually inside of `foo` (for example, type-checking or linting it) we would use this `ParamEnv` everywhere that we interact with the type system. +This would allow things such as [normalization], evaluating generic constants, +and proving where clauses/goals, to rely on `T` being sized, implementing `Trait`, etc. A more concrete example: ```rust @@ -72,9 +82,13 @@ fn foo2<T>(a: T) { ### Acquiring a `ParamEnv` -Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, illformed programs compiling, or erroring when we shouldn't. See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs. +Using the wrong [`ParamEnv`][penv] when interacting with the type system can lead to ICEs, +illformed programs compiling, or erroring when we shouldn't. +See [#82159](https://github.com/rust-lang/rust/pull/82159) and [#82067](https://github.com/rust-lang/rust/pull/82067) as examples of PRs that modified the compiler to use the correct param env and in the process fixed ICEs. -In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, or above in the call stack and should be passed down. A non exhaustive list of places where you might find an existing `ParamEnv`: +In the large majority of cases, when a `ParamEnv` is required it either already exists somewhere in scope, +or above in the call stack and should be passed down. +A non exhaustive list of places where you might find an existing `ParamEnv`: - During typeck `FnCtxt` has a [`param_env` field][fnctxt_param_env] - When writing late lints the `LateContext` has a [`param_env` field][latectxt_param_env] - During well formedness checking the `WfCheckingCtxt` has a [`param_env` field][wfckctxt_param_env] @@ -82,16 +96,20 @@ In the large majority of cases, when a `ParamEnv` is required it either already - In the next-gen trait solver all `Goal`s have a [`param_env` field][goal_param_env] specifying what environment to prove the goal in - When editing an existing [`TypeRelation`][typerelation] if it implements [`PredicateEmittingRelation`][predicate_emitting_relation] then a [`param_env` method][typerelation_param_env] will be available. -If you aren't sure if there's a `ParamEnv` in scope somewhere that can be used it can be worth opening a thread in the [`#t-compiler/help`][compiler_help] zulip stream where someone may be able to point out where a `ParamEnv` can be acquired from. +If you aren't sure if there's a `ParamEnv` in scope somewhere that can be used it can be worth opening a thread in the [`#t-compiler/help`][compiler_help] Zulip channel where someone may be able to point out where a `ParamEnv` can be acquired from. -Manually constructing a `ParamEnv` is typically only needed at the start of some kind of top level analysis (e.g. hir typeck or borrow checking). In such cases there are three ways it can be done: +Manually constructing a `ParamEnv` is typically only needed at the start of some kind of top level analysis (e.g. hir typeck or borrow checking). +In such cases there are three ways it can be done: - Calling the [`tcx.param_env(def_id)` query][param_env_query] which returns the environment associated with a given definition. - Creating an empty environment with [`ParamEnv::empty`][env_empty]. -- Using [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses. Then calling [`traits::normalize_param_env_or_error`][normalize_env_or_error] to handle normalizing and elaborating all the where clauses in the env. +- Using [`ParamEnv::new`][param_env_new] to construct an env with an arbitrary set of where clauses. + Then calling [`traits::normalize_param_env_or_error`][normalize_env_or_error] to handle normalizing and elaborating all the where clauses in the env. Using the `param_env` query is by far the most common way to construct a `ParamEnv` as most of the time the compiler is performing an analysis as part of some specific definition. -Creating an empty environment with `ParamEnv::empty` is typically only done either in codegen (indirectly via [`TypingEnv::fully_monomorphized`][tenv_mono]), or as part of some analysis that do not expect to ever encounter generic parameters (e.g. various parts of coherence/orphan check). +Creating an empty environment with `ParamEnv::empty` is typically only done either in codegen (indirectly via [`TypingEnv::fully_monomorphized`][tenv_mono]), +or as part of some analysis that do not expect to ever encounter generic parameters +(e.g. various parts of coherence/orphan check). Creating an env from an arbitrary set of where clauses is usually unnecessary and should only be done if the environment you need does not correspond to an actual item in the source code (e.g. [`compare_method_predicate_entailment`][method_pred_entailment]). @@ -113,11 +131,14 @@ Creating an env from an arbitrary set of where clauses is usually unnecessary an ### How are `ParamEnv`s constructed -Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user. We need to both elaborate supertraits into the env and fully normalize all aliases. This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration). +Creating a [`ParamEnv`][pe] is more complicated than simply using the list of where clauses defined on an item as written by the user. +We need to both elaborate supertraits into the env and fully normalize all aliases. +This logic is handled by [`traits::normalize_param_env_or_error`][normalize_env_or_error] (even though it does not mention anything about elaboration). #### Elaborating supertraits -When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait. Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits. +When we have a function such as `fn foo<T: Copy>()` we would like to be able to prove `T: Clone` inside of the function as the `Copy` trait has a `Clone` supertrait. +Constructing a `ParamEnv` looks at all of the trait bounds in the env and explicitly adds new where clauses to the `ParamEnv` for any supertraits found on the traits. A concrete example would be the following function: ```rust @@ -133,13 +154,16 @@ fn bar<T: Copy + Trait>(a: T) { fn requires_impl<T: Clone + SuperSuperTrait>(a: T) {} ``` -If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`. In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually: +If we did not elaborate the env then the `requires_impl` call would fail to typecheck as we would not be able to prove `T: Clone` or `T: SuperSuperTrait`. +In practice we elaborate the env which means that `bar`'s `ParamEnv` is actually: `[T: Sized, T: Copy, T: Clone, T: Trait, T: SuperTrait, T: SuperSuperTrait]` This allows us to prove `T: Clone` and `T: SuperSuperTrait` when type checking `bar`. The `Clone` trait has a `Sized` supertrait however we do not end up with two `T: Sized` bounds in the env (one for the supertrait and one for the implicitly added `T: Sized` bound) as the elaboration process (implemented via [`util::elaborate`][elaborate]) deduplicates where clauses. -A side effect of this is that even if no actual elaboration of supertraits takes place, the existing where clauses in the env are _also_ deduplicated. See the following example: +A side effect of this is that even if no actual elaboration of supertraits takes place, +the existing where clauses in the env are _also_ deduplicated. +See the following example: ```rust trait Trait {} // The unelaborated `ParamEnv` would be: @@ -156,7 +180,8 @@ The [next-gen trait solver][next-gen-solver] also requires this elaboration to t #### Normalizing all bounds -In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized as otherwise the trait solver will not function correctly. A concrete example of needing to normalize the `ParamEnv` is the following: +In the old trait solver the where clauses stored in `ParamEnv` are required to be fully normalized as otherwise the trait solver will not function correctly. +A concrete example of needing to normalize the `ParamEnv` is the following: ```rust trait Trait<T> { type Assoc; @@ -182,11 +207,14 @@ where fn requires_impl<U: Trait<u32>>(_: U) {} ``` -As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`. In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`. +As humans we can tell that `<T as Other>::Bar` is equal to `u32` so the trait bound on `U` is equivalent to `U: Trait<u32>`. +In practice trying to prove `U: Trait<u32>` in the old solver in this environment would fail as it is unable to determine that `<T as Other>::Bar` is equal to `u32`. To work around this we normalize `ParamEnv`'s after constructing them so that `foo`'s `ParamEnv` is actually: `[T: Sized, U: Sized, U: Trait<u32>]` which means the trait solver is now able to use the `U: Trait<u32>` in the `ParamEnv` to determine that the trait bound `U: Trait<u32>` holds. -This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem. We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`. Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]). +This workaround does not work in all cases as normalizing associated types requires a `ParamEnv` which introduces a bootstrapping problem. +We need a normalized `ParamEnv` in order for normalization to give correct results, but we need to normalize to get that `ParamEnv`. +Currently we normalize the `ParamEnv` once using the unnormalized param env and it tends to give okay results in practice even though there are some examples where this breaks ([example]). In the next-gen trait solver the requirement for all where clauses in the `ParamEnv` to be fully normalized is not present and so we do not normalize when constructing `ParamEnv`s. @@ -196,9 +224,12 @@ In the next-gen trait solver the requirement for all where clauses in the `Param ## Typing Modes -Depending on what context we are performing type system operations in, different behaviour may be required. For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal. +Depending on what context we are performing type system operations in, +different behaviour may be required. +For example during coherence there are stronger requirements about when we can consider goals to not hold or when we can consider types to be unequal. -Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tmode] enum. The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly. +Tracking which "phase" of the compiler type system operations are being performed in is done by the [`TypingMode`][tmode] enum. +The documentation on the `TypingMode` enum is quite good so instead of repeating it here verbatim we would recommend reading the API documentation directly. [penv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.ParamEnv.html [tenv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypingEnv.html diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml index 3ac5d57a52b..4a885239152 100644 --- a/src/doc/rustc-dev-guide/triagebot.toml +++ b/src/doc/rustc-dev-guide/triagebot.toml @@ -90,7 +90,6 @@ does not need reviews. You can request a review using `r? rustc-dev-guide` or \ [assign.adhoc_groups] rustc-dev-guide = [ "@BoxyUwU", - "@jieyouxu", "@jyn514", "@tshepang", ] diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 8e378e53e51..e4bf33dd8a0 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -48,6 +48,7 @@ - [\*-apple-visionos](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md) + - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md) - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md) - [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md) - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) @@ -55,7 +56,9 @@ - [arm-none-eabi](platform-support/arm-none-eabi.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) - - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md) + - [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md) + - [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md) + - [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md) - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md) - [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md) - [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md) diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 00add2651ae..4caeaa106b4 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -134,7 +134,7 @@ As of `2025-01-02T`, the list of known names is as follows: - `unix` - `windows` -> Starting with 1.85.0, the `test` cfg is consider to be a "userspace" config +> Starting with 1.85.0, the `test` cfg is considered to be a "userspace" config > despite being also set by `rustc` and should be managed by the build system itself. Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 6c5b48d8c8f..e5e46f72637 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -95,8 +95,8 @@ target | notes `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17) `armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony -[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36) -[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5) +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required +[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17) @@ -149,22 +149,22 @@ target | std | notes [`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia -`aarch64-unknown-none` | * | Bare ARM64, hardfloat -`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat +[`aarch64-unknown-none`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, hardfloat +[`aarch64-unknown-none-softfloat`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, softfloat [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI [`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android `arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3 `arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC -[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian -[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat +[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian +[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat -[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A +[`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87] diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md new file mode 100644 index 00000000000..7e18e8c157f --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md @@ -0,0 +1,78 @@ +# `aarch64-unknown-none` and `aarch64-unknown-none-softfloat` + +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) + +Bare-metal targets for CPUs in the Armv8-A architecture family, running in AArch64 mode. + +For the AArch32 mode carried over from Armv7-A, see +[`armv7a-none-eabi`](armv7a-none-eabi.md) instead. + +Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus]. + +[aarch64-cpus]: https://en.wikipedia.org/wiki/Comparison_of_ARM_processors#ARMv8-A + +## Target maintainers + +[Rust Embedded Devices Working Group Arm Team] + +[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team + +## Target CPU and Target Feature options + +All AArch64 processors include an FPU. The difference between the `-none` and +`-none-softfloat` targets is whether the FPU is used for passing function arguments. +You may prefer the `-softfloat` target when writing a kernel or interfacing with +pre-compiled binaries that use the soft-float ABI. + +When using the hardfloat targets, the minimum floating-point features assumed +are those of the `fp-armv8`, which excludes NEON SIMD support. If your +processor supports a different set of floating-point features than the default +expectations of `fp-armv8`, then these should also be enabled or disabled as +needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or +LLVM) that you have a specific model of Arm processor, using the +[`-Ctarget-cpu`][target-cpu] option. Doing so may change the default set of +target-features enabled. + +[target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu +[target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature + +## Requirements + +These targets are cross-compiled and use static linking. + +By default, the `lld` linker included with Rust will be used; however, you may +want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux +from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's +package manager. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.aarch64-unknown-none] +linker = "aarch64-none-elf-ld" +``` + +The GNU linker can also be used by specifying `aarch64-none-elf-gcc` as the +linker. This is needed when using GCC's link time optimization. + +These targets don't provide a linker script, so you'll need to bring your own +according to the specific device you are using. Pass +`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use +`your_script.ld` during linking. + +[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain + +## Cross-compilation toolchains and C code + +This target supports C code compiled with the `aarch64-none-elf` target +triple and a suitable `-march` or `-mcpu` flag. + +## Start-up and Low-Level Code + +The [Rust Embedded Devices Working Group Arm Team] maintain the +[`aarch64-cpu`] crate, which may be useful for writing bare-metal code using +this target. + +The *TrustedFirmware* group also maintain [Rust crates for this +target](https://github.com/ArmFirmwareCrates). + +[`aarch64-cpu`]: https://docs.rs/aarch64-cpu diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index 9732df4be7f..aaa80e42971 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -12,10 +12,10 @@ their own document. ### Tier 2 Target List - Arm A-Profile Architectures - - `armv7a-none-eabi` + - [`armv7a-none-eabi`](armv7a-none-eabi.md) - Arm R-Profile Architectures - [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md) - - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armv7r-none-eabi.md) + - [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armebv7r-none-eabi.md) - Arm M-Profile Architectures - [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md) - [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md) @@ -28,7 +28,7 @@ their own document. ### Tier 3 Target List - Arm A-Profile Architectures - - `armv7a-none-eabihf` + - [`armv7a-none-eabihf`](armv7a-none-eabi.md) - Arm R-Profile Architectures - [`armv8r-none-eabihf`](armv8r-none-eabihf.md) - Arm M-Profile Architectures diff --git a/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md new file mode 100644 index 00000000000..3e90319c373 --- /dev/null +++ b/src/doc/rustc/src/platform-support/armebv7r-none-eabi.md @@ -0,0 +1,55 @@ +# `armebv7r-none-eabi` and `armebv7r-none-eabihf` + +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) + +Bare-metal target for CPUs in the Armv7-R architecture family running in Big +Endian mode. These processors support dual ARM/Thumb mode, with ARM mode as +the default. + +**NOTE:** You should almost always prefer the [little-endian +versions](armv7r-none-eabi.md) of these target. Big Endian Arm systems are +highly unusual. + +Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r]. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R + +## Target maintainers + +[@chrisnc](https://github.com/chrisnc) + +## Requirements + +Note that some variants of the Cortex-R have both big-endian instructions and +data. This configuration is known as BE-32, while data-only big-endianness is +known as BE-8. To build programs for BE-32 processors, the GNU linker must be +used with the `-mbe32` option. See [ARM Cortex-R Series Programmer's Guide: +Endianness][endianness] for more details about different endian modes. + +When using the hardfloat targets, the minimum floating-point features assumed +are those of the `vfpv3-d16`, which includes single- and double-precision, with +16 double-precision registers. This floating-point unit appears in Cortex-R4F +and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp] +for more details on the possible FPU variants. + +If your processor supports a different set of floating-point features than the +default expectations of `vfpv3-d16`, then these should also be enabled or +disabled as needed with `-C target-feature=(+/-)`. + +[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness + +[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors + +## Start-up and Low-Level Code + +The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] +and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code +using this target. Those crates include several examples which run in QEMU and +build using these targets. + +[`cortex-ar`]: https://docs.rs/cortex-ar +[`cortex-r-rt`]: https://docs.rs/cortex-r-rt diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index 56f919e2a12..c6d88762fb1 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -1,6 +1,7 @@ # armv4t-none-eabi / thumbv4t-none-eabi -Tier 3 +* **Tier: 3** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) These two targets are part of the [`arm-none-eabi`](arm-none-eabi.md) target group, and all the information there applies. diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md index 22287972b7e..e9f34d4ede8 100644 --- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -1,6 +1,7 @@ # `armv5te-none-eabi` -**Tier: 3** +* **Tier: 3** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for any cpu in the Armv5TE architecture family, supporting ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md new file mode 100644 index 00000000000..3dadda86a5f --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md @@ -0,0 +1,70 @@ +# `armv7a-none-eabi` and `armv7a-none-eabihf` + +* **Tier: 2** for `armv7a-none-eabi` +* **Tier: 3** for `armv7a-none-eabihf` +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) + +Bare-metal target for CPUs in the Armv7-A architecture family, supporting +dual ARM/Thumb mode, with ARM mode as the default. + +Note, this is for processors running in AArch32 mode. For the AArch64 mode +added in Armv8-A, see [`aarch64-unknown-none`](aarch64-unknown-none.md) instead. + +Processors in this family include the [Arm Cortex-A5, 8, 32, etc][cortex-a]. + +See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all +`arm-none-eabi` targets. + +[cortex-a]: https://en.wikipedia.org/wiki/ARM_Cortex-A + +## Target maintainers + +[Rust Embedded Devices Working Group Arm Team] + +[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team + +## Requirements + +Almost all Armv7-A processors include an FPU (a VFPv3 or a VFPv4). The +difference between the `-eabi` and `-eabihf` targets is whether the FPU is +used for passing function arguments. You may prefer the `-eabi` soft-float +target when the processor does not have a floating point unit or the compiled +code should not use the floating point unit. + +When using the hardfloat targets, the minimum floating-point features assumed +are those of the VFPv3-D16, which includes single- and double-precision, with +16 double-precision registers. This floating-point unit appears in Cortex-A8 +and Cortex-A9 processors. See [VFP in the Cortex-A processors][vfp] for more +details on the possible FPU variants. + +If your processor supports a different set of floating-point features than the +default expectations of VFPv3-D16, then these should also be enabled or +disabled as needed with `-C target-feature=(+/-)`. + +In general, the following four combinations are possible: + +- VFPv3-D16, target feature `+vfp3` and `-d32` +- VFPv3-D32, target feature `+vfp3` and `+d32` +- VFPv4-D16, target feature `+vfp4` and `-d32` +- VFPv4-D32, target feature `+vfp4` and `+d32` + +An Armv7-A processor may optionally include a NEON hardware unit which +provides Single Instruction Multiple Data (SIMD) operations. The +implementation of this unit implies VFPv3-D32. The target feature `+neon` may +be added to inform the compiler about the availability of NEON. + +You can refer to the [arm-none-eabi](arm-none-eabi.md) documentation for a +generic guide on target feature and target CPU specification and how to enable +and disable them via `.cargo/config.toml` file. + +[vfp]: https://developer.arm.com/documentation/den0013/0400/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/ARM-VFP + +## Start-up and Low-Level Code + +The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] +and [`cortex-a-rt`] crates, which may be useful for writing bare-metal code +using this target. The [`cortex-ar` repository](https://github.com/rust-embedded/cortex-ar) +includes several examples which run in QEMU and build using these targets. + +[`cortex-ar`]: https://docs.rs/cortex-ar +[`cortex-a-rt`]: https://docs.rs/cortex-a-rt diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md index 88b2689dcf0..c1252b4a4bf 100644 --- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md @@ -1,14 +1,13 @@ -# `arm(eb)?v7r-none-eabi(hf)?` +# `armv7r-none-eabi` and `armv7r-none-eabihf` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv7-R architecture family, supporting dual ARM/Thumb mode, with ARM mode as the default. Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r]. -The `eb` versions of this target generate code for big-endian processors. - See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all `arm-none-eabi` targets. @@ -17,15 +16,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers [@chrisnc](https://github.com/chrisnc) +[Rust Embedded Devices Working Group Arm Team] -## Requirements +[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team -When using the big-endian version of this target, note that some variants of -the Cortex-R have both big-endian instructions and data. This configuration is -known as BE-32, while data-only big-endianness is known as BE-8. To build -programs for BE-32 processors, the GNU linker must be used with the `-mbe32` -option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness] -for more details about different endian modes. +## Requirements When using the hardfloat targets, the minimum floating-point features assumed are those of the `vfpv3-d16`, which includes single- and double-precision, with @@ -41,7 +36,12 @@ disabled as needed with `-C target-feature=(+/-)`. [vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors -## Cross-compilation toolchains and C code +## Start-up and Low-Level Code + +The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`] +and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code +using this target. Those crates include several examples which run in QEMU and +build using these targets. -This target supports C code compiled with the `arm-none-eabi` target triple and -`-march=armv7-r` or a suitable `-mcpu` flag. +[`cortex-ar`]: https://docs.rs/cortex-ar +[`cortex-r-rt`]: https://docs.rs/cortex-r-rt diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md index 569d8802ebe..0d5a36c3ee2 100644 --- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md +++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md @@ -1,6 +1,7 @@ # `armv8r-none-eabihf` -**Tier: 3** +* **Tier: 3** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Armv8-R architecture family, supporting dual ARM/Thumb mode, with ARM mode as the default. @@ -17,6 +18,9 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers [@chrisnc](https://github.com/chrisnc) +[Rust Embedded Devices Working Group Arm Team] + +[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team ## Requirements @@ -34,7 +38,14 @@ Technical Reference Manual for more details. [fpu]: https://developer.arm.com/documentation/100026/0104/Advanced-SIMD-and-floating-point-support/About-the-Advanced-SIMD-and-floating-point-support -## Cross-compilation toolchains and C code - -This target supports C code compiled with the `arm-none-eabi` target triple and -`-march=armv8-r` or a suitable `-mcpu` flag. +### Table of supported CPUs for `armv8r-none-eabihf` + +| CPU | FPU | Neon | Target CPU | Target Features | +|:----------- | --- |:---- |:---------------- |:------------------ | +| Any | SP | No | None | None | +| Cortex-R52 | SP | No | `cortex-r52` | `-fp64,-d32,-neon` | +| Cortex-R52 | DP | No | `cortex-r52` | `-neon` | +| Cortex-R52 | DP | Yes | `cortex-r52` | None | +| Cortex-R52+ | SP | No | `cortex-r52plus` | `-fp64,-d32,-neon` | +| Cortex-R52+ | DP | No | `cortex-r52plus` | `-neon` | +| Cortex-R52+ | DP | Yes | `cortex-r52plus` | None | diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index 817d3a89230..a923218282c 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -7,8 +7,8 @@ LoongArch is a RISC ISA developed by Loongson Technology Corporation Limited. | Target | Description | |--------|-------------| -| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) | -| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) | +| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36), LSX required | +| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5), LSX required | These support both native and cross builds, and have full support for `std`. @@ -23,8 +23,6 @@ Reference material: ## Target maintainers [@heiher](https://github.com/heiher) -[@xiangzhai](https://github.com/xiangzhai) -[@zhaixiaojuan](https://github.com/zhaixiaojuan) [@xen0n](https://github.com/xen0n) ## Requirements @@ -46,8 +44,8 @@ The targets require a reasonably up-to-date LoongArch toolchain on the host. Currently the following components are used by the Rust CI to build the target, and the versions can be seen as the minimum requirement: -* GNU Binutils 2.40 -* GCC 13.x +* GNU Binutils 2.42 +* GCC 14.x * glibc 2.36 * linux-headers 5.19 @@ -59,6 +57,11 @@ for newer LoongArch ELF relocation types, among other features. Recent LLVM/Clang toolchains may be able to build the targets, but are not currently being actively tested. +### CPU features + +These targets require the double-precision floating-point and LSX (LoongArch +SIMD Extension) features. + ## Building These targets are distributed through `rustup`, and otherwise require no diff --git a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md index 746b8443547..d4bd0b0945a 100644 --- a/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv6m-none-eabi.md @@ -1,6 +1,7 @@ # `thumbv6m-none-eabi` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the [Armv6-M] architecture family, supporting a subset of the [T32 ISA][t32-isa]. @@ -26,7 +27,7 @@ only option because there is no FPU support in [Armv6-M]. ## Target maintainers -* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md index 12e28265678..98dcf9bd396 100644 --- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md @@ -1,6 +1,7 @@ # `thumbv7em-none-eabi` and `thumbv7em-none-eabihf` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the [Armv7E-M] architecture family, supporting a subset of the [T32 ISA][t32-isa]. @@ -21,7 +22,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md index 03324b341d0..d8f3970c8bf 100644 --- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md @@ -1,6 +1,7 @@ # `thumbv7m-none-eabi` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the [Armv7-M] architecture family, supporting a subset of the [T32 ISA][t32-isa]. @@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv7-M]. ## Target maintainers -* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md index 4a92e856466..b16d450275d 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md @@ -1,6 +1,7 @@ # `thumbv8m.base-none-eabi` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Baseline [Armv8-M] architecture family, supporting a subset of the [T32 ISA][t32-isa]. @@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv8-M] Baseline. ## Target maintainers -* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md index 9f85d08fa0a..a2d515d07ea 100644 --- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md +++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md @@ -1,6 +1,7 @@ # `thumbv8m.main-none-eabi` and `thumbv8m.main-none-eabihf` -**Tier: 2** +* **Tier: 2** +* **Library Support:** core and alloc (bare-metal, `#![no_std]`) Bare-metal target for CPUs in the Mainline [Armv8-M] architecture family, supporting a subset of the [T32 ISA][t32-isa]. @@ -25,7 +26,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all ## Target maintainers -* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) +[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team) ## Target CPU and Target Feature options diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index 6c1494186a4..e1750e27f0b 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -16,6 +16,21 @@ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print targe To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`. +<div class="warning"> + +The target JSON properties are not stable and subject to change. +Always pin your compiler version when using custom targets! + +</div> + +## JSON Schema + +`rustc` provides a JSON schema for the custom target JSON specification. +Because the schema is subject to change, you should always use the schema from the version of rustc which you are passing the target to. + +It can be found in `etc/target-spec-json-schema.json` in the sysroot (`rustc --print sysroot`) or printed with `rustc +nightly -Zunstable-options --print target-spec-json-schema`. +The existence and name of this schema is, just like the properties of the JSON specification, not stable and subject to change. + ## Custom Target Lookup Path When `rustc` is given an option `--target=TARGET` (where `TARGET` is any string), it uses the following logic: diff --git a/src/doc/sitemap.txt b/src/doc/sitemap.txt new file mode 100644 index 00000000000..6e5f0fbad37 --- /dev/null +++ b/src/doc/sitemap.txt @@ -0,0 +1,4 @@ +https://doc.rust-lang.org/stable/ +https://doc.rust-lang.org/beta/ +https://doc.rust-lang.org/nightly/ + diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 93932936a2e..5ccacafea01 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1256,7 +1256,10 @@ pub(crate) fn clean_impl_item<'tcx>( })), hir::ImplItemKind::Fn(ref sig, body) => { let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body)); - let defaultness = cx.tcx.defaultness(impl_.owner_id); + let defaultness = match impl_.impl_kind { + hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final, + hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness, + }; MethodItem(m, Some(defaultness)) } hir::ImplItemKind::Type(hir_ty) => { @@ -1295,12 +1298,14 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo simplify::move_bounds_to_generic_parameters(&mut generics); match assoc_item.container { - ty::AssocItemContainer::Impl => ImplAssocConstItem(Box::new(Constant { - generics, - kind: ConstantKind::Extern { def_id: assoc_item.def_id }, - type_: ty, - })), - ty::AssocItemContainer::Trait => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { + ImplAssocConstItem(Box::new(Constant { + generics, + kind: ConstantKind::Extern { def_id: assoc_item.def_id }, + type_: ty, + })) + } + ty::AssocContainer::Trait => { if tcx.defaultness(assoc_item.def_id).has_value() { ProvidedAssocConstItem(Box::new(Constant { generics, @@ -1318,10 +1323,10 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo if has_self { let self_ty = match assoc_item.container { - ty::AssocItemContainer::Impl => { + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => { tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity() } - ty::AssocItemContainer::Trait => tcx.types.self_param, + ty::AssocContainer::Trait => tcx.types.self_param, }; let self_param_ty = tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); @@ -1338,13 +1343,13 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } let provided = match assoc_item.container { - ty::AssocItemContainer::Impl => true, - ty::AssocItemContainer::Trait => assoc_item.defaultness(tcx).has_value(), + ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true, + ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(), }; if provided { let defaultness = match assoc_item.container { - ty::AssocItemContainer::Impl => Some(assoc_item.defaultness(tcx)), - ty::AssocItemContainer::Trait => None, + ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)), + ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None, }; MethodItem(item, defaultness) } else { @@ -1375,7 +1380,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo } let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; - if let ty::AssocItemContainer::Trait = assoc_item.container { + if let ty::AssocContainer::Trait = assoc_item.container { let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied(); predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); } @@ -1386,7 +1391,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo ); simplify::move_bounds_to_generic_parameters(&mut generics); - if let ty::AssocItemContainer::Trait = assoc_item.container { + if let ty::AssocContainer::Trait = assoc_item.container { // Move bounds that are (likely) directly attached to the associated type // from the where-clause to the associated type. // There is no guarantee that this is what the user actually wrote but we have diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index d684e6f8650..b5a8d64ff4f 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -3,6 +3,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast_pretty::pprust::PrintState; use rustc_ast_pretty::pprust::state::State as Printer; use rustc_middle::ty::TyCtxt; +use rustc_parse::lexer::StripTokens; use rustc_session::parse::ParseSess; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{FileName, Span}; @@ -64,14 +65,18 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String // Create a Parser. let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec()); let file_name = FileName::macro_expansion_source_code(&snippet); - let mut parser = - match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) { - Ok(parser) => parser, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - return None; - } - }; + let mut parser = match rustc_parse::new_parser_from_source_str( + &psess, + file_name, + snippet.clone(), + StripTokens::Nothing, + ) { + Ok(parser) => parser, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + return None; + } + }; // Reparse a single token tree. if parser.token == token::Eof { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index dcd67cb7ebc..bd3f4e9a6f2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -690,16 +690,13 @@ impl Item { // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we // won't be printing correct syntax plus the syntax is unstable. - match tcx.opt_associated_item(def_id) { - Some(ty::AssocItem { - container: ty::AssocItemContainer::Impl, - trait_item_def_id: Some(_), - .. - }) - | Some(ty::AssocItem { container: ty::AssocItemContainer::Trait, .. }) => { - hir::Constness::NotConst - } - None | Some(_) => hir::Constness::Const, + if let Some(assoc) = tcx.opt_associated_item(def_id) + && let ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) = + assoc.container + { + hir::Constness::NotConst + } else { + hir::Constness::Const } } else { hir::Constness::NotConst @@ -779,17 +776,13 @@ impl Item { | RequiredAssocTypeItem(..) | RequiredMethodItem(..) | MethodItem(..) => { - let assoc_item = tcx.associated_item(def_id); - let is_trait_item = match assoc_item.container { - ty::AssocItemContainer::Trait => true, - ty::AssocItemContainer::Impl => { - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some() + match tcx.associated_item(def_id).container { + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + ty::AssocContainer::Trait | ty::AssocContainer::TraitImpl(_) => { + return None; } - }; - if is_trait_item { - return None; + ty::AssocContainer::InherentImpl => {} } } _ => {} diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index f229f77c978..5eaadc9eb45 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -10,6 +10,7 @@ use rustc_ast::tokenstream::TokenTree; use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind}; use rustc_errors::emitter::stderr_destination; use rustc_errors::{ColorConfig, DiagCtxtHandle}; +use rustc_parse::lexer::StripTokens; use rustc_parse::new_parser_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::edition::{DEFAULT_EDITION, Edition}; @@ -468,14 +469,16 @@ fn parse_source( let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match new_parser_from_source_str(&psess, filename, wrapped_source) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - reset_error_count(&psess); - return Err(()); - } - }; + // Don't strip any tokens; it wouldn't matter anyway because the source is wrapped in a function. + let mut parser = + match new_parser_from_source_str(&psess, filename, wrapped_source, StripTokens::Nothing) { + Ok(p) => p, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + reset_error_count(&psess); + return Err(()); + } + }; fn push_to_s(s: &mut String, source: &str, span: rustc_span::Span, prev_span_hi: &mut usize) { let extra_len = DOCTEST_CODE_WRAPPER.len(); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index feafb41dc99..0e06361024b 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -578,7 +578,7 @@ pub(super) fn write_code( } fn write_footer(out: &mut String, playground_button: Option<&str>) { - write_str(out, format_args_nl!("</code></pre>{}</div>", playground_button.unwrap_or_default())); + write_str(out, format_args!("</code></pre>{}</div>", playground_button.unwrap_or_default())); } /// How a span of text is classified. Mostly corresponds to token kinds. diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b01b596da68..3b84ae2bed0 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3639,7 +3639,7 @@ class DocSearch { if (contains.length === 0) { return 0; } - const maxPathEditDistance = Math.floor( + const maxPathEditDistance = parsedQuery.literalSearch ? 0 : Math.floor( contains.reduce((acc, next) => acc + next.length, 0) / 3, ); let ret_dist = maxPathEditDistance + 1; @@ -3650,7 +3650,9 @@ class DocSearch { let dist_total = 0; for (let x = 0; x < clength; ++x) { const [p, c] = [path[i + x], contains[x]]; - if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance && + if (parsedQuery.literalSearch && p !== c) { + continue pathiter; + } else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance && p.indexOf(c) !== -1 ) { // discount distance on substring match diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f62eba4b3c1..9871066b9eb 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -10,7 +10,6 @@ #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(file_buffered)] -#![feature(format_args_nl)] #![feature(if_let_guard)] #![feature(iter_advance_by)] #![feature(iter_intersperse)] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 719b7c6ab89..0da42f38251 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -210,7 +210,7 @@ impl UrlFragment { &UrlFragment::Item(def_id) => { let kind = match tcx.def_kind(def_id) { DefKind::AssocFn => { - if tcx.defaultness(def_id).has_value() { + if tcx.associated_item(def_id).defaultness(tcx).has_value() { "method." } else { "tymethod." diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs index f70bdf4e4fe..06256d61151 100644 --- a/src/librustdoc/passes/lint/bare_urls.rs +++ b/src/librustdoc/passes/lint/bare_urls.rs @@ -17,7 +17,10 @@ use crate::core::DocContext; use crate::html::markdown::main_body_opts; pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) { - let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| { + let report_diag = |cx: &DocContext<'_>, + msg: &'static str, + range: Range<usize>, + without_brackets: Option<&str>| { let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings) .map(|(sp, _)| sp); let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx)); @@ -27,14 +30,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & // The fallback of using the attribute span is suitable for // highlighting where the error is, but not for placing the < and > if let Some(sp) = maybe_sp { - lint.multipart_suggestion( - "use an automatic link instead", - vec![ - (sp.shrink_to_lo(), "<".to_string()), - (sp.shrink_to_hi(), ">".to_string()), - ], - Applicability::MachineApplicable, - ); + if let Some(without_brackets) = without_brackets { + lint.multipart_suggestion( + "use an automatic link instead", + vec![(sp, format!("<{without_brackets}>"))], + Applicability::MachineApplicable, + ); + } else { + lint.multipart_suggestion( + "use an automatic link instead", + vec![ + (sp.shrink_to_lo(), "<".to_string()), + (sp.shrink_to_hi(), ">".to_string()), + ], + Applicability::MachineApplicable, + ); + } } }); }; @@ -43,7 +54,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & while let Some((event, range)) = p.next() { match event { - Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag), + Event::Text(s) => find_raw_urls(cx, dox, &s, range, &report_diag), // We don't want to check the text inside code blocks or links. Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => { for (event, _) in p.by_ref() { @@ -67,25 +78,35 @@ static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| { r"https?://", // url scheme r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains r"[a-zA-Z]{2,63}", // root domain - r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)" // optional query or url fragments + r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)", // optional query or url fragments )) .expect("failed to build regex") }); fn find_raw_urls( cx: &DocContext<'_>, + dox: &str, text: &str, range: Range<usize>, - f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>), + f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>, Option<&str>), ) { trace!("looking for raw urls in {text}"); // For now, we only check "full" URLs (meaning, starting with "http://" or "https://"). for match_ in URL_REGEX.find_iter(text) { - let url_range = match_.range(); - f( - cx, - "this URL is not a hyperlink", - Range { start: range.start + url_range.start, end: range.start + url_range.end }, - ); + let mut url_range = match_.range(); + url_range.start += range.start; + url_range.end += range.start; + let mut without_brackets = None; + // If the link is contained inside `[]`, then we need to replace the brackets and + // not just add `<>`. + if dox[..url_range.start].ends_with('[') + && url_range.end <= dox.len() + && dox[url_range.end..].starts_with(']') + { + url_range.start -= 1; + url_range.end += 1; + without_brackets = Some(match_.as_str()); + } + f(cx, "this URL is not a hyperlink", url_range, without_brackets); } } diff --git a/src/llvm-project b/src/llvm-project -Subproject 19f0a49c5c3f4ba88b5e7ac620b9a0d8574c09c +Subproject 333793696b0a08002acac6af983adc7a5233fc5 diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 761c4658d0079d607e6d33cf0c060e61a617cad +Subproject 24bb93c388fb8c211a37986539f24a819dc669d diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 9aa2f3cf0a5..9645a26a68a 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -364,7 +364,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // priority. if let Some(fn_id) = typeck.type_dependent_def_id(hir_id) && let Some(trait_id) = cx.tcx.trait_of_assoc(fn_id) - && let arg_ty = cx.tcx.erase_regions(adjusted_ty) + && let arg_ty = cx.tcx.erase_and_anonymize_regions(adjusted_ty) && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() && let args = typeck.node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default() diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 23e7c7251cf..49cd2671dc0 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefIdMap; use rustc_hir::{ - AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, + AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, ImplItemImplKind, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; @@ -177,7 +177,9 @@ impl LateLintPass<'_> for DisallowedMacros { fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) { self.check(cx, item.span, None); - self.check(cx, item.vis_span, None); + if let ImplItemImplKind::Inherent { vis_span, .. } = item.impl_kind { + self.check(cx, vis_span, None); + } } fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index 74283d7ba86..43bb9723555 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -8,6 +8,7 @@ use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_errors::emitter::HumanEmitter; use rustc_errors::{Diag, DiagCtxt}; use rustc_lint::LateContext; +use rustc_parse::lexer::StripTokens; use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; @@ -49,13 +50,14 @@ pub fn check( let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match new_parser_from_source_str(&psess, filename, code) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(Diag::cancel); - return (false, test_attr_spans); - }, - }; + let mut parser = + match new_parser_from_source_str(&psess, filename, code, StripTokens::ShebangAndFrontmatter) { + Ok(p) => p, + Err(errs) => { + errs.into_iter().for_each(Diag::cancel); + return (false, test_attr_spans); + }, + }; let mut relevant_main_found = false; let mut eligible = true; diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index f8e8f5544b9..e25611d4881 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::{Applicability, MultiSpan}; -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_hir::hir_id::OwnerId; +use rustc_hir::def_id::DefIdSet; use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; use rustc_span::Span; @@ -19,7 +18,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored of_trait: Some(of_trait), .. }) = &parent_item.kind - && let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id) + && let Some(did) = cx.tcx.trait_item_of(item.owner_id) && !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits) { let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id); @@ -87,11 +86,6 @@ impl RenamedFnArgs { } } -/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item. -fn trait_item_def_id_of_impl(cx: &LateContext<'_>, target: OwnerId) -> Option<DefId> { - cx.tcx.associated_item(target).trait_item_def_id -} - fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool { of_trait .trait_def_id() diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 010652e1cb9..6ce7f0b1f0b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -140,7 +140,7 @@ fn is_ref_iterable<'tcx>( let res_ty = cx .tcx - .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); + .erase_and_anonymize_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id))); let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { Some(mutbl) } else { diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index ba1ad599e11..bee3b19b597 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, - FnRetTy, GenericBound, ImplItem, Item, Node, OpaqueTy, TraitRef, Ty, TyKind, + FnRetTy, GenericBound, Node, OpaqueTy, TraitRef, Ty, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; @@ -60,8 +60,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { && let ExprKind::Block(block, _) = body.value.kind && block.stmts.is_empty() && let Some(closure_body) = desugared_async_block(cx, block) - && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = - cx.tcx.hir_node_by_def_id(fn_def_id) + && let Some(vis_span_opt) = match cx.tcx.hir_node_by_def_id(fn_def_id) { + Node::Item(item) => Some(Some(item.vis_span)), + Node::ImplItem(impl_item) => Some(impl_item.vis_span()), + _ => None, + } && !span.from_expansion() { let header_span = span.with_hi(ret_ty.span.hi()); @@ -72,7 +75,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { header_span, "this function can be simplified using the `async fn` syntax", |diag| { - if let Some(vis_snip) = vis_span.get_source_text(cx) + if let Some(vis_span) = vis_span_opt + && let Some(vis_snip) = vis_span.get_source_text(cx) && let Some(header_snip) = header_span.get_source_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) && let Some((_, ret_snip)) = suggested_ret(cx, output) diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index dbce29a8631..6258e408217 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -5,8 +5,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item}; use rustc_hir::{ - GenericParamKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, - UsePath, + GenericParamKind, HirId, Impl, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind, ItemLocalId, Node, Pat, + PatKind, TraitItem, UsePath, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; @@ -256,7 +256,7 @@ fn is_not_in_trait_impl(cx: &LateContext<'_>, pat: &Pat<'_>, ident: Ident) -> bo } fn get_param_name(impl_item: &ImplItem<'_>, cx: &LateContext<'_>, ident: Ident) -> Option<Symbol> { - if let Some(trait_item_def_id) = impl_item.trait_item_def_id { + if let ImplItemImplKind::Trait { trait_item_def_id: Ok(trait_item_def_id), .. } = impl_item.impl_kind { let trait_param_names = cx.tcx.fn_arg_idents(trait_item_def_id); let ImplItemKind::Fn(_, body_id) = impl_item.kind else { diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs index 788a04357b1..cf0c85990b1 100644 --- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs @@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnindexMap; use rustc_errors::{Applicability, Diag}; -use rustc_hir::{Body, Expr, ExprKind}; +use rustc_hir::{Block, Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -135,12 +135,12 @@ fn assert_len_expr<'hir>( cx: &LateContext<'_>, expr: &'hir Expr<'hir>, ) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> { - let (cmp, asserted_len, slice_len) = if let Some( - higher::IfLetOrMatch::Match(cond, [_, then], _) - ) = higher::IfLetOrMatch::parse(cx, expr) - && let ExprKind::Binary(bin_op, left, right) = &cond.kind + let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) + && let ExprKind::Unary(UnOp::Not, condition) = &cond.kind + && let ExprKind::Binary(bin_op, left, right) = &condition.kind // check if `then` block has a never type expression - && cx.typeck_results().expr_ty(then.body).is_never() + && let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind + && cx.typeck_results().expr_ty(then_expr).is_never() { len_comparison(bin_op.node, left, right)? } else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| { diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index a6be7581c9a..a63ad978626 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -158,13 +158,23 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { let mir = cx.tcx.optimized_mir(def_id); if let Ok(()) = is_min_const_fn(cx, mir, self.msrv) - && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = - cx.tcx.hir_node_by_def_id(def_id) + && let node = cx.tcx.hir_node_by_def_id(def_id) + && let Some((item_span, vis_span_opt)) = match node { + hir::Node::Item(item) => Some((item.span, Some(item.vis_span))), + hir::Node::ImplItem(impl_item) => Some((impl_item.span, impl_item.vis_span())), + _ => None, + } { - let suggestion = if vis_span.is_empty() { "const " } else { " const" }; + let (sugg_span, suggestion) = if let Some(vis_span) = vis_span_opt + && !vis_span.is_empty() + { + (vis_span.shrink_to_hi(), " const") + } else { + (item_span.shrink_to_lo(), "const ") + }; span_lint_and_then(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`", |diag| { diag.span_suggestion_verbose( - vis_span.shrink_to_hi(), + sugg_span, "make the function `const`", suggestion, Applicability::MachineApplicable, diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 7772051eb5c..39b5964bd87 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -16,7 +16,7 @@ use rustc_hir::Attribute; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::Visibility; +use rustc_middle::ty::{AssocContainer, Visibility}; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::kw; @@ -246,12 +246,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { // If the method is an impl for a trait, don't doc. - if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) { - if cx.tcx.impl_trait_ref(cid).is_some() { + match cx.tcx.associated_item(impl_item.owner_id).container { + AssocContainer::Trait | AssocContainer::TraitImpl(_) => { note_prev_span_then_ret!(self.prev_span, impl_item.span); - } - } else { - note_prev_span_then_ret!(self.prev_span, impl_item.span); + }, + AssocContainer::InherentImpl => {} } let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 28555a61090..6323e728666 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -3,7 +3,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, Attribute, find_attr}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::AssocItemContainer; +use rustc_middle::ty::AssocContainer; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -166,8 +166,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let container_id = assoc_item.container_id(cx.tcx); let trait_def_id = match assoc_item.container { - AssocItemContainer::Trait => Some(container_id), - AssocItemContainer::Impl => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id), + AssocContainer::Trait => Some(container_id), + AssocContainer::TraitImpl(_) => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id), + AssocContainer::InherentImpl => None, }; if let Some(trait_def_id) = trait_def_id diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs index 9cc93bf0653..8e9400e9d58 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods { .tcx .associated_items(item.owner_id) .in_definition_order() - .filter_map(|assoc_item| assoc_item.trait_item_def_id) + .filter_map(|assoc_item| assoc_item.expect_trait_impl().ok()) .collect(); for assoc in cx diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index a42763172f5..c4cad592e36 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -248,11 +248,11 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { .tcx .impl_trait_ref(item.owner_id) .map(EarlyBinder::instantiate_identity) - && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id + && let Some(trait_item_id) = cx.tcx.trait_item_of(owner_id) { ( trait_item_id, - FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize), + FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_and_anonymize_regions(trait_ref.args)) as usize), usize::from(sig.decl.implicit_self.has_implicit_self()), ) } else { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 3842c4eb60e..6aeb22d41a7 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>( Applicability::MaybeIncorrect, ); triggered = true; - } else if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) && !const_context { + } else if (cx.tcx.erase_and_anonymize_regions(from_ty) != cx.tcx.erase_and_anonymize_regions(to_ty)) && !const_context { span_lint_and_then( cx, TRANSMUTE_PTR_TO_PTR, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs index 26323af3122..3e6aae475ec 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -12,8 +12,8 @@ pub(super) fn check<'tcx>( from_ty_orig: Ty<'tcx>, to_ty_orig: Ty<'tcx>, ) -> bool { - let mut from_ty = cx.tcx.erase_regions(from_ty_orig); - let mut to_ty = cx.tcx.erase_regions(to_ty_orig); + let mut from_ty = cx.tcx.erase_and_anonymize_regions(from_ty_orig); + let mut to_ty = cx.tcx.erase_and_anonymize_regions(to_ty_orig); while from_ty != to_ty { let reduced_tys = reduce_refs(cx, from_ty, to_ty); diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index aeda864b7eb..8252e6d4869 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -151,8 +151,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { // trait, not in the impl of the trait. let trait_method = cx .tcx - .associated_item(impl_item.owner_id) - .trait_item_def_id + .trait_item_of(impl_item.owner_id) .expect("impl method matches a trait method"); let trait_method_sig = cx.tcx.fn_sig(trait_method).instantiate_identity(); let trait_method_sig = cx.tcx.instantiate_bound_regions_with_erased(trait_method_sig); diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 70ae982a445..e45f884cfcb 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -98,7 +98,7 @@ fn into_iter_bound<'tcx>( if tr.def_id() == into_iter_did { into_iter_span = Some(*span); } else { - let tr = cx.tcx.erase_regions(tr); + let tr = cx.tcx.erase_and_anonymize_regions(tr); if tr.has_escaping_bound_vars() { return None; } diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index c4a759e919b..1a25c90d735 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -19,7 +19,7 @@ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, + ImplItem, ImplItemImplKind, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; @@ -280,16 +280,17 @@ fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) { } fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { - let (start_pat, end_pat) = match &item.kind { + let (mut start_pat, end_pat) = match &item.kind { ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), ImplItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")), ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), }; - if item.vis_span.is_empty() { - (start_pat, end_pat) - } else { - (Pat::Str("pub"), end_pat) - } + if let ImplItemImplKind::Inherent { vis_span, .. } = item.impl_kind + && !vis_span.is_empty() + { + start_pat = Pat::Str("pub"); + }; + (start_pat, end_pat) } fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { @@ -313,21 +314,20 @@ fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { } fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) { - let (start_pat, end_pat) = match kind { + let (mut start_pat, end_pat) = match kind { FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")), FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, body.value).1), }; - let start_pat = match tcx.hir_node(hir_id) { - Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => { - if vis_span.is_empty() { - start_pat - } else { - Pat::Str("pub") + match tcx.hir_node(hir_id) { + Node::Item(Item { vis_span, .. }) + | Node::ImplItem(ImplItem { impl_kind: ImplItemImplKind::Inherent { vis_span, .. }, .. }) => { + if !vis_span.is_empty() { + start_pat = Pat::Str("pub") } }, - Node::TraitItem(_) => start_pat, - _ => Pat::Str(""), + Node::ImplItem(_) | Node::TraitItem(_) => {}, + _ => start_pat = Pat::Str(""), }; (start_pat, end_pat) } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 14b64eb4d54..120ab2e717d 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2133,17 +2133,11 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { } pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { - cx.tcx - .hir_attrs(hir::CRATE_HIR_ID) - .iter() - .any(|attr| attr.has_name(sym::no_std)) + find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoStd(..)) } pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { - cx.tcx - .hir_attrs(hir::CRATE_HIR_ID) - .iter() - .any(|attr| attr.has_name(sym::no_core)) + find_attr!(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), AttributeKind::NoCore(..)) } /// Check if parent of a hir node is a trait implementation block. @@ -3250,8 +3244,8 @@ pub fn get_path_from_caller_to_method_type<'tcx>( let assoc_item = tcx.associated_item(method); let def_id = assoc_item.container_id(tcx); match assoc_item.container { - rustc_ty::AssocItemContainer::Trait => get_path_to_callee(tcx, from, def_id), - rustc_ty::AssocItemContainer::Impl => { + rustc_ty::AssocContainer::Trait => get_path_to_callee(tcx, from, def_id), + rustc_ty::AssocContainer::InherentImpl | rustc_ty::AssocContainer::TraitImpl(_) => { let ty = tcx.type_of(def_id).instantiate_identity(); get_path_to_ty(tcx, from, ty, args) }, diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 278101ac27f..8033b74a8d2 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -194,7 +194,6 @@ generate! { itertools, join, kw, - last, lazy_static, lint_vec, ln, diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 8e302f9d2ad..9f77a1c4d9b 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -285,7 +285,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( let _ = tcx.hir_body_owner_kind(callee_id); } - let ty = tcx.erase_regions(ty); + let ty = tcx.erase_and_anonymize_regions(ty); if ty.has_escaping_bound_vars() { return false; } diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs index 63c6342a323..8bb4f0e5d97 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.rs +++ b/src/tools/clippy/tests/ui/const_is_empty.rs @@ -196,7 +196,6 @@ fn issue_13106() { const { assert!(EMPTY_STR.is_empty()); - //~^ const_is_empty } const { diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr index 9a42518698e..2ba189058e8 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.stderr +++ b/src/tools/clippy/tests/ui/const_is_empty.stderr @@ -158,16 +158,10 @@ LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:198:17 - | -LL | assert!(EMPTY_STR.is_empty()); - | ^^^^^^^^^^^^^^^^^^^^ - -error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:203:9 + --> tests/ui/const_is_empty.rs:202:9 | LL | EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 28 previous errors +error: aborting due to 27 previous errors diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs index 882f909e30c..f7f21e1850d 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.rs +++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs @@ -1,6 +1,6 @@ #![warn(clippy::incompatible_msrv)] #![feature(custom_inner_attributes)] -#![allow(stable_features, clippy::diverging_sub_expression)] +#![allow(stable_features)] #![feature(strict_provenance)] // For use in test #![clippy::msrv = "1.3.0"] diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 857953072c4..1277fd225eb 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -1446,6 +1446,7 @@ pub(crate) fn make_test_description<R: Read>( cache: &DirectivesCache, name: String, path: &Utf8Path, + filterable_path: &Utf8Path, src: R, test_revision: Option<&str>, poisoned: &mut bool, @@ -1520,7 +1521,13 @@ pub(crate) fn make_test_description<R: Read>( _ => ShouldPanic::No, }; - CollectedTestDesc { name, ignore, ignore_message, should_panic } + CollectedTestDesc { + name, + filterable_path: filterable_path.to_owned(), + ignore, + ignore_message, + should_panic, + } } fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 33a02eb29fd..16cf76be9a5 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -14,6 +14,7 @@ fn make_test_description<R: Read>( config: &Config, name: String, path: &Utf8Path, + filterable_path: &Utf8Path, src: R, revision: Option<&str>, ) -> CollectedTestDesc { @@ -24,6 +25,7 @@ fn make_test_description<R: Read>( &cache, name, path, + filterable_path, src, revision, &mut poisoned, @@ -221,7 +223,7 @@ fn parse_rs(config: &Config, contents: &str) -> EarlyProps { fn check_ignore(config: &Config, contents: &str) -> bool { let tn = String::new(); let p = Utf8Path::new("a.rs"); - let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None); + let d = make_test_description(&config, tn, p, p, std::io::Cursor::new(contents), None); d.ignore } @@ -231,9 +233,9 @@ fn should_fail() { let tn = String::new(); let p = Utf8Path::new("a.rs"); - let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None); + let d = make_test_description(&config, tn.clone(), p, p, std::io::Cursor::new(""), None); assert_eq!(d.should_panic, ShouldPanic::No); - let d = make_test_description(&config, tn, p, std::io::Cursor::new("//@ should-fail"), None); + let d = make_test_description(&config, tn, p, p, std::io::Cursor::new("//@ should-fail"), None); assert_eq!(d.should_panic, ShouldPanic::Yes); } diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index b0dc24798b6..37cc17351d5 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -12,6 +12,8 @@ use std::num::NonZero; use std::sync::{Arc, Mutex, mpsc}; use std::{env, hint, io, mem, panic, thread}; +use camino::Utf8PathBuf; + use crate::common::{Config, TestPaths}; use crate::output_capture::{self, ConsoleOut}; use crate::panic_hook; @@ -293,8 +295,12 @@ fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> let mut filtered = tests; let matches_filter = |test: &CollectedTest, filter_str: &str| { - let test_name = &test.desc.name; - if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) } + let filterable_path = test.desc.filterable_path.as_str(); + if opts.filter_exact { + filterable_path == filter_str + } else { + filterable_path.contains(filter_str) + } }; // Remove tests that don't match the test filter @@ -339,6 +345,7 @@ pub(crate) struct CollectedTest { /// Information that was historically needed to create a libtest `TestDesc`. pub(crate) struct CollectedTestDesc { pub(crate) name: String, + pub(crate) filterable_path: Utf8PathBuf, pub(crate) ignore: bool, pub(crate) ignore_message: Option<Cow<'static, str>>, pub(crate) should_panic: ShouldPanic, diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index f647f96a9bf..5e349a20ed2 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -317,11 +317,17 @@ pub fn parse_config(args: Vec<String>) -> Config { .free .iter() .map(|f| { + // Here `f` is relative to `./tests/run-make`. So if you run + // + // ./x test tests/run-make/crate-loading + // + // then `f` is "crate-loading". let path = Utf8Path::new(f); let mut iter = path.iter().skip(1); - // We skip the test folder and check if the user passed `rmake.rs`. if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() { + // Strip the "rmake.rs" suffix. For example, if `f` is + // "crate-loading/rmake.rs" then this gives us "crate-loading". path.parent().unwrap().to_string() } else { f.to_string() @@ -329,6 +335,12 @@ pub fn parse_config(args: Vec<String>) -> Config { }) .collect::<Vec<_>>() } else { + // Note that the filters are relative to the root dir of the different test + // suites. For example, with: + // + // ./x test tests/ui/lint/unused + // + // the filter is "lint/unused". matches.free.clone() }; let compare_mode = matches.opt_str("compare-mode").map(|s| { @@ -911,7 +923,8 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te collector.tests.extend(revisions.into_iter().map(|revision| { // Create a test name and description to hand over to the executor. let src_file = fs::File::open(&test_path).expect("open test file to parse ignores"); - let test_name = make_test_name(&cx.config, testpaths, revision); + let (test_name, filterable_path) = + make_test_name_and_filterable_path(&cx.config, testpaths, revision); // Create a description struct for the test/revision. // This is where `ignore-*`/`only-*`/`needs-*` directives are handled, // because they historically needed to set the libtest ignored flag. @@ -920,6 +933,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te &cx.cache, test_name, &test_path, + &filterable_path, src_file, revision, &mut collector.poisoned, @@ -1072,7 +1086,11 @@ impl Stamp { } /// Creates a name for this test/revision that can be handed over to the executor. -fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> String { +fn make_test_name_and_filterable_path( + config: &Config, + testpaths: &TestPaths, + revision: Option<&str>, +) -> (String, Utf8PathBuf) { // Print the name of the file, relative to the sources root. let path = testpaths.file.strip_prefix(&config.src_root).unwrap(); let debugger = match config.debugger { @@ -1084,14 +1102,23 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str> None => String::new(), }; - format!( + let name = format!( "[{}{}{}] {}{}", config.mode, debugger, mode_suffix, path, revision.map_or("".to_string(), |rev| format!("#{}", rev)) - ) + ); + + // `path` is the full path from the repo root like, `tests/ui/foo/bar.rs`. + // Filtering is applied without the `tests/ui/` part, so strip that off. + // First strip off "tests" to make sure we don't have some unexpected path. + let mut filterable_path = path.strip_prefix("tests").unwrap().to_owned(); + // Now strip off e.g. "ui" or "run-make" component. + filterable_path = filterable_path.components().skip(1).collect(); + + (name, filterable_path) } /// Checks that test discovery didn't find any tests whose name stem is a prefix diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index fb5bff3fe63..f0886e31b24 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -10,3 +10,4 @@ path = "main.rs" [dependencies] regex = "1" html5ever = "0.29.0" +urlencoding = "2.1.3" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 1dc45728c90..e07a0784cdb 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -232,18 +232,7 @@ enum FileEntry { type Cache = HashMap<String, FileEntry>; fn small_url_encode(s: &str) -> String { - s.replace('<', "%3C") - .replace('>', "%3E") - .replace(' ', "%20") - .replace('?', "%3F") - .replace('\'', "%27") - .replace('&', "%26") - .replace(',', "%2C") - .replace(':', "%3A") - .replace(';', "%3B") - .replace('[', "%5B") - .replace(']', "%5D") - .replace('\"', "%22") + urlencoding::encode(s).to_string() } impl Checker { diff --git a/src/tools/linkchecker/tests/valid/inner/bar.html b/src/tools/linkchecker/tests/valid/inner/bar.html index 4b500d78b76..6ffda259c40 100644 --- a/src/tools/linkchecker/tests/valid/inner/bar.html +++ b/src/tools/linkchecker/tests/valid/inner/bar.html @@ -3,5 +3,8 @@ <h2 id="barfrag">Bar</h2> + <!-- testing urlecoded anchor link against a non-urlencoded heading IDs --> + <h2 id="barfrag-è">Bar</h2> + </body> </html> diff --git a/src/tools/linkchecker/tests/valid/inner/foo.html b/src/tools/linkchecker/tests/valid/inner/foo.html index 3c6a7483bcd..f30bf718205 100644 --- a/src/tools/linkchecker/tests/valid/inner/foo.html +++ b/src/tools/linkchecker/tests/valid/inner/foo.html @@ -8,7 +8,15 @@ <a href="https://example.com/doesnotexist">external links not validated</a> <a href="redir.html#redirfrag">Redirect</a> + <!-- testing urlecoded anchor link against a non-urlencoded heading IDs --> + <a href="#localfrag-%C3%A8"></a> + <a href="bar.html#barfrag-%C3%A8"></a> + <a href="redir.html#redirfrag-%C3%A8"></a> + <h2 id="localfrag">Local</h2> + <!-- testing urlecoded anchor link against a non-urlencoded heading IDs --> + <h2 id="localfrag-è">Local</h2> + </body> </html> diff --git a/src/tools/linkchecker/tests/valid/inner/redir-target.html b/src/tools/linkchecker/tests/valid/inner/redir-target.html index bd59884a01e..ac1dec6d5b4 100644 --- a/src/tools/linkchecker/tests/valid/inner/redir-target.html +++ b/src/tools/linkchecker/tests/valid/inner/redir-target.html @@ -1,5 +1,8 @@ <html> <body> <h2 id="redirfrag">Redir</h2> + + <!-- testing urlecoded anchor link against a non-urlencoded heading IDs --> + <h2 id="redirfrag-è">Redir</h2> </body> </html> diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 517aa343a6d..d433ee8daaa 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -606,6 +606,7 @@ Definite bugs found: * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo) * [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite) * [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248) +* [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr index bcec5557a3f..c7c1a769cda 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr @@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _ = note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr index 51533cd17a8..ae8b2b936a7 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr @@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr index 63fc7ce346e..dfa9a6e2583 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr @@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr index d8a3e058da9..47a0ebdcfef 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: trying to join a detached thread - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here @@ -7,7 +7,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr index 079f01c0e54..3b1181c92fd 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr @@ -9,13 +9,13 @@ LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJ = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr index 70de94f56ba..6eefa2da1d8 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr @@ -8,13 +8,13 @@ LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0 = note: inside closure at tests/fail-dep/concurrency/windows_join_self.rs:LL:CC error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr index 4f3a56fef82..6dd6c36ab65 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr @@ -1,11 +1,11 @@ error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr index 5045badaa87..3154197b95e 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr @@ -1,11 +1,11 @@ error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr index 3713c8da392..1af44c107ff 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr @@ -5,13 +5,13 @@ error: the evaluated program deadlocked = note: BACKTRACE on thread `unnamed-ID`: error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr index 47fc889b001..b85470225c6 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr @@ -1,11 +1,11 @@ error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr index 99d242ec7da..bbd2ab1c4d8 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr @@ -1,11 +1,11 @@ error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr index f766500d331..c3cc2068173 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr @@ -1,11 +1,11 @@ error: the evaluated program deadlocked - --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC | LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; | ^ this thread got stuck here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC note: inside `main` diff --git a/src/tools/miri/tests/pass/btreemap.rs b/src/tools/miri/tests/pass/btreemap.rs index 1d65e69bf72..7af6d7b5551 100644 --- a/src/tools/miri/tests/pass/btreemap.rs +++ b/src/tools/miri/tests/pass/btreemap.rs @@ -1,7 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance -#![feature(btree_extract_if)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/src/tools/miri/tests/pass/static_align.rs b/src/tools/miri/tests/pass/static_align.rs new file mode 100644 index 00000000000..f292f028568 --- /dev/null +++ b/src/tools/miri/tests/pass/static_align.rs @@ -0,0 +1,14 @@ +#![feature(static_align)] + +// When a static uses `align(N)`, its address should be a multiple of `N`. + +#[rustc_align_static(256)] +static FOO: u64 = 0; + +#[rustc_align_static(512)] +static BAR: u64 = 0; + +fn main() { + assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256)); + assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512)); +} diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 2ec8769c45f..63c6c8c99d0 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use rustc_ast::{ast, attr}; use rustc_errors::Diag; +use rustc_parse::lexer::StripTokens; use rustc_parse::parser::Parser as RawParser; use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_span::{Span, sym}; @@ -64,11 +65,14 @@ impl<'a> ParserBuilder<'a> { input: Input, ) -> Result<RawParser<'a>, Vec<Diag<'a>>> { match input { - Input::File(ref file) => new_parser_from_file(psess, file, None), + Input::File(ref file) => { + new_parser_from_file(psess, file, StripTokens::ShebangAndFrontmatter, None) + } Input::Text(text) => new_parser_from_source_str( psess, rustc_span::FileName::Custom("stdin".to_owned()), text, + StripTokens::ShebangAndFrontmatter, ), } } @@ -104,8 +108,12 @@ impl<'a> Parser<'a> { span: Span, ) -> Result<(ast::AttrVec, ThinVec<Box<ast::Item>>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { - let mut parser = - unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span))); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file( + psess.inner(), + path, + StripTokens::ShebangAndFrontmatter, + Some(span), + )); match parser.parse_mod(exp!(Eof)) { Ok((a, i, spans)) => Some((a, i, spans.inner_span)), Err(e) => { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index fee48bea144..568ec0c1198 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -48,40 +48,116 @@ const LICENSES: &[&str] = &[ type ExceptionList = &'static [(&'static str, &'static str)]; +#[derive(Clone, Copy)] +pub(crate) struct WorkspaceInfo<'a> { + /// Path to the directory containing the workspace root Cargo.toml file. + pub(crate) path: &'a str, + /// The list of license exceptions. + pub(crate) exceptions: ExceptionList, + /// Optionally: + /// * A list of crates for which dependencies need to be explicitly allowed. + /// * The list of allowed dependencies. + /// * The source code location of the allowed dependencies list + crates_and_deps: Option<(&'a [&'a str], &'a [&'a str], ListLocation)>, + /// Submodules required for the workspace + pub(crate) submodules: &'a [&'a str], +} + /// The workspaces to check for licensing and optionally permitted dependencies. -/// -/// Each entry consists of a tuple with the following elements: -/// -/// * The path to the workspace root Cargo.toml file. -/// * The list of license exceptions. -/// * Optionally a tuple of: -/// * A list of crates for which dependencies need to be explicitly allowed. -/// * The list of allowed dependencies. -/// * Submodules required for the workspace. // FIXME auto detect all cargo workspaces -pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>, &[&str])] = &[ +pub(crate) const WORKSPACES: &[WorkspaceInfo<'static>] = &[ // The root workspace has to be first for check_rustfix to work. - (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES)), &[]), - ("library", EXCEPTIONS_STDLIB, Some((&["sysroot"], PERMITTED_STDLIB_DEPENDENCIES)), &[]), - // Outside of the alphabetical section because rustfmt formats it using multiple lines. - ( - "compiler/rustc_codegen_cranelift", - EXCEPTIONS_CRANELIFT, - Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)), - &[], - ), - // tidy-alphabetical-start - ("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None, &[]), - ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None, &[]), - ("src/tools/cargo", EXCEPTIONS_CARGO, None, &["src/tools/cargo"]), - //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored - //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored - ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None, &[]), - ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None, &["src/doc/book", "src/doc/reference"]), - ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None, &["src/tools/rustc-perf"]), - ("src/tools/test-float-parse", EXCEPTIONS, None, &[]), - ("tests/run-make-cargo/uefi-qemu/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None, &[]), - // tidy-alphabetical-end + WorkspaceInfo { + path: ".", + exceptions: EXCEPTIONS, + crates_and_deps: Some(( + &["rustc-main"], + PERMITTED_RUSTC_DEPENDENCIES, + PERMITTED_RUSTC_DEPS_LOCATION, + )), + submodules: &[], + }, + WorkspaceInfo { + path: "library", + exceptions: EXCEPTIONS_STDLIB, + crates_and_deps: Some(( + &["sysroot"], + PERMITTED_STDLIB_DEPENDENCIES, + PERMITTED_STDLIB_DEPS_LOCATION, + )), + submodules: &[], + }, + { + WorkspaceInfo { + path: "compiler/rustc_codegen_cranelift", + exceptions: EXCEPTIONS_CRANELIFT, + crates_and_deps: Some(( + &["rustc_codegen_cranelift"], + PERMITTED_CRANELIFT_DEPENDENCIES, + PERMITTED_CRANELIFT_DEPS_LOCATION, + )), + submodules: &[], + } + }, + WorkspaceInfo { + path: "compiler/rustc_codegen_gcc", + exceptions: EXCEPTIONS_GCC, + crates_and_deps: None, + submodules: &[], + }, + WorkspaceInfo { + path: "src/bootstrap", + exceptions: EXCEPTIONS_BOOTSTRAP, + crates_and_deps: None, + submodules: &[], + }, + WorkspaceInfo { + path: "src/tools/cargo", + exceptions: EXCEPTIONS_CARGO, + crates_and_deps: None, + submodules: &["src/tools/cargo"], + }, + // FIXME uncomment once all deps are vendored + // WorkspaceInfo { + // path: "src/tools/miri/test-cargo-miri", + // crates_and_deps: None + // submodules: &[], + // }, + // WorkspaceInfo { + // path: "src/tools/miri/test_dependencies", + // crates_and_deps: None, + // submodules: &[], + // } + WorkspaceInfo { + path: "src/tools/rust-analyzer", + exceptions: EXCEPTIONS_RUST_ANALYZER, + crates_and_deps: None, + submodules: &[], + }, + WorkspaceInfo { + path: "src/tools/rustbook", + exceptions: EXCEPTIONS_RUSTBOOK, + crates_and_deps: None, + submodules: &["src/doc/book", "src/doc/reference"], + }, + WorkspaceInfo { + path: "src/tools/rustc-perf", + exceptions: EXCEPTIONS_RUSTC_PERF, + crates_and_deps: None, + submodules: &["src/tools/rustc-perf"], + }, + WorkspaceInfo { + path: "src/tools/test-float-parse", + exceptions: EXCEPTIONS, + crates_and_deps: None, + submodules: &[], + }, + WorkspaceInfo { + path: "tests/run-make-cargo/uefi-qemu/uefi_qemu_test", + exceptions: EXCEPTIONS_UEFI_QEMU_TEST, + crates_and_deps: None, + submodules: &[], + }, ]; /// These are exceptions to Rust's permissive licensing policy, and @@ -226,7 +302,20 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[ ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptable, but we use it under MIT OR Apache-2.0 ]; -const PERMITTED_DEPS_LOCATION: &str = concat!(file!(), ":", line!()); +#[derive(Clone, Copy)] +struct ListLocation { + path: &'static str, + line: u32, +} + +/// Creates a [`ListLocation`] for the current location (with an additional offset to the actual list start); +macro_rules! location { + (+ $offset:literal) => { + ListLocation { path: file!(), line: line!() + $offset } + }; +} + +const PERMITTED_RUSTC_DEPS_LOCATION: ListLocation = location!(+6); /// Crates rustc is allowed to depend on. Avoid adding to the list if possible. /// @@ -267,6 +356,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "digest", "displaydoc", "dissimilar", + "dyn-clone", "either", "elsa", "ena", @@ -346,6 +436,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rand_xorshift", // dependency for doc-tests in rustc_thread_pool "rand_xoshiro", "redox_syscall", + "ref-cast", + "ref-cast-impl", "regex", "regex-automata", "regex-syntax", @@ -357,11 +449,14 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustix", "ruzstd", // via object in thorin-dwp "ryu", + "schemars", + "schemars_derive", "scoped-tls", "scopeguard", "self_cell", "serde", "serde_derive", + "serde_derive_internals", "serde_json", "serde_path_to_error", "sha1", @@ -452,6 +547,8 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-end ]; +const PERMITTED_STDLIB_DEPS_LOCATION: ListLocation = location!(+2); + const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "addr2line", @@ -477,7 +574,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-literal-escaper", "shlex", - "unicode-width", "unwinding", "wasi", "windows-sys", @@ -494,6 +590,8 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-end ]; +const PERMITTED_CRANELIFT_DEPS_LOCATION: ListLocation = location!(+2); + const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "allocator-api2", @@ -568,29 +666,30 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) { check_proc_macro_dep_list(root, cargo, bless, bad); - for &(workspace, exceptions, permitted_deps, submodules) in WORKSPACES { + for &WorkspaceInfo { path, exceptions, crates_and_deps, submodules } in WORKSPACES { if has_missing_submodule(root, submodules) { continue; } - if !root.join(workspace).join("Cargo.lock").exists() { - tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock"); + if !root.join(path).join("Cargo.lock").exists() { + tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock"); continue; } let mut cmd = cargo_metadata::MetadataCommand::new(); cmd.cargo_path(cargo) - .manifest_path(root.join(workspace).join("Cargo.toml")) + .manifest_path(root.join(path).join("Cargo.toml")) .features(cargo_metadata::CargoOpt::AllFeatures) .other_options(vec!["--locked".to_owned()]); let metadata = t!(cmd.exec()); - check_license_exceptions(&metadata, workspace, exceptions, bad); - if let Some((crates, permitted_deps)) = permitted_deps { - check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad); + check_license_exceptions(&metadata, path, exceptions, bad); + if let Some((crates, permitted_deps, location)) = crates_and_deps { + let descr = crates.get(0).unwrap_or(&path); + check_permitted_dependencies(&metadata, descr, permitted_deps, crates, location, bad); } - if workspace == "library" { + if path == "library" { check_runtime_license_exceptions(&metadata, bad); check_runtime_no_duplicate_dependencies(&metadata, bad); check_runtime_no_proc_macros(&metadata, bad); @@ -835,6 +934,7 @@ fn check_permitted_dependencies( descr: &str, permitted_dependencies: &[&'static str], restricted_dependency_crates: &[&'static str], + permitted_location: ListLocation, bad: &mut bool, ) { let mut has_permitted_dep_error = false; @@ -895,7 +995,7 @@ fn check_permitted_dependencies( } if has_permitted_dep_error { - eprintln!("Go to `{PERMITTED_DEPS_LOCATION}` for the list."); + eprintln!("Go to `{}:{}` for the list.", permitted_location.path, permitted_location.line); } } diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index bc217a55cc1..2b212cfa67a 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -3,6 +3,8 @@ use std::fs; use std::path::Path; +use crate::deps::WorkspaceInfo; + /// List of allowed sources for packages. const ALLOWED_SOURCES: &[&str] = &[ r#""registry+https://github.com/rust-lang/crates.io-index""#, @@ -13,22 +15,22 @@ const ALLOWED_SOURCES: &[&str] = &[ /// Checks for external package sources. `root` is the path to the directory that contains the /// workspace `Cargo.toml`. pub fn check(root: &Path, bad: &mut bool) { - for &(workspace, _, _, submodules) in crate::deps::WORKSPACES { + for &WorkspaceInfo { path, submodules, .. } in crate::deps::WORKSPACES { if crate::deps::has_missing_submodule(root, submodules) { continue; } // FIXME check other workspaces too // `Cargo.lock` of rust. - let path = root.join(workspace).join("Cargo.lock"); + let lockfile = root.join(path).join("Cargo.lock"); - if !path.exists() { - tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock"); + if !lockfile.exists() { + tidy_error!(bad, "the `{path}` workspace doesn't have a Cargo.lock"); continue; } // Open and read the whole file. - let cargo_lock = t!(fs::read_to_string(&path)); + let cargo_lock = t!(fs::read_to_string(&lockfile)); // Process each line. for line in cargo_lock.lines() { diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs index 321ef65117e..a6b50b5ca47 100644 --- a/src/tools/tidy/src/extra_checks/mod.rs +++ b/src/tools/tidy/src/extra_checks/mod.rs @@ -124,6 +124,12 @@ fn check_impl( }; } + let rerun_with_bless = |mode: &str, action: &str| { + if !bless { + eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}"); + } + }; + let python_lint = extra_check!(Py, Lint); let python_fmt = extra_check!(Py, Fmt); let shell_lint = extra_check!(Shell, Lint); @@ -147,14 +153,21 @@ fn check_impl( } if python_lint { - eprintln!("linting python files"); let py_path = py_path.as_ref().unwrap(); - let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &["check".as_ref()]); + let args: &[&OsStr] = if bless { + eprintln!("linting python files and applying suggestions"); + &["check".as_ref(), "--fix".as_ref()] + } else { + eprintln!("linting python files"); + &["check".as_ref()] + }; + + let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args); - if res.is_err() && show_diff { + if res.is_err() && show_diff && !bless { eprintln!("\npython linting failed! Printing diff suggestions:"); - let _ = run_ruff( + let diff_res = run_ruff( root_path, outdir, py_path, @@ -162,6 +175,10 @@ fn check_impl( &file_args, &["check".as_ref(), "--diff".as_ref()], ); + // `ruff check --diff` will return status 0 if there are no suggestions. + if diff_res.is_err() { + rerun_with_bless("py:lint", "apply ruff suggestions"); + } } // Rethrow error res?; @@ -192,7 +209,7 @@ fn check_impl( &["format".as_ref(), "--diff".as_ref()], ); } - eprintln!("rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code"); + rerun_with_bless("py:fmt", "reformat Python code"); } // Rethrow error @@ -225,7 +242,7 @@ fn check_impl( let args = merge_args(&cfg_args_clang_format, &file_args_clang_format); let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args); - if res.is_err() && show_diff { + if res.is_err() && show_diff && !bless { eprintln!("\nclang-format linting failed! Printing diff suggestions:"); let mut cfg_args_clang_format_diff = cfg_args.clone(); @@ -265,6 +282,7 @@ fn check_impl( ); } } + rerun_with_bless("cpp:fmt", "reformat C++ code"); } // Rethrow error res?; @@ -290,12 +308,16 @@ fn check_impl( args.extend_from_slice(SPELLCHECK_DIRS); if bless { - eprintln!("spellcheck files and fix"); + eprintln!("spellchecking files and fixing typos"); args.push("--write-changes"); } else { - eprintln!("spellcheck files"); + eprintln!("spellchecking files"); } - spellcheck_runner(root_path, &outdir, &cargo, &args)?; + let res = spellcheck_runner(root_path, &outdir, &cargo, &args); + if res.is_err() { + rerun_with_bless("spellcheck", "fix typos"); + } + res?; } if js_lint || js_typecheck { @@ -303,11 +325,21 @@ fn check_impl( } if js_lint { - rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless)?; + if bless { + eprintln!("linting javascript files"); + } else { + eprintln!("linting javascript files and applying suggestions"); + } + let res = rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless); + if res.is_err() { + rerun_with_bless("js:lint", "apply eslint suggestions"); + } + res?; rustdoc_js::es_check(outdir, librustdoc_path)?; } if js_typecheck { + eprintln!("typechecking javascript files"); rustdoc_js::typecheck(outdir, librustdoc_path)?; } diff --git a/src/tools/tidy/src/extra_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs index a6c66b8be80..5137e618367 100644 --- a/src/tools/tidy/src/extra_checks/rustdoc_js.rs +++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs @@ -57,7 +57,7 @@ fn run_eslint( if exit_status.success() { return Ok(()); } - Err(super::Error::FailedCheck("eslint command failed")) + Err(super::Error::FailedCheck("eslint")) } Err(error) => Err(super::Error::Generic(format!("eslint command failed: {error:?}"))), } @@ -94,7 +94,7 @@ pub(super) fn typecheck(outdir: &Path, librustdoc_path: &Path) -> Result<(), sup if exit_status.success() { return Ok(()); } - Err(super::Error::FailedCheck("tsc command failed")) + Err(super::Error::FailedCheck("tsc")) } Err(error) => Err(super::Error::Generic(format!("tsc command failed: {error:?}"))), } @@ -112,7 +112,7 @@ pub(super) fn es_check(outdir: &Path, librustdoc_path: &Path) -> Result<(), supe if exit_status.success() { return Ok(()); } - Err(super::Error::FailedCheck("es-check command failed")) + Err(super::Error::FailedCheck("es-check")) } Err(error) => Err(super::Error::Generic(format!("es-check command failed: {error:?}"))), } diff --git a/src/tools/tidy/src/fluent_lowercase.rs b/src/tools/tidy/src/fluent_lowercase.rs new file mode 100644 index 00000000000..13f0319909e --- /dev/null +++ b/src/tools/tidy/src/fluent_lowercase.rs @@ -0,0 +1,64 @@ +//! Checks that the error messages start with a lowercased letter (except when allowed to). + +use std::path::Path; + +use fluent_syntax::ast::{Entry, Message, PatternElement}; + +use crate::walk::{filter_dirs, walk}; + +#[rustfmt::skip] +const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[ + // tidy-alphabetical-start + "ABI", + "ABIs", + "ADT", + "C", + "CGU", + "Ferris", + "MIR", + "OK", + "Rust", + "VS", // VS Code + // tidy-alphabetical-end +]; + +fn filter_fluent(path: &Path) -> bool { + if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } +} + +fn is_allowed_capitalized_word(msg: &str) -> bool { + ALLOWED_CAPITALIZED_WORDS.iter().any(|word| { + msg.strip_prefix(word) + .map(|tail| tail.chars().next().map(|c| c == '-' || c.is_whitespace()).unwrap_or(true)) + .unwrap_or_default() + }) +} + +fn check_lowercase(filename: &str, contents: &str, bad: &mut bool) { + let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents); + + for entry in &parse.body { + if let Entry::Message(msg) = entry + && let Message { value: Some(pattern), .. } = msg + && let [first_pattern, ..] = &pattern.elements[..] + && let PatternElement::TextElement { value } = first_pattern + && value.chars().next().is_some_and(char::is_uppercase) + && !is_allowed_capitalized_word(value) + { + tidy_error!( + bad, + "{filename}: message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`" + ); + } + } +} + +pub fn check(path: &Path, bad: &mut bool) { + walk( + path, + |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), + &mut |ent, contents| { + check_lowercase(ent.path().to_str().unwrap(), contents, bad); + }, + ); +} diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index ee06707415f..849dcb9e88f 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2021,7 +2021,6 @@ ui/parser/issues/issue-5806.rs ui/parser/issues/issue-58094-missing-right-square-bracket.rs ui/parser/issues/issue-58856-1.rs ui/parser/issues/issue-58856-2.rs -ui/parser/issues/issue-59418.rs ui/parser/issues/issue-60075.rs ui/parser/issues/issue-61858.rs ui/parser/issues/issue-62524.rs diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 37713cbf75e..2a9c3963d2d 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -257,6 +257,7 @@ pub mod extra_checks; pub mod features; pub mod filenames; pub mod fluent_alphabetical; +pub mod fluent_lowercase; pub mod fluent_period; mod fluent_used; pub mod gcc_submodule; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index bfe30258915..f9e82341b7a 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -121,6 +121,7 @@ fn main() { check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info); check!(fluent_alphabetical, &compiler_path, bless); check!(fluent_period, &compiler_path); + check!(fluent_lowercase, &compiler_path); check!(target_policy, &root_path); check!(gcc_submodule, &root_path, &compiler_path); diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 23dc86998e8..3def2391a13 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.16" +wasm-component-ld = "0.5.17" diff --git a/src/version b/src/version index 6979a6c0661..7f229af9647 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.91.0 +1.92.0 diff --git a/tests/assembly-llvm/c-variadic-arm.rs b/tests/assembly-llvm/c-variadic-arm.rs new file mode 100644 index 00000000000..2ef307405e1 --- /dev/null +++ b/tests/assembly-llvm/c-variadic-arm.rs @@ -0,0 +1,26 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -Copt-level=3 +//@ only-arm +//@ ignore-thumb +//@ ignore-android +#![no_std] +#![crate_type = "lib"] +#![feature(c_variadic)] + +// Check that the assembly that rustc generates matches what clang emits. + +#[unsafe(no_mangle)] +unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { + // CHECK-LABEL: variadic + // CHECK: sub sp, sp + + // CHECK: vldr + // CHECK: vadd.f64 + // CHECK: vldr + // CHECK: vadd.f64 + let b = args.arg::<f64>(); + let c = args.arg::<f64>(); + a + b + c + + // CHECK: add sp, sp +} diff --git a/tests/codegen-llvm/align-static.rs b/tests/codegen-llvm/align-static.rs new file mode 100644 index 00000000000..53db998919a --- /dev/null +++ b/tests/codegen-llvm/align-static.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -C no-prepopulate-passes -Z mir-opt-level=0 + +#![crate_type = "lib"] +#![feature(static_align)] + +// CHECK: @STATIC_ALIGN = +// CHECK-SAME: align 16 +#[no_mangle] +#[rustc_align_static(16)] +pub static STATIC_ALIGN: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_1 = +// CHECK-SAME: align 64 +#[no_mangle] +#[rustc_align_static(32)] +#[rustc_align_static(64)] +pub static ALIGN_SPECIFIED_TWICE_1: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_2 = +// CHECK-SAME: align 128 +#[no_mangle] +#[rustc_align_static(128)] +#[rustc_align_static(32)] +pub static ALIGN_SPECIFIED_TWICE_2: u64 = 0; + +// CHECK: @ALIGN_SPECIFIED_TWICE_3 = +// CHECK-SAME: align 256 +#[no_mangle] +#[rustc_align_static(32)] +#[rustc_align_static(256)] +pub static ALIGN_SPECIFIED_TWICE_3: u64 = 0; diff --git a/tests/codegen-llvm/c-variadic-lifetime.rs b/tests/codegen-llvm/c-variadic-lifetime.rs new file mode 100644 index 00000000000..c6d3602ef51 --- /dev/null +++ b/tests/codegen-llvm/c-variadic-lifetime.rs @@ -0,0 +1,21 @@ +//@ add-core-stubs +//@ compile-flags: -Copt-level=3 +#![feature(c_variadic)] +#![crate_type = "lib"] + +// Check that `%args` explicitly has its lifetime start and end. Being explicit can improve +// instruction and register selection, see e.g. https://github.com/rust-lang/rust/pull/144549 + +#[unsafe(no_mangle)] +unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { + // CHECK: call void @llvm.lifetime.start.p0({{(i64 [0-9]+, )?}}ptr nonnull %args) + // CHECK: call void @llvm.va_start.p0(ptr nonnull %args) + + let b = args.arg::<f64>(); + let c = args.arg::<f64>(); + + a + b + c + + // CHECK: call void @llvm.va_end.p0(ptr nonnull %args) + // CHECK: call void @llvm.lifetime.end.p0({{(i64 [0-9]+, )?}}ptr nonnull %args) +} diff --git a/tests/codegen-llvm/cffi/c-variadic-inline.rs b/tests/codegen-llvm/cffi/c-variadic-inline.rs new file mode 100644 index 00000000000..369b7e571ca --- /dev/null +++ b/tests/codegen-llvm/cffi/c-variadic-inline.rs @@ -0,0 +1,47 @@ +//@ compile-flags: -C opt-level=3 +#![feature(c_variadic)] + +// Test that the inline attributes are accepted on C-variadic functions. +// +// Currently LLVM is unable to inline C-variadic functions, but that is valid because despite +// the name even `#[inline(always)]` is just a hint. + +#[inline(always)] +unsafe extern "C" fn inline_always(mut ap: ...) -> u32 { + ap.arg::<u32>() +} + +#[inline] +unsafe extern "C" fn inline(mut ap: ...) -> u32 { + ap.arg::<u32>() +} + +#[inline(never)] +unsafe extern "C" fn inline_never(mut ap: ...) -> u32 { + ap.arg::<u32>() +} + +#[cold] +unsafe extern "C" fn cold(mut ap: ...) -> u32 { + ap.arg::<u32>() +} + +#[unsafe(no_mangle)] +#[inline(never)] +fn helper() { + // CHECK-LABEL: helper + // CHECK-LABEL: call c_variadic_inline::inline_always + // CHECK-LABEL: call c_variadic_inline::inline + // CHECK-LABEL: call c_variadic_inline::inline_never + // CHECK-LABEL: call c_variadic_inline::cold + unsafe { + inline_always(1); + inline(2); + inline_never(3); + cold(4); + } +} + +fn main() { + helper() +} diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index 8afb6ad250e..a18d7e7478f 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,30 +1,30 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] +| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10] | 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] | 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send | 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] +| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10] | 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] | 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send | 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] +| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10] | 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty(General(U0))] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] | 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send diff --git a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir index 7be3ab8cbae..8e47aabb9b9 100644 --- a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir +++ b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-abort.mir @@ -1,4 +1,4 @@ -// MIR for `drop_in_place` after SimplifyCfg-make_shim +// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); diff --git a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir index 6c3c1aaa2bd..2457405d996 100644 --- a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir +++ b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir @@ -1,4 +1,4 @@ -// MIR for `drop_in_place` after SimplifyCfg-make_shim +// MIR for `std::ptr::drop_in_place` after SimplifyCfg-make_shim fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir index 9d5af8e84e4..ed3f4788cea 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String;42].AddMovesForPackedDrops.before.mir @@ -1,4 +1,4 @@ -// MIR for `drop_in_place` before AddMovesForPackedDrops +// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn drop_in_place(_1: *mut [String; 42]) -> () { let mut _0: (); diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir index 144880d1598..bee671af6df 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir @@ -1,4 +1,4 @@ -// MIR for `drop_in_place` before AddMovesForPackedDrops +// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); diff --git a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir index 51ef9f7c068..1bdb1c1debd 100644 --- a/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir @@ -1,4 +1,4 @@ -// MIR for `drop_in_place` before AddMovesForPackedDrops +// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops fn drop_in_place(_1: *mut Vec<i32>) -> () { let mut _0: (); diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff index 07eafca3271..044302a19a0 100644 --- a/tests/run-make/print-request-help-stable-unstable/help-diff.diff +++ b/tests/run-make/print-request-help-stable-unstable/help-diff.diff @@ -2,6 +2,6 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models` -+ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` ++ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err index 50ef340e3dd..cc6c3c909b3 100644 --- a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err +++ b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err @@ -1,5 +1,5 @@ error: unknown print request: `xxx` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index 3fc297fb08e..cd161c51ee3 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -43,7 +43,7 @@ Options: --print <INFO>[=<FILE>] Compiler information to print on stdout (or to a file) INFO may be one of - <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models>. + <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|target-spec-json-schema|tls-models>. -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o <FILENAME> Write output to FILENAME diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index caffe28f498..74ec083bdee 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -43,7 +43,7 @@ Options: --print <INFO>[=<FILE>] Compiler information to print on stdout (or to a file) INFO may be one of - <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models>. + <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|target-spec-json-schema|tls-models>. -g Equivalent to -C debuginfo=2 -O Equivalent to -C opt-level=3 -o <FILENAME> Write output to FILENAME diff --git a/tests/rustdoc-js/literal-path.js b/tests/rustdoc-js/literal-path.js new file mode 100644 index 00000000000..ea999ea1a6f --- /dev/null +++ b/tests/rustdoc-js/literal-path.js @@ -0,0 +1,23 @@ +// exact-check + +// This test ensures that literal search is always applied on elements of the path. + +const EXPECTED = [ + { + 'query': '"some::path"', + 'others': [ + { 'path': 'literal_path::some', 'name': 'Path' }, + ], + }, + { + 'query': '"somea::path"', + 'others': [ + { 'path': 'literal_path::somea', 'name': 'Path' }, + ], + }, + { + 'query': '"soma::path"', + 'others': [ + ], + }, +]; diff --git a/tests/rustdoc-js/literal-path.rs b/tests/rustdoc-js/literal-path.rs new file mode 100644 index 00000000000..fa7685fd966 --- /dev/null +++ b/tests/rustdoc-js/literal-path.rs @@ -0,0 +1,7 @@ +pub mod some { + pub struct Path; +} + +pub mod somea { + pub struct Path; +} diff --git a/tests/rustdoc-ui/lints/bare-urls.fixed b/tests/rustdoc-ui/lints/bare-urls.fixed index a91573146b8..ac63e291c5b 100644 --- a/tests/rustdoc-ui/lints/bare-urls.fixed +++ b/tests/rustdoc-ui/lints/bare-urls.fixed @@ -68,3 +68,17 @@ pub mod foo { /// https://somewhere.com/a?hello=12&bye=11#xyz pub fn bar() {} } + +/// <https://bloob.blob> +//~^ ERROR this URL is not a hyperlink +/// [ <https://bloob.blob> ] +//~^ ERROR this URL is not a hyperlink +/// [ <https://bloob.blob>] +//~^ ERROR this URL is not a hyperlink +/// [<https://bloob.blob> ] +//~^ ERROR this URL is not a hyperlink +/// [<https://bloob.blob> +//~^ ERROR this URL is not a hyperlink +/// <https://bloob.blob>] +//~^ ERROR this URL is not a hyperlink +pub fn lint_with_brackets() {} diff --git a/tests/rustdoc-ui/lints/bare-urls.rs b/tests/rustdoc-ui/lints/bare-urls.rs index 5b008cdafa2..a70a3ec822e 100644 --- a/tests/rustdoc-ui/lints/bare-urls.rs +++ b/tests/rustdoc-ui/lints/bare-urls.rs @@ -68,3 +68,17 @@ pub mod foo { /// https://somewhere.com/a?hello=12&bye=11#xyz pub fn bar() {} } + +/// [https://bloob.blob] +//~^ ERROR this URL is not a hyperlink +/// [ https://bloob.blob ] +//~^ ERROR this URL is not a hyperlink +/// [ https://bloob.blob] +//~^ ERROR this URL is not a hyperlink +/// [https://bloob.blob ] +//~^ ERROR this URL is not a hyperlink +/// [https://bloob.blob +//~^ ERROR this URL is not a hyperlink +/// https://bloob.blob] +//~^ ERROR this URL is not a hyperlink +pub fn lint_with_brackets() {} diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr index e1108c7e7f8..fc3c642f5aa 100644 --- a/tests/rustdoc-ui/lints/bare-urls.stderr +++ b/tests/rustdoc-ui/lints/bare-urls.stderr @@ -243,5 +243,73 @@ help: use an automatic link instead LL | #[doc = "<https://example.com/raw>"] | + + -error: aborting due to 20 previous errors +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:72:5 + | +LL | /// [https://bloob.blob] + | ^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://bloob.blob>` + | + = note: bare URLs are not automatically turned into clickable links + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:74:7 + | +LL | /// [ https://bloob.blob ] + | ^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// [ <https://bloob.blob> ] + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:76:7 + | +LL | /// [ https://bloob.blob] + | ^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// [ <https://bloob.blob>] + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:78:6 + | +LL | /// [https://bloob.blob ] + | ^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// [<https://bloob.blob> ] + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:80:6 + | +LL | /// [https://bloob.blob + | ^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// [<https://bloob.blob> + | + + + +error: this URL is not a hyperlink + --> $DIR/bare-urls.rs:82:5 + | +LL | /// https://bloob.blob] + | ^^^^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +help: use an automatic link instead + | +LL | /// <https://bloob.blob>] + | + + + +error: aborting due to 26 previous errors diff --git a/tests/ui-fulldeps/auxiliary/parser.rs b/tests/ui-fulldeps/auxiliary/parser.rs index 6726969350d..6ee39e5130f 100644 --- a/tests/ui-fulldeps/auxiliary/parser.rs +++ b/tests/ui-fulldeps/auxiliary/parser.rs @@ -10,7 +10,7 @@ extern crate rustc_span; use rustc_ast::ast::{AttrKind, Attribute, DUMMY_NODE_ID, Expr}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::node_id::NodeId; -use rustc_ast::token::{self, Token}; +use rustc_ast::token; use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, LazyAttrTokenStream}; use rustc_errors::Diag; use rustc_parse::parser::Recovery; @@ -23,6 +23,7 @@ pub fn parse_expr(psess: &ParseSess, source_code: &str) -> Option<Box<Expr>> { psess, FileName::anon_source_code(source_code), source_code.to_owned(), + rustc_parse::lexer::StripTokens::Nothing, )); let mut parser = parser.recovery(Recovery::Forbidden); diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index 99cb5fc5aa1..df5f29e35fe 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -16,7 +16,7 @@ extern crate rustc_span; #[allow(unused_extern_crates)] extern crate rustc_driver; -use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; +use rustc_parse::{lexer::StripTokens, new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use std::path::Path; @@ -34,6 +34,11 @@ fn parse() { let path = Path::new(file!()); let path = path.canonicalize().unwrap(); - let mut parser = unwrap_or_emit_fatal(new_parser_from_file(&psess, &path, None)); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file( + &psess, + &path, + StripTokens::ShebangAndFrontmatter, + None, + )); let _ = parser.parse_crate_mod(); } diff --git a/tests/ui/issues/issue-56806.rs b/tests/ui/abi/invalid-self-parameter-type-56806.rs index b1dac26d65a..60229df3005 100644 --- a/tests/ui/issues/issue-56806.rs +++ b/tests/ui/abi/invalid-self-parameter-type-56806.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56806 pub trait Trait { fn dyn_instead_of_self(self: Box<dyn Trait>); //~^ ERROR invalid `self` parameter type diff --git a/tests/ui/issues/issue-56806.stderr b/tests/ui/abi/invalid-self-parameter-type-56806.stderr index ec50d863758..ac249b8f108 100644 --- a/tests/ui/issues/issue-56806.stderr +++ b/tests/ui/abi/invalid-self-parameter-type-56806.stderr @@ -1,5 +1,5 @@ error[E0307]: invalid `self` parameter type: `Box<(dyn Trait + 'static)>` - --> $DIR/issue-56806.rs:2:34 + --> $DIR/invalid-self-parameter-type-56806.rs:3:34 | LL | fn dyn_instead_of_self(self: Box<dyn Trait>); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/simd-abi-checks-s390x.rs b/tests/ui/abi/simd-abi-checks-s390x.rs index 877a25e8b08..75232a66ab0 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.rs +++ b/tests/ui/abi/simd-abi-checks-s390x.rs @@ -8,6 +8,7 @@ // FIXME: +soft-float itself doesn't set -vector //@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float //@[z13_soft_float] needs-llvm-components: systemz +//[z13_soft_float]~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly #![feature(no_core, repr_simd, s390x_target_feature)] #![no_core] diff --git a/tests/ui/abi/simd-abi-checks-s390x.z10.stderr b/tests/ui/abi/simd-abi-checks-s390x.z10.stderr index c1c4e90f3cf..e1cfa373c63 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.z10.stderr +++ b/tests/ui/abi/simd-abi-checks-s390x.z10.stderr @@ -1,5 +1,5 @@ error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:38:1 + --> $DIR/simd-abi-checks-s390x.rs:39:1 | LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -7,7 +7,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:43:1 + --> $DIR/simd-abi-checks-s390x.rs:44:1 | LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -15,7 +15,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:89:1 + --> $DIR/simd-abi-checks-s390x.rs:90:1 | LL | / extern "C" fn vector_transparent_wrapper_ret_small( LL | | x: &TransparentWrapper<i8x8>, @@ -25,7 +25,7 @@ LL | | ) -> TransparentWrapper<i8x8> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:96:1 + --> $DIR/simd-abi-checks-s390x.rs:97:1 | LL | / extern "C" fn vector_transparent_wrapper_ret( LL | | x: &TransparentWrapper<i8x16>, @@ -35,7 +35,7 @@ LL | | ) -> TransparentWrapper<i8x16> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:111:1 + --> $DIR/simd-abi-checks-s390x.rs:112:1 | LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -43,7 +43,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:116:1 + --> $DIR/simd-abi-checks-s390x.rs:117:1 | LL | extern "C" fn vector_arg(x: i8x16) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -51,7 +51,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:127:1 + --> $DIR/simd-abi-checks-s390x.rs:128:1 | LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -59,7 +59,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:132:1 + --> $DIR/simd-abi-checks-s390x.rs:133:1 | LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -67,7 +67,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:143:1 + --> $DIR/simd-abi-checks-s390x.rs:144:1 | LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -75,7 +75,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8 = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:148:1 + --> $DIR/simd-abi-checks-s390x.rs:149:1 | LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here diff --git a/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr index c1c4e90f3cf..e1cfa373c63 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr +++ b/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr @@ -1,5 +1,5 @@ error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:38:1 + --> $DIR/simd-abi-checks-s390x.rs:39:1 | LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -7,7 +7,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:43:1 + --> $DIR/simd-abi-checks-s390x.rs:44:1 | LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -15,7 +15,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:89:1 + --> $DIR/simd-abi-checks-s390x.rs:90:1 | LL | / extern "C" fn vector_transparent_wrapper_ret_small( LL | | x: &TransparentWrapper<i8x8>, @@ -25,7 +25,7 @@ LL | | ) -> TransparentWrapper<i8x8> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:96:1 + --> $DIR/simd-abi-checks-s390x.rs:97:1 | LL | / extern "C" fn vector_transparent_wrapper_ret( LL | | x: &TransparentWrapper<i8x16>, @@ -35,7 +35,7 @@ LL | | ) -> TransparentWrapper<i8x16> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:111:1 + --> $DIR/simd-abi-checks-s390x.rs:112:1 | LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -43,7 +43,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:116:1 + --> $DIR/simd-abi-checks-s390x.rs:117:1 | LL | extern "C" fn vector_arg(x: i8x16) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -51,7 +51,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:127:1 + --> $DIR/simd-abi-checks-s390x.rs:128:1 | LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -59,7 +59,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:132:1 + --> $DIR/simd-abi-checks-s390x.rs:133:1 | LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -67,7 +67,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:143:1 + --> $DIR/simd-abi-checks-s390x.rs:144:1 | LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -75,7 +75,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8 = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:148:1 + --> $DIR/simd-abi-checks-s390x.rs:149:1 | LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here diff --git a/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr index c1c4e90f3cf..577fcc23bf1 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr +++ b/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr @@ -1,5 +1,10 @@ +warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:38:1 + --> $DIR/simd-abi-checks-s390x.rs:39:1 | LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -7,7 +12,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:43:1 + --> $DIR/simd-abi-checks-s390x.rs:44:1 | LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -15,7 +20,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:89:1 + --> $DIR/simd-abi-checks-s390x.rs:90:1 | LL | / extern "C" fn vector_transparent_wrapper_ret_small( LL | | x: &TransparentWrapper<i8x8>, @@ -25,7 +30,7 @@ LL | | ) -> TransparentWrapper<i8x8> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:96:1 + --> $DIR/simd-abi-checks-s390x.rs:97:1 | LL | / extern "C" fn vector_transparent_wrapper_ret( LL | | x: &TransparentWrapper<i8x16>, @@ -35,7 +40,7 @@ LL | | ) -> TransparentWrapper<i8x16> { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:111:1 + --> $DIR/simd-abi-checks-s390x.rs:112:1 | LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -43,7 +48,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:116:1 + --> $DIR/simd-abi-checks-s390x.rs:117:1 | LL | extern "C" fn vector_arg(x: i8x16) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -51,7 +56,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:127:1 + --> $DIR/simd-abi-checks-s390x.rs:128:1 | LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -59,7 +64,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:132:1 + --> $DIR/simd-abi-checks-s390x.rs:133:1 | LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -67,7 +72,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:143:1 + --> $DIR/simd-abi-checks-s390x.rs:144:1 | LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here @@ -75,12 +80,12 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8 = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled - --> $DIR/simd-abi-checks-s390x.rs:148:1 + --> $DIR/simd-abi-checks-s390x.rs:149:1 | LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here | = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`) -error: aborting due to 10 previous errors +error: aborting due to 10 previous errors; 1 warning emitted diff --git a/tests/ui/issues/issue-56870.rs b/tests/ui/associated-consts/traits-associated-consts-ice-56870.rs index fc6deedd029..0c5a2b84773 100644 --- a/tests/ui/issues/issue-56870.rs +++ b/tests/ui/associated-consts/traits-associated-consts-ice-56870.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56870 //@ build-pass // Regression test for #56870: Internal compiler error (traits & associated consts) diff --git a/tests/ui/issues/issue-59326.rs b/tests/ui/associated-types/duplicate-associated-type-resolution-59326.rs index e9634ad9fd8..0439e229e14 100644 --- a/tests/ui/issues/issue-59326.rs +++ b/tests/ui/associated-types/duplicate-associated-type-resolution-59326.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/59326 //@ check-pass trait Service { type S; diff --git a/tests/ui/issues/issue-57399-self-return-impl-trait.rs b/tests/ui/associated-types/impl-trait-member-type-resolution-57399.rs index bcf1b18a9ff..3342dd0631a 100644 --- a/tests/ui/issues/issue-57399-self-return-impl-trait.rs +++ b/tests/ui/associated-types/impl-trait-member-type-resolution-57399.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57399 //@ check-pass trait T { @@ -12,7 +13,6 @@ struct S<A> { a: A, } - impl From<u32> for S<<i32 as T>::T> { fn from(a: u32) -> Self { Self { a } diff --git a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs index ea67831b68e..a13a255d536 100644 --- a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs +++ b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.rs @@ -1,21 +1,22 @@ // Demonstrates and records a theoretical regressions / breaking changes caused by the // introduction of async trait bounds. -// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018. +// Setting the edition to >2015 since we didn't regress `demo! { dyn async }` in Rust 2015. //@ edition:2018 macro_rules! demo { - ($ty:ty) => { compile_error!("ty"); }; + ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! //~^ ERROR ty //~| ERROR ty - (impl $c:ident Trait) => {}; - (dyn $c:ident Trait) => {}; + + // DON'T MODIFY THE MATCHERS BELOW UNLESS THE ASYNC TRAIT MODIFIER SYNTAX CHANGES! + + (impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ }; + (dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ }; } -demo! { impl async Trait } -//~^ ERROR `async` trait bounds are unstable +demo! { impl async Trait } //~ ERROR `async` trait bounds are unstable -demo! { dyn async Trait } -//~^ ERROR `async` trait bounds are unstable +demo! { dyn async Trait } //~ ERROR `async` trait bounds are unstable fn main() {} diff --git a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr index 6c3044e64d2..0292c53fb1c 100644 --- a/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr +++ b/tests/ui/async-await/async-fn/macro-async-trait-bound-theoretical-regression.stderr @@ -1,7 +1,7 @@ error: ty --> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19 | -LL | ($ty:ty) => { compile_error!("ty"); }; +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! | ^^^^^^^^^^^^^^^^^^^^ ... LL | demo! { impl async Trait } @@ -12,7 +12,7 @@ LL | demo! { impl async Trait } error: ty --> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19 | -LL | ($ty:ty) => { compile_error!("ty"); }; +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! | ^^^^^^^^^^^^^^^^^^^^ ... LL | demo! { dyn async Trait } @@ -21,7 +21,7 @@ LL | demo! { dyn async Trait } = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: `async` trait bounds are unstable - --> $DIR/macro-async-trait-bound-theoretical-regression.rs:15:14 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:14 | LL | demo! { impl async Trait } | ^^^^^ @@ -32,7 +32,7 @@ LL | demo! { impl async Trait } = help: use the desugared name of the async trait, such as `AsyncFn` error[E0658]: `async` trait bounds are unstable - --> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:13 + --> $DIR/macro-async-trait-bound-theoretical-regression.rs:20:13 | LL | demo! { dyn async Trait } | ^^^^^ diff --git a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs index b5f59069f85..7113f591630 100644 --- a/tests/ui/async-await/future-sizes/async-awaiting-fut.rs +++ b/tests/ui/async-await/future-sizes/async-awaiting-fut.rs @@ -1,3 +1,5 @@ +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0 +//@ compile-flags: -C debuginfo=0 //@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib //@ needs-deterministic-layouts //@ edition:2021 diff --git a/tests/ui/async-await/future-sizes/large-arg.rs b/tests/ui/async-await/future-sizes/large-arg.rs index 809f7cf1f93..b05a2b71915 100644 --- a/tests/ui/async-await/future-sizes/large-arg.rs +++ b/tests/ui/async-await/future-sizes/large-arg.rs @@ -1,3 +1,5 @@ +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0 +//@ compile-flags: -C debuginfo=0 //@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type=lib //@ needs-deterministic-layouts //@ edition: 2021 diff --git a/tests/ui/attributes/malformed-no-std.rs b/tests/ui/attributes/malformed-no-std.rs new file mode 100644 index 00000000000..528ecb549b0 --- /dev/null +++ b/tests/ui/attributes/malformed-no-std.rs @@ -0,0 +1,25 @@ +#![feature(no_core)] +// these all still apply no_std and then later error +#![no_std = "foo"] +//~^ ERROR malformed `no_std` attribute input +#![no_std("bar")] +//~^ ERROR malformed `no_std` attribute input +#![no_std(foo = "bar")] +//~^ ERROR malformed `no_std` attribute input +#![no_core = "foo"] +//~^ ERROR malformed `no_core` attribute input +#![no_core("bar")] +//~^ ERROR malformed `no_core` attribute input +#![no_core(foo = "bar")] +//~^ ERROR malformed `no_core` attribute input + +#[deny(unused_attributes)] +#[no_std] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: +#[no_core] +//~^ ERROR crate-level attribute should be an inner attribute: add an exclamation mark: +// to fix compilation +extern crate core; +extern crate std; + +fn main() {} diff --git a/tests/ui/attributes/malformed-no-std.stderr b/tests/ui/attributes/malformed-no-std.stderr new file mode 100644 index 00000000000..322d5f03e41 --- /dev/null +++ b/tests/ui/attributes/malformed-no-std.stderr @@ -0,0 +1,86 @@ +error[E0565]: malformed `no_std` attribute input + --> $DIR/malformed-no-std.rs:3:1 + | +LL | #![no_std = "foo"] + | ^^^^^^^^^^-------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_std]` + +error[E0565]: malformed `no_std` attribute input + --> $DIR/malformed-no-std.rs:5:1 + | +LL | #![no_std("bar")] + | ^^^^^^^^^-------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_std]` + +error[E0565]: malformed `no_std` attribute input + --> $DIR/malformed-no-std.rs:7:1 + | +LL | #![no_std(foo = "bar")] + | ^^^^^^^^^-------------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_std]` + +error[E0565]: malformed `no_core` attribute input + --> $DIR/malformed-no-std.rs:9:1 + | +LL | #![no_core = "foo"] + | ^^^^^^^^^^^-------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_core]` + +error[E0565]: malformed `no_core` attribute input + --> $DIR/malformed-no-std.rs:11:1 + | +LL | #![no_core("bar")] + | ^^^^^^^^^^-------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_core]` + +error[E0565]: malformed `no_core` attribute input + --> $DIR/malformed-no-std.rs:13:1 + | +LL | #![no_core(foo = "bar")] + | ^^^^^^^^^^-------------^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![no_core]` + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/malformed-no-std.rs:17:1 + | +LL | #[no_std] + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this extern crate + --> $DIR/malformed-no-std.rs:22:1 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/malformed-no-std.rs:16:8 + | +LL | #[deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_core]` + --> $DIR/malformed-no-std.rs:19:1 + | +LL | #[no_core] + | ^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this extern crate + --> $DIR/malformed-no-std.rs:22:1 + | +LL | extern crate core; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0565`. diff --git a/tests/ui/attributes/malformed-static-align.rs b/tests/ui/attributes/malformed-static-align.rs new file mode 100644 index 00000000000..305d8acf8af --- /dev/null +++ b/tests/ui/attributes/malformed-static-align.rs @@ -0,0 +1,17 @@ +#![feature(static_align)] +#![crate_type = "lib"] + +#[rustc_align_static = 16] //~ ERROR malformed `rustc_align_static` attribute input +static S1: () = (); + +#[rustc_align_static("hello")] //~ ERROR invalid alignment value: not an unsuffixed integer +static S2: () = (); + +#[rustc_align_static(0)] //~ ERROR invalid alignment value: not a power of two +static S3: () = (); + +#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on static +static S4: () = (); + +#[rustc_align_static(16)] //~ ERROR `#[rustc_align_static]` attribute cannot be used on structs +struct Struct1; diff --git a/tests/ui/attributes/malformed-static-align.stderr b/tests/ui/attributes/malformed-static-align.stderr new file mode 100644 index 00000000000..35f654d3990 --- /dev/null +++ b/tests/ui/attributes/malformed-static-align.stderr @@ -0,0 +1,45 @@ +error[E0539]: malformed `rustc_align_static` attribute input + --> $DIR/malformed-static-align.rs:4:1 + | +LL | #[rustc_align_static = 16] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[rustc_align_static(<alignment in bytes>)]` + +error[E0589]: invalid alignment value: not an unsuffixed integer + --> $DIR/malformed-static-align.rs:7:22 + | +LL | #[rustc_align_static("hello")] + | ^^^^^^^ + +error[E0589]: invalid alignment value: not a power of two + --> $DIR/malformed-static-align.rs:10:22 + | +LL | #[rustc_align_static(0)] + | ^ + +error: `#[rustc_align_static]` attribute cannot be used on structs + --> $DIR/malformed-static-align.rs:16:1 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[rustc_align_static]` can be applied to statics and foreign statics + +error: `#[repr(align(...))]` is not supported on statics + --> $DIR/malformed-static-align.rs:13:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + | +help: use `#[rustc_align_static(...)]` instead + --> $DIR/malformed-static-align.rs:13:8 + | +LL | #[repr(align(16))] + | ^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0539, E0589. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/issues/issue-59488.rs b/tests/ui/binop/function-comparison-errors-59488.rs index 384501e3e5d..8ded781ef95 100644 --- a/tests/ui/issues/issue-59488.rs +++ b/tests/ui/binop/function-comparison-errors-59488.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/59488 fn foo() -> i32 { 42 } diff --git a/tests/ui/issues/issue-59488.stderr b/tests/ui/binop/function-comparison-errors-59488.stderr index b6611ad63a8..615458bc45b 100644 --- a/tests/ui/issues/issue-59488.stderr +++ b/tests/ui/binop/function-comparison-errors-59488.stderr @@ -1,5 +1,5 @@ error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` - --> $DIR/issue-59488.rs:14:9 + --> $DIR/function-comparison-errors-59488.rs:15:9 | LL | foo > 12; | --- ^ -- {integer} @@ -12,7 +12,7 @@ LL | foo() > 12; | ++ error[E0308]: mismatched types - --> $DIR/issue-59488.rs:14:11 + --> $DIR/function-comparison-errors-59488.rs:15:11 | LL | foo > 12; | ^^ expected fn item, found `i32` @@ -21,7 +21,7 @@ LL | foo > 12; found type `i32` error[E0369]: binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` - --> $DIR/issue-59488.rs:18:9 + --> $DIR/function-comparison-errors-59488.rs:19:9 | LL | bar > 13; | --- ^ -- {integer} @@ -34,7 +34,7 @@ LL | bar(/* i64 */) > 13; | +++++++++++ error[E0308]: mismatched types - --> $DIR/issue-59488.rs:18:11 + --> $DIR/function-comparison-errors-59488.rs:19:11 | LL | bar > 13; | ^^ expected fn item, found `i64` @@ -43,7 +43,7 @@ LL | bar > 13; found type `i64` error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` - --> $DIR/issue-59488.rs:22:9 + --> $DIR/function-comparison-errors-59488.rs:23:9 | LL | foo > foo; | --- ^ --- fn() -> i32 {foo} @@ -56,7 +56,7 @@ LL | foo() > foo(); | ++ ++ error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` - --> $DIR/issue-59488.rs:25:9 + --> $DIR/function-comparison-errors-59488.rs:26:9 | LL | foo > bar; | --- ^ --- fn(i64) -> i64 {bar} @@ -64,7 +64,7 @@ LL | foo > bar; | fn() -> i32 {foo} error[E0308]: mismatched types - --> $DIR/issue-59488.rs:25:11 + --> $DIR/function-comparison-errors-59488.rs:26:11 | LL | foo > bar; | ^^^ expected fn item, found a different fn item @@ -73,7 +73,7 @@ LL | foo > bar; found fn item `fn(i64) -> i64 {bar}` error[E0369]: binary operation `==` cannot be applied to type `fn(usize) -> Foo {Foo::Bar}` - --> $DIR/issue-59488.rs:30:5 + --> $DIR/function-comparison-errors-59488.rs:31:5 | LL | assert_eq!(Foo::Bar, i); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | assert_eq!(Foo::Bar, i); = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` - --> $DIR/issue-59488.rs:30:5 + --> $DIR/function-comparison-errors-59488.rs:31:5 | LL | assert_eq!(Foo::Bar, i); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` @@ -92,7 +92,7 @@ LL | assert_eq!(Foo::Bar, i); = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` - --> $DIR/issue-59488.rs:30:5 + --> $DIR/function-comparison-errors-59488.rs:31:5 | LL | assert_eq!(Foo::Bar, i); | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs b/tests/ui/box/boxed-value-matching-57741.rs index d0aae23b2fc..7e2f089dad8 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs +++ b/tests/ui/box/boxed-value-matching-57741.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57741 #![allow(warnings)] // This tests that the `help: consider dereferencing the boxed value` suggestion isn't made diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.stderr b/tests/ui/box/boxed-value-matching-57741.stderr index 76f03bab6d1..33d7a6759ad 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.stderr +++ b/tests/ui/box/boxed-value-matching-57741.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-57741-1.rs:14:9 + --> $DIR/boxed-value-matching-57741.rs:15:9 | LL | let y = match x { | - this expression has type `Box<u32>` @@ -10,7 +10,7 @@ LL | S::A { a } | S::B { b: a } => a, found enum `S` error[E0308]: mismatched types - --> $DIR/issue-57741-1.rs:14:22 + --> $DIR/boxed-value-matching-57741.rs:15:22 | LL | let y = match x { | - this expression has type `Box<u32>` diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.fixed b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.fixed index 1823f0d3d4c..ee796b56272 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.fixed +++ b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.fixed @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57741 //@ run-rustfix #![allow(warnings)] diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.rs index 47ab91177e0..3a45a8b56ff 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs +++ b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57741 //@ run-rustfix #![allow(warnings)] diff --git a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.stderr index 62d83a54614..c07387b21bd 100644 --- a/tests/ui/issues/issue-57741-dereference-boxed-value/issue-57741.stderr +++ b/tests/ui/box/dereferencing-boxed-enum-in-match-57741.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-57741.rs:20:9 + --> $DIR/dereferencing-boxed-enum-in-match-57741.rs:21:9 | LL | let y = match x { | - this expression has type `Box<T>` @@ -14,7 +14,7 @@ LL | let y = match *x { | + error[E0308]: mismatched types - --> $DIR/issue-57741.rs:20:19 + --> $DIR/dereferencing-boxed-enum-in-match-57741.rs:21:19 | LL | let y = match x { | - this expression has type `Box<T>` @@ -29,7 +29,7 @@ LL | let y = match *x { | + error[E0308]: mismatched types - --> $DIR/issue-57741.rs:27:9 + --> $DIR/dereferencing-boxed-enum-in-match-57741.rs:28:9 | LL | let y = match x { | - this expression has type `Box<S>` @@ -44,7 +44,7 @@ LL | let y = match *x { | + error[E0308]: mismatched types - --> $DIR/issue-57741.rs:27:22 + --> $DIR/dereferencing-boxed-enum-in-match-57741.rs:28:22 | LL | let y = match x { | - this expression has type `Box<S>` diff --git a/tests/ui/c-variadic/issue-86053-1.rs b/tests/ui/c-variadic/issue-86053-1.rs index 537d0263adf..58dfee55cf8 100644 --- a/tests/ui/c-variadic/issue-86053-1.rs +++ b/tests/ui/c-variadic/issue-86053-1.rs @@ -13,6 +13,6 @@ fn ordering4 < 'a , 'b > ( a : , self , self , self , //~| ERROR unexpected `self` parameter in function //~| ERROR unexpected `self` parameter in function //~| ERROR `...` must be the last argument of a C-variadic function - //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~| ERROR `...` is not supported for non-extern functions //~| ERROR cannot find type `F` in this scope } diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index b58016b5a81..adbc04d3a65 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -46,11 +46,13 @@ error: `...` must be the last argument of a C-variadic function LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: `...` is not supported for non-extern functions --> $DIR/issue-86053-1.rs:11:36 | LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^ + | + = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error[E0412]: cannot find type `F` in this scope --> $DIR/issue-86053-1.rs:11:48 diff --git a/tests/ui/c-variadic/naked.rs b/tests/ui/c-variadic/naked.rs new file mode 100644 index 00000000000..46b59395485 --- /dev/null +++ b/tests/ui/c-variadic/naked.rs @@ -0,0 +1,40 @@ +//@ run-pass +//@ only-x86_64 +//@ only-linux +#![feature(c_variadic)] + +#[repr(C)] +#[derive(Debug, PartialEq)] +struct Data(i32, f64); + +#[unsafe(naked)] +unsafe extern "C" fn c_variadic(_: ...) -> Data { + // This assembly was generated with GCC, because clang/LLVM is unable to + // optimize out the spilling of all registers to the stack. + core::arch::naked_asm!( + " sub rsp, 96", + " mov QWORD PTR [rsp-88], rdi", + " test al, al", + " je .L7", + " movaps XMMWORD PTR [rsp-40], xmm0", + ".L7:", + " lea rax, [rsp+104]", + " mov rcx, QWORD PTR [rsp-40]", + " mov DWORD PTR [rsp-112], 0", + " mov QWORD PTR [rsp-104], rax", + " lea rax, [rsp-88]", + " mov QWORD PTR [rsp-96], rax", + " movq xmm0, rcx", + " mov eax, DWORD PTR [rsp-88]", + " mov DWORD PTR [rsp-108], 48", + " add rsp, 96", + " ret", + ) +} + +fn main() { + unsafe { + assert_eq!(c_variadic(1, 2.0), Data(1, 2.0)); + assert_eq!(c_variadic(123, 4.56), Data(123, 4.56)); + } +} diff --git a/tests/ui/c-variadic/not-async.rs b/tests/ui/c-variadic/not-async.rs new file mode 100644 index 00000000000..45a7e1f8972 --- /dev/null +++ b/tests/ui/c-variadic/not-async.rs @@ -0,0 +1,7 @@ +//@ edition: 2021 +#![feature(c_variadic)] +#![crate_type = "lib"] + +async unsafe extern "C" fn cannot_be_async(x: isize, ...) {} +//~^ ERROR functions cannot be both `async` and C-variadic +//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds diff --git a/tests/ui/c-variadic/not-async.stderr b/tests/ui/c-variadic/not-async.stderr new file mode 100644 index 00000000000..b8caf0d8bd8 --- /dev/null +++ b/tests/ui/c-variadic/not-async.stderr @@ -0,0 +1,19 @@ +error: functions cannot be both `async` and C-variadic + --> $DIR/not-async.rs:5:1 + | +LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {} + | ^^^^^ `async` because of this ^^^ C-variadic because of this + +error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds + --> $DIR/not-async.rs:5:59 + | +LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {} + | --------------------------------------------------------- ^^ + | | + | opaque type defined here + | + = note: hidden type `{async fn body of cannot_be_async()}` captures lifetime `'_` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs b/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs index afb16cf58e8..4ae77ab6439 100644 --- a/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs +++ b/tests/ui/closures/2229_closure_analysis/run_pass/lit-pattern-matching-with-methods.rs @@ -2,7 +2,6 @@ //@check-pass #![warn(unused)] #![feature(rustc_attrs)] -#![feature(btree_extract_if)] use std::collections::BTreeMap; use std::panic::{catch_unwind, AssertUnwindSafe}; diff --git a/tests/ui/issues/issue-59494.rs b/tests/ui/closures/generic-typed-nested-closures-59494.rs index b4d50bd4ce7..04d7b00ff7f 100644 --- a/tests/ui/issues/issue-59494.rs +++ b/tests/ui/closures/generic-typed-nested-closures-59494.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/59494 fn t7p<A, B, C>(f: impl Fn(B) -> C, g: impl Fn(A) -> B) -> impl Fn(A) -> C { move |a: A| -> C { f(g(a)) } } diff --git a/tests/ui/issues/issue-59494.stderr b/tests/ui/closures/generic-typed-nested-closures-59494.stderr index 33d3e48c1aa..9706fea82a3 100644 --- a/tests/ui/issues/issue-59494.stderr +++ b/tests/ui/closures/generic-typed-nested-closures-59494.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-59494.rs:20:40 + --> $DIR/generic-typed-nested-closures-59494.rs:21:40 | LL | let t7 = |env| |a| |b| t7p(f, g)(((env, a), b)); | ^^^ cyclic type of infinite size diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index ad4fca8252d..eb6f4a32365 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -53,9 +53,7 @@ extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { x } -extern "cmse-nonsecure-entry" fn static_trait_object( - x: &'static dyn Trait, -) -> &'static dyn Trait { +extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait { //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798] x } @@ -63,14 +61,12 @@ extern "cmse-nonsecure-entry" fn static_trait_object( #[repr(transparent)] struct WrapperTransparent<'a>(&'a dyn Trait); -extern "cmse-nonsecure-entry" fn wrapped_trait_object( - x: WrapperTransparent, -) -> WrapperTransparent { +extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent { //~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798] x } -extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { + //~^ ERROR `...` is not supported for `extern "cmse-nonsecure-entry"` functions //~| ERROR requires `va_list` lang_item } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index 7aeb6969feb..8937def9428 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,8 +1,12 @@ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/generics.rs:73:53 +error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions + --> $DIR/generics.rs:69:60 | -LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - | ^^^^^^ +LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { + | ----------------------------- ^^^^^^ + | | + | `extern "cmse-nonsecure-entry"` because of this + | + = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type --> $DIR/generics.rs:30:1 @@ -50,28 +54,28 @@ LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:58:6 + --> $DIR/generics.rs:56:80 | -LL | ) -> &'static dyn Trait { - | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait { + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:68:6 + --> $DIR/generics.rs:64:81 | -LL | ) -> WrapperTransparent { - | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers +LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent { + | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers | = note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error: requires `va_list` lang_item - --> $DIR/generics.rs:73:53 + --> $DIR/generics.rs:69:60 | -LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - | ^^^^^^ +LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { + | ^^^^^^ error: aborting due to 9 previous errors diff --git a/tests/ui/issues/issue-58375-monomorphize-default-impls.rs b/tests/ui/codegen/mono-item-collector-default-impl-58375.rs index 769a1176edd..f00e79e0dc5 100644 --- a/tests/ui/issues/issue-58375-monomorphize-default-impls.rs +++ b/tests/ui/codegen/mono-item-collector-default-impl-58375.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58375 // Make sure that the mono-item collector does not crash when trying to // instantiate a default impl for DecodeUtf16<<u8 as A>::Item> // See https://github.com/rust-lang/rust/issues/58375 diff --git a/tests/ui/codemap_tests/issue-28308.rs b/tests/ui/codemap_tests/issue-28308.rs index b0e04d0f1f6..81493f8c453 100644 --- a/tests/ui/codemap_tests/issue-28308.rs +++ b/tests/ui/codemap_tests/issue-28308.rs @@ -1,16 +1,4 @@ fn main() { - assert!("foo"); //~ ERROR mismatched types - //~^ NOTE expected `bool`, found `str` - //~| NOTE in this expansion of assert! - let x = Some(&1); - assert!(x); //~ ERROR mismatched types - //~^ NOTE expected `bool`, found `Option<&{integer}>` - //~| NOTE expected enum `bool` - //~| NOTE in this expansion of assert! - //~| NOTE in this expansion of assert! - assert!(x, ""); //~ ERROR mismatched types - //~^ NOTE expected `bool`, found `Option<&{integer}>` - //~| NOTE expected enum `bool` - //~| NOTE in this expansion of assert! - //~| NOTE in this expansion of assert! + assert!("foo"); + //~^ ERROR cannot apply unary operator `!` } diff --git a/tests/ui/codemap_tests/issue-28308.stderr b/tests/ui/codemap_tests/issue-28308.stderr index e84ceb44aac..7bc9e05dfc0 100644 --- a/tests/ui/codemap_tests/issue-28308.stderr +++ b/tests/ui/codemap_tests/issue-28308.stderr @@ -1,27 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/issue-28308.rs:2:13 +error[E0600]: cannot apply unary operator `!` to type `&'static str` + --> $DIR/issue-28308.rs:2:5 | LL | assert!("foo"); - | ^^^^^ expected `bool`, found `str` + | ^^^^^^^^^^^^^^ cannot apply unary operator `!` -error[E0308]: mismatched types - --> $DIR/issue-28308.rs:6:13 - | -LL | assert!(x); - | ^ expected `bool`, found `Option<&{integer}>` - | - = note: expected enum `bool` - found type `Option<&{integer}>` - -error[E0308]: mismatched types - --> $DIR/issue-28308.rs:11:13 - | -LL | assert!(x, ""); - | ^ expected `bool`, found `Option<&{integer}>` - | - = note: expected enum `bool` - found type `Option<&{integer}>` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0600`. diff --git a/tests/ui/issues/issue-57162.rs b/tests/ui/coherence/trait-implementation-coherence-check-57162.rs index 5e62d0eb010..a57e827ca8b 100644 --- a/tests/ui/issues/issue-57162.rs +++ b/tests/ui/coherence/trait-implementation-coherence-check-57162.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57162 //@ check-pass trait Foo {} diff --git a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs b/tests/ui/const-generics/generic_arg_infer/paren_infer.rs index 9d7df8016cb..869683b7056 100644 --- a/tests/ui/const-generics/generic_arg_infer/parend_infer.rs +++ b/tests/ui/const-generics/generic_arg_infer/paren_infer.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ reference: items.generics.const.inferred struct Foo<const N: usize>; diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs index 478fa3706e8..9af351ec59f 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.rs @@ -11,7 +11,6 @@ where { fn unimplemented(self, _: &Foo) -> Self::Output { //~^ ERROR method `unimplemented` is not a member of trait `std::ops::Add` - //~| ERROR type annotations needed loop {} } } diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr index 29bbd23a469..37eb895f9a8 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr @@ -3,7 +3,6 @@ error[E0407]: method `unimplemented` is not a member of trait `std::ops::Add` | LL | / fn unimplemented(self, _: &Foo) -> Self::Output { LL | | -LL | | LL | | loop {} LL | | } | |_____^ not a member of trait `std::ops::Add` @@ -39,21 +38,7 @@ LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported -error[E0284]: type annotations needed - --> $DIR/post-analysis-user-facing-param-env.rs:12:40 - | -LL | fn unimplemented(self, _: &Foo) -> Self::Output { - | ^^^^^^^^^^^^ cannot infer the value of const parameter `NUM` - | -note: required for `Foo` to implement `Add<&'a Foo>` - --> $DIR/post-analysis-user-facing-param-env.rs:6:28 - | -LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo - | ---------------- ^^^^^^^^^^^^^^^^^^^^^^ ^^^ - | | - | unsatisfied trait bound introduced here - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted -Some errors have detailed explanations: E0046, E0207, E0284, E0407. +Some errors have detailed explanations: E0046, E0207, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/const-generics/std/const-generics-range.full.stderr b/tests/ui/const-generics/std/const-generics-range.full.stderr index 2b5c63e6643..ccede2af9e5 100644 --- a/tests/ui/const-generics/std/const-generics-range.full.stderr +++ b/tests/ui/const-generics/std/const-generics-range.full.stderr @@ -28,7 +28,7 @@ error[E0741]: `RangeTo<usize>` must implement `ConstParamTy` to be used as the t LL | struct _RangeTo<const R: std::ops::RangeTo<usize>>; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0741]: `RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter +error[E0741]: `std::ops::RangeToInclusive<usize>` must implement `ConstParamTy` to be used as the type of a const generic parameter --> $DIR/const-generics-range.rs:34:35 | LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; diff --git a/tests/ui/const-generics/std/const-generics-range.min.stderr b/tests/ui/const-generics/std/const-generics-range.min.stderr index 04e3fe74453..43a57c880d5 100644 --- a/tests/ui/const-generics/std/const-generics-range.min.stderr +++ b/tests/ui/const-generics/std/const-generics-range.min.stderr @@ -58,7 +58,7 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: `RangeToInclusive<usize>` is forbidden as the type of a const generic parameter +error: `std::ops::RangeToInclusive<usize>` is forbidden as the type of a const generic parameter --> $DIR/const-generics-range.rs:34:35 | LL | struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; diff --git a/tests/ui/const-generics/std/const-generics-range.rs b/tests/ui/const-generics/std/const-generics-range.rs index 3a238ed177e..391366dadba 100644 --- a/tests/ui/const-generics/std/const-generics-range.rs +++ b/tests/ui/const-generics/std/const-generics-range.rs @@ -7,32 +7,32 @@ // `Range` should be usable within const generics: struct _Range<const R: std::ops::Range<usize>>; //[min]~^ ERROR `std::ops::Range<usize>` is forbidden -const RANGE : _Range<{ 0 .. 1000 }> = _Range; +const RANGE: _Range<{ 0..1000 }> = _Range; // `RangeFrom` should be usable within const generics: struct _RangeFrom<const R: std::ops::RangeFrom<usize>>; //[min]~^ ERROR `std::ops::RangeFrom<usize>` is forbidden -const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom; +const RANGE_FROM: _RangeFrom<{ 0.. }> = _RangeFrom; // `RangeFull` should be usable within const generics: struct _RangeFull<const R: std::ops::RangeFull>; //[min]~^ ERROR `RangeFull` is forbidden -const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull; +const RANGE_FULL: _RangeFull<{ .. }> = _RangeFull; // Regression test for #70155 // `RangeInclusive` should be usable within const generics: struct _RangeInclusive<const R: std::ops::RangeInclusive<usize>>; //[min]~^ ERROR `std::ops::RangeInclusive<usize>` is forbidden -const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive; +const RANGE_INCLUSIVE: _RangeInclusive<{ 0..=999 }> = _RangeInclusive; // `RangeTo` should be usable within const generics: struct _RangeTo<const R: std::ops::RangeTo<usize>>; //[min]~^ ERROR `RangeTo<usize>` is forbidden -const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo; +const RANGE_TO: _RangeTo<{ ..1000 }> = _RangeTo; // `RangeToInclusive` should be usable within const generics: struct _RangeToInclusive<const R: std::ops::RangeToInclusive<usize>>; -//[min]~^ ERROR `RangeToInclusive<usize>` is forbidden -const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive; +//[min]~^ ERROR `std::ops::RangeToInclusive<usize>` is forbidden +const RANGE_TO_INCLUSIVE: _RangeToInclusive<{ ..=999 }> = _RangeToInclusive; pub fn main() {} diff --git a/tests/ui/consts/const-eval/ptr_fragments.rs b/tests/ui/consts/const-eval/ptr_fragments.rs index 04dcbe55590..7dc5870f89e 100644 --- a/tests/ui/consts/const-eval/ptr_fragments.rs +++ b/tests/ui/consts/const-eval/ptr_fragments.rs @@ -1,5 +1,6 @@ //! Test that various operations involving pointer fragments work as expected. //@ run-pass +//@ ignore-test: disabled due to <https://github.com/rust-lang/rust/issues/146291> use std::mem::{self, MaybeUninit, transmute}; use std::ptr; diff --git a/tests/ui/consts/const-eval/ptr_fragments_in_final.rs b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs index e2f3f51b086..aed33d7ed8d 100644 --- a/tests/ui/consts/const-eval/ptr_fragments_in_final.rs +++ b/tests/ui/consts/const-eval/ptr_fragments_in_final.rs @@ -1,4 +1,5 @@ //! Test that we properly error when there is a pointer fragment in the final value. +//@ ignore-test: disabled due to <https://github.com/rust-lang/rust/issues/146291> use std::{mem::{self, MaybeUninit}, ptr}; diff --git a/tests/ui/consts/const-eval/ptr_fragments_mixed.rs b/tests/ui/consts/const-eval/ptr_fragments_mixed.rs new file mode 100644 index 00000000000..79a42820f50 --- /dev/null +++ b/tests/ui/consts/const-eval/ptr_fragments_mixed.rs @@ -0,0 +1,28 @@ +//! This mixes fragments from different pointers to the same allocarion, in a way +//! that we should not accept. See <https://github.com/rust-lang/rust/issues/146291>. +static A: u8 = 123; + +const HALF_PTR: usize = std::mem::size_of::<*const ()>() / 2; + +const fn mix_ptr() -> *const u8 { + unsafe { + let x: *const u8 = &raw const A; + let mut y = x.wrapping_add(usize::MAX / 4); + core::ptr::copy_nonoverlapping( + (&raw const x).cast::<u8>(), + (&raw mut y).cast::<u8>(), + HALF_PTR, + ); + y + } +} + +const APTR: *const u8 = mix_ptr(); //~ERROR: unable to read parts of a pointer + +fn main() { + let a = APTR; + println!("{a:p}"); + let b = mix_ptr(); + println!("{b:p}"); + assert_eq!(a, b); +} diff --git a/tests/ui/consts/const-eval/ptr_fragments_mixed.stderr b/tests/ui/consts/const-eval/ptr_fragments_mixed.stderr new file mode 100644 index 00000000000..9e991ab7a7d --- /dev/null +++ b/tests/ui/consts/const-eval/ptr_fragments_mixed.stderr @@ -0,0 +1,23 @@ +error[E0080]: unable to read parts of a pointer from memory at ALLOC0 + --> $DIR/ptr_fragments_mixed.rs:20:25 + | +LL | const APTR: *const u8 = mix_ptr(); + | ^^^^^^^^^ evaluation of `APTR` failed inside this call + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported +note: inside `mix_ptr` + --> $DIR/ptr_fragments_mixed.rs:11:9 + | +LL | / core::ptr::copy_nonoverlapping( +LL | | (&raw const x).cast::<u8>(), +LL | | (&raw mut y).cast::<u8>(), +LL | | HALF_PTR, +LL | | ); + | |_________^ +note: inside `std::ptr::copy_nonoverlapping::<u8>` + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/read_partial_ptr.rs b/tests/ui/consts/const-eval/read_partial_ptr.rs index bccef9c0bc6..c153e274e41 100644 --- a/tests/ui/consts/const-eval/read_partial_ptr.rs +++ b/tests/ui/consts/const-eval/read_partial_ptr.rs @@ -1,4 +1,5 @@ //! Ensure we error when trying to load from a pointer whose provenance has been messed with. +//@ ignore-test: disabled due to <https://github.com/rust-lang/rust/issues/146291> const PARTIAL_OVERWRITE: () = { let mut p = &42; diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs index ff44876c5c4..dc0701d3b1d 100644 --- a/tests/ui/consts/const_cmp_type_id.rs +++ b/tests/ui/consts/const_cmp_type_id.rs @@ -9,8 +9,7 @@ fn main() { assert!(TypeId::of::<u8>() == TypeId::of::<u8>()); assert!(TypeId::of::<()>() != TypeId::of::<u8>()); let _a = TypeId::of::<u8>() < TypeId::of::<u16>(); - //~^ ERROR: cannot call non-const operator in constants - // can't assert `_a` because it is not deterministic - // FIXME(const_trait_impl) make it pass + //~^ ERROR: the trait bound `TypeId: const PartialOrd` is not satisfied + // FIXME(const_trait_impl) make it pass; requires const comparison of pointers (#53020) } } diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr index 05b94caef79..62a1677c0d9 100644 --- a/tests/ui/consts/const_cmp_type_id.stderr +++ b/tests/ui/consts/const_cmp_type_id.stderr @@ -1,13 +1,9 @@ -error[E0015]: cannot call non-const operator in constants +error[E0277]: the trait bound `TypeId: const PartialOrd` is not satisfied --> $DIR/const_cmp_type_id.rs:11:18 | LL | let _a = TypeId::of::<u8>() < TypeId::of::<u16>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: impl defined here, but it is not `const` - --> $SRC_DIR/core/src/any.rs:LL:COL - = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/control-flow/assert.stderr b/tests/ui/consts/control-flow/assert.stderr index deaad6abbcc..026097a6ba0 100644 --- a/tests/ui/consts/control-flow/assert.stderr +++ b/tests/ui/consts/control-flow/assert.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/assert.rs:5:23 + --> $DIR/assert.rs:5:15 | LL | const _: () = assert!(false); - | ^^^^^ evaluation of `_` failed here + | ^^^^^^^^^^^^^^ evaluation of `_` failed here error: aborting due to 1 previous error diff --git a/tests/ui/consts/fn_trait_refs.rs b/tests/ui/consts/fn_trait_refs.rs index e475c0a1b6f..e4a62e18c7b 100644 --- a/tests/ui/consts/fn_trait_refs.rs +++ b/tests/ui/consts/fn_trait_refs.rs @@ -1,6 +1,5 @@ -//@ known-bug: #110395 +//@ check-pass -#![feature(const_fn_trait_ref_impls)] #![feature(fn_traits)] #![feature(unboxed_closures)] #![feature(const_trait_impl)] diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr deleted file mode 100644 index bbe0714801c..00000000000 --- a/tests/ui/consts/fn_trait_refs.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0635]: unknown feature `const_fn_trait_ref_impls` - --> $DIR/fn_trait_refs.rs:3:12 - | -LL | #![feature(const_fn_trait_ref_impls)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied - --> $DIR/fn_trait_refs.rs:71:17 - | -LL | assert!(test_one == (1, 1, 1)); - | ^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied - --> $DIR/fn_trait_refs.rs:74:17 - | -LL | assert!(test_two == (2, 2)); - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0277, E0635. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/missing-larger-array-impl.stderr b/tests/ui/consts/missing-larger-array-impl.stderr index ff4fa36d684..33d7a46339b 100644 --- a/tests/ui/consts/missing-larger-array-impl.stderr +++ b/tests/ui/consts/missing-larger-array-impl.stderr @@ -8,11 +8,11 @@ LL | <[X; 35] as Default>::default(); &[T] &mut [T] [T; 0] - [T; 10] - [T; 11] - [T; 12] - [T; 13] - [T; 14] + [T; 1] + [T; 2] + [T; 3] + [T; 4] + [T; 5] and 27 others error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-57781.rs b/tests/ui/consts/oncecell-const-init-57781.rs index 7f0d2eda9bb..27426ef2549 100644 --- a/tests/ui/issues/issue-57781.rs +++ b/tests/ui/consts/oncecell-const-init-57781.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57781 //@ run-pass use std::cell::UnsafeCell; diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr index 67f5009c4ff..c1ae42b3939 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.noopt.stderr @@ -1,17 +1,17 @@ error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:9:19 + --> $DIR/collect-in-promoted-const.rs:11:19 | LL | const C: () = panic!(); | ^^^^^^^^ evaluation of `Fail::<i32>::C` failed here note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:20:21 + --> $DIR/collect-in-promoted-const.rs:22:21 | LL | let _val = &Fail::<T>::C; | ^^^^^^^^^^^^ note: the above error was encountered while instantiating `fn f::<i32>` - --> $DIR/collect-in-promoted-const.rs:25:5 + --> $DIR/collect-in-promoted-const.rs:27:5 | LL | f::<i32>(); | ^^^^^^^^^^ diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr index 5c3edf68d95..0d7ac48172c 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.opt.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:9:19 + --> $DIR/collect-in-promoted-const.rs:11:19 | LL | const C: () = panic!(); | ^^^^^^^^ evaluation of `Fail::<T>::C` failed here note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:20:21 + --> $DIR/collect-in-promoted-const.rs:22:21 | LL | let _val = &Fail::<T>::C; | ^^^^^^^^^^^^ error[E0080]: evaluation panicked: explicit panic - --> $DIR/collect-in-promoted-const.rs:9:19 + --> $DIR/collect-in-promoted-const.rs:11:19 | LL | const C: () = panic!(); | ^^^^^^^^ evaluation of `Fail::<i32>::C` failed here note: erroneous constant encountered - --> $DIR/collect-in-promoted-const.rs:20:21 + --> $DIR/collect-in-promoted-const.rs:22:21 | LL | let _val = &Fail::<T>::C; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _val = &Fail::<T>::C; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn f::<i32>` - --> $DIR/collect-in-promoted-const.rs:25:5 + --> $DIR/collect-in-promoted-const.rs:27:5 | LL | f::<i32>(); | ^^^^^^^^^^ diff --git a/tests/ui/consts/required-consts/collect-in-promoted-const.rs b/tests/ui/consts/required-consts/collect-in-promoted-const.rs index 25c8cb7e804..498328abe21 100644 --- a/tests/ui/consts/required-consts/collect-in-promoted-const.rs +++ b/tests/ui/consts/required-consts/collect-in-promoted-const.rs @@ -1,6 +1,8 @@ //@revisions: noopt opt //@ build-fail //@[noopt] compile-flags: -Copt-level=0 +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0 +//@[opt] compile-flags: -C debuginfo=0 //@[opt] compile-flags: -O //! Make sure we error on erroneous consts even if they get promoted. diff --git a/tests/ui/issues/issue-58463.rs b/tests/ui/debuginfo/impl-copy-function-debuginfo-58463.rs index 6e4b909bc38..72388c36ce4 100644 --- a/tests/ui/issues/issue-58463.rs +++ b/tests/ui/debuginfo/impl-copy-function-debuginfo-58463.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58463 //@ run-pass //@ compile-flags:-C debuginfo=2 diff --git a/tests/ui/deref/pin-deref-const.rs b/tests/ui/deref/pin-deref-const.rs new file mode 100644 index 00000000000..6ed00177b23 --- /dev/null +++ b/tests/ui/deref/pin-deref-const.rs @@ -0,0 +1,79 @@ +// The purpose of this file is to track the error messages from Pin and DerefMut interacting. +// +// Identical to `pin-deref.rs` except for using unstable `const fn`. + +//@ check-fail + +#![feature(const_convert)] +#![feature(const_trait_impl)] + +use std::ops::DerefMut; +use std::pin::Pin; + +struct MyUnpinType {} + +impl MyUnpinType { + const fn at_self(&self) {} + const fn at_mut_self(&mut self) {} +} + +struct MyPinType(core::marker::PhantomPinned); + +impl MyPinType { + const fn at_self(&self) {} + const fn at_mut_self(&mut self) {} +} + +const fn call_mut_ref_unpin(mut r_unpin: Pin<&mut MyUnpinType>) { + r_unpin.at_self(); + r_unpin.at_mut_self(); +} + +const fn call_ref_unpin(mut r_unpin: Pin<&MyUnpinType>) { + r_unpin.at_self(); + r_unpin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable +} + +const fn call_mut_ref_pin(mut r_pin: Pin<&mut MyPinType>) { + r_pin.at_self(); + r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable +} + +const fn call_ref_pin(mut r_pin: Pin<&MyPinType>) { + r_pin.at_self(); + r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable +} + +const fn coerce_unpin_rr<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a MyUnpinType { + r_unpin +} + +const fn coerce_unpin_rm<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a mut MyUnpinType { + r_unpin //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable +} + +const fn coerce_unpin_mr<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a MyUnpinType { + r_unpin +} + +const fn coerce_unpin_mm<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a mut MyUnpinType { + r_unpin +} + +const fn coerce_pin_rr<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a MyPinType { + r_pin +} + +const fn coerce_pin_rm<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a mut MyPinType { + r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable +} + +const fn coerce_pin_mr<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a MyPinType { + r_pin +} + +const fn coerce_pin_mm<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a mut MyPinType { + r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable +} + +fn main() {} diff --git a/tests/ui/deref/pin-deref-const.stderr b/tests/ui/deref/pin-deref-const.stderr new file mode 100644 index 00000000000..caa270e64ff --- /dev/null +++ b/tests/ui/deref/pin-deref-const.stderr @@ -0,0 +1,51 @@ +error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable + --> $DIR/pin-deref-const.rs:34:5 + | +LL | r_unpin.at_mut_self(); + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable + --> $DIR/pin-deref-const.rs:39:5 + | +LL | r_pin.at_mut_self(); + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable + --> $DIR/pin-deref-const.rs:44:5 + | +LL | r_pin.at_mut_self(); + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable + --> $DIR/pin-deref-const.rs:52:5 + | +LL | r_unpin + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable + --> $DIR/pin-deref-const.rs:68:5 + | +LL | r_pin + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable + --> $DIR/pin-deref-const.rs:76:5 + | +LL | r_pin + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/deref/pin-deref.rs b/tests/ui/deref/pin-deref.rs new file mode 100644 index 00000000000..180831c9bc6 --- /dev/null +++ b/tests/ui/deref/pin-deref.rs @@ -0,0 +1,76 @@ +// The purpose of this file is to track the error messages from Pin and DerefMut interacting. +// +// Identical to `pin-deref-const.rs` except for being stable and not using `const fn`. + +//@ check-fail + +use std::ops::DerefMut; +use std::pin::Pin; + +struct MyUnpinType {} + +impl MyUnpinType { + fn at_self(&self) {} + fn at_mut_self(&mut self) {} +} + +struct MyPinType(core::marker::PhantomPinned); + +impl MyPinType { + fn at_self(&self) {} + fn at_mut_self(&mut self) {} +} + +fn call_mut_ref_unpin(mut r_unpin: Pin<&mut MyUnpinType>) { + r_unpin.at_self(); + r_unpin.at_mut_self(); +} + +fn call_ref_unpin(mut r_unpin: Pin<&MyUnpinType>) { + r_unpin.at_self(); + r_unpin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable +} + +fn call_mut_ref_pin(mut r_pin: Pin<&mut MyPinType>) { + r_pin.at_self(); + r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable +} + +fn call_ref_pin(mut r_pin: Pin<&MyPinType>) { + r_pin.at_self(); + r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable +} + +fn coerce_unpin_rr<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a MyUnpinType { + r_unpin +} + +fn coerce_unpin_rm<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a mut MyUnpinType { + r_unpin //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable +} + +fn coerce_unpin_mr<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a MyUnpinType { + r_unpin +} + +fn coerce_unpin_mm<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a mut MyUnpinType { + r_unpin +} + +fn coerce_pin_rr<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a MyPinType { + r_pin +} + +fn coerce_pin_rm<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a mut MyPinType { + r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable +} + +fn coerce_pin_mr<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a MyPinType { + r_pin +} + +fn coerce_pin_mm<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a mut MyPinType { + r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable +} + +fn main() {} diff --git a/tests/ui/deref/pin-deref.stderr b/tests/ui/deref/pin-deref.stderr new file mode 100644 index 00000000000..71277a10cdf --- /dev/null +++ b/tests/ui/deref/pin-deref.stderr @@ -0,0 +1,51 @@ +error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable + --> $DIR/pin-deref.rs:31:5 + | +LL | r_unpin.at_mut_self(); + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable + --> $DIR/pin-deref.rs:36:5 + | +LL | r_pin.at_mut_self(); + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable + --> $DIR/pin-deref.rs:41:5 + | +LL | r_pin.at_mut_self(); + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable + --> $DIR/pin-deref.rs:49:5 + | +LL | r_unpin + | ^^^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable + --> $DIR/pin-deref.rs:65:5 + | +LL | r_pin + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>` + +error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable + --> $DIR/pin-deref.rs:73:5 + | +LL | r_pin + | ^^^^^ cannot borrow as mutable + | + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/deref/pin-impl-deref.rs b/tests/ui/deref/pin-impl-deref.rs new file mode 100644 index 00000000000..b1dc8dea3f2 --- /dev/null +++ b/tests/ui/deref/pin-impl-deref.rs @@ -0,0 +1,40 @@ +// The purpose of this file is to track the error messages from Pin and DerefMut interacting. + +//@ check-fail + +use std::ops::DerefMut; +use std::pin::Pin; + +struct MyUnpinType {} + +impl MyUnpinType { + fn at_self(&self) {} + fn at_mut_self(&mut self) {} +} + +struct MyPinType(core::marker::PhantomPinned); + +impl MyPinType { + fn at_self(&self) {} + fn at_mut_self(&mut self) {} +} + +fn impl_deref_mut(_: impl DerefMut) {} +fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) { + impl_deref_mut(r_unpin) + //~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied +} +fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) { + impl_deref_mut(r_unpin) +} +fn pin_impl_ref(r_pin: Pin<&MyPinType>) { + impl_deref_mut(r_pin) + //~^ ERROR: `PhantomPinned` cannot be unpinned + //~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied +} +fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) { + impl_deref_mut(r_pin) + //~^ ERROR: `PhantomPinned` cannot be unpinned +} + +fn main() {} diff --git a/tests/ui/deref/pin-impl-deref.stderr b/tests/ui/deref/pin-impl-deref.stderr new file mode 100644 index 00000000000..106654641a1 --- /dev/null +++ b/tests/ui/deref/pin-impl-deref.stderr @@ -0,0 +1,85 @@ +error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied + --> $DIR/pin-impl-deref.rs:24:20 + | +LL | impl_deref_mut(r_unpin) + | -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>` + | | + | required by a bound introduced by this call + | + = note: required for `Pin<&MyUnpinType>` to implement `DerefMut` +note: required by a bound in `impl_deref_mut` + --> $DIR/pin-impl-deref.rs:22:27 + | +LL | fn impl_deref_mut(_: impl DerefMut) {} + | ^^^^^^^^ required by this bound in `impl_deref_mut` +help: consider mutably borrowing here + | +LL | impl_deref_mut(&mut r_unpin) + | ++++ + +error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied + --> $DIR/pin-impl-deref.rs:31:20 + | +LL | impl_deref_mut(r_pin) + | -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>` + | | + | required by a bound introduced by this call + | + = note: required for `Pin<&MyPinType>` to implement `DerefMut` +note: required by a bound in `impl_deref_mut` + --> $DIR/pin-impl-deref.rs:22:27 + | +LL | fn impl_deref_mut(_: impl DerefMut) {} + | ^^^^^^^^ required by this bound in `impl_deref_mut` +help: consider mutably borrowing here + | +LL | impl_deref_mut(&mut r_pin) + | ++++ + +error[E0277]: `PhantomPinned` cannot be unpinned + --> $DIR/pin-impl-deref.rs:31:20 + | +LL | impl_deref_mut(r_pin) + | -------------- ^^^^^ within `MyPinType`, the trait `Unpin` is not implemented for `PhantomPinned` + | | + | required by a bound introduced by this call + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required because it appears within the type `MyPinType` + --> $DIR/pin-impl-deref.rs:15:8 + | +LL | struct MyPinType(core::marker::PhantomPinned); + | ^^^^^^^^^ + = note: required for `Pin<&MyPinType>` to implement `DerefMut` +note: required by a bound in `impl_deref_mut` + --> $DIR/pin-impl-deref.rs:22:27 + | +LL | fn impl_deref_mut(_: impl DerefMut) {} + | ^^^^^^^^ required by this bound in `impl_deref_mut` + +error[E0277]: `PhantomPinned` cannot be unpinned + --> $DIR/pin-impl-deref.rs:36:20 + | +LL | impl_deref_mut(r_pin) + | -------------- ^^^^^ within `MyPinType`, the trait `Unpin` is not implemented for `PhantomPinned` + | | + | required by a bound introduced by this call + | + = note: consider using the `pin!` macro + consider using `Box::pin` if you need to access the pinned value outside of the current scope +note: required because it appears within the type `MyPinType` + --> $DIR/pin-impl-deref.rs:15:8 + | +LL | struct MyPinType(core::marker::PhantomPinned); + | ^^^^^^^^^ + = note: required for `Pin<&mut MyPinType>` to implement `DerefMut` +note: required by a bound in `impl_deref_mut` + --> $DIR/pin-impl-deref.rs:22:27 + | +LL | fn impl_deref_mut(_: impl DerefMut) {} + | ^^^^^^^^ required by this bound in `impl_deref_mut` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs index 198f8d1bc10..6d12ab1e4cf 100644 --- a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs +++ b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs @@ -2,6 +2,7 @@ // dist artifacts. //@ only-dist +//@ only-nightly (cranelift is not stable yet) //@ only-x86_64-unknown-linux-gnu //@ compile-flags: -Z codegen-backend=cranelift //@ run-pass diff --git a/tests/ui/issues/issue-58734.rs b/tests/ui/dyn-compatibility/spurious-dyn-compat-errors-58734.rs index e5b371f5530..3e9ebb497a2 100644 --- a/tests/ui/issues/issue-58734.rs +++ b/tests/ui/dyn-compatibility/spurious-dyn-compat-errors-58734.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58734 trait Trait { fn exists(self) -> (); diff --git a/tests/ui/issues/issue-58734.stderr b/tests/ui/dyn-compatibility/spurious-dyn-compat-errors-58734.stderr index 2336a94f150..140461283f3 100644 --- a/tests/ui/issues/issue-58734.stderr +++ b/tests/ui/dyn-compatibility/spurious-dyn-compat-errors-58734.stderr @@ -1,5 +1,5 @@ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-58734.rs:20:5 + --> $DIR/spurious-dyn-compat-errors-58734.rs:21:5 | LL | Trait::nonexistent(()); | ^^^^^ @@ -13,14 +13,14 @@ LL | <dyn Trait>::nonexistent(()); | ++++ + error[E0038]: the trait `Trait` is not dyn compatible - --> $DIR/issue-58734.rs:20:5 + --> $DIR/spurious-dyn-compat-errors-58734.rs:21:5 | LL | Trait::nonexistent(()); | ^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $DIR/issue-58734.rs:4:8 + --> $DIR/spurious-dyn-compat-errors-58734.rs:5:8 | LL | trait Trait { | ----- this trait is not dyn compatible... diff --git a/tests/ui/error-emitter/multiline-removal-suggestion.svg b/tests/ui/error-emitter/multiline-removal-suggestion.svg index 9c9bd163ecd..7a88ac55b23 100644 --- a/tests/ui/error-emitter/multiline-removal-suggestion.svg +++ b/tests/ui/error-emitter/multiline-removal-suggestion.svg @@ -1,4 +1,4 @@ -<svg width="2322px" height="4322px" xmlns="http://www.w3.org/2000/svg"> +<svg width="2238px" height="3890px" xmlns="http://www.w3.org/2000/svg"> <style> .fg { fill: #AAAAAA } .bg { background: #000000 } @@ -129,375 +129,327 @@ </tspan> <tspan x="10px" y="982px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> </tspan> - <tspan x="10px" y="1000px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}>> as IntoIterator>::IntoIter = _`</tspan> + <tspan x="10px" y="1000px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="1018px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> + <tspan x="10px" y="1018px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="1036px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}>> as IntoIterator>::Item = _`</tspan> + <tspan x="10px" y="1036px"> </tspan> - <tspan x="10px" y="1054px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> + <tspan x="10px" y="1054px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="1072px"><tspan> `Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:16:10: 16:13}>>: IntoIterator`</tspan> + <tspan x="10px" y="1072px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:32:6</tspan> </tspan> - <tspan x="10px" y="1090px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> + <tspan x="10px" y="1090px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1108px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> + <tspan x="10px" y="1108px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> </tspan> - <tspan x="10px" y="1126px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:14:8: 14:23}>>: Iterator`</tspan> + <tspan x="10px" y="1126px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="1144px"> + <tspan x="10px" y="1144px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1162px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="1162px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="1180px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:32:6</tspan> + <tspan x="10px" y="1180px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="1198px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1198px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> </tspan> - <tspan x="10px" y="1216px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> + <tspan x="10px" y="1216px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="1234px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="1234px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> </tspan> <tspan x="10px" y="1252px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1270px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="1270px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="1288px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="1288px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- .map(|t| (is_true, t))</tspan> </tspan> - <tspan x="10px" y="1306px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> + <tspan x="10px" y="1306px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="1324px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> + <tspan x="10px" y="1324px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1342px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> + <tspan x="10px" y="1342px"> </tspan> - <tspan x="10px" y="1360px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1360px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="1378px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="1378px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:28:2</tspan> </tspan> - <tspan x="10px" y="1396px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- .map(|t| (is_true, t))</tspan> + <tspan x="10px" y="1396px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1414px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="1414px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="1432px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1432px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="1450px"> + <tspan x="10px" y="1450px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="1468px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="1468px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|t| (is_true, t))</tspan> </tspan> - <tspan x="10px" y="1486px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:28:2</tspan> + <tspan x="10px" y="1486px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .flatten()</tspan> </tspan> - <tspan x="10px" y="1504px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1504px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> </tspan> - <tspan x="10px" y="1522px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="1522px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="1540px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> + <tspan x="10px" y="1540px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1558px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="1558px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="1576px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|t| (is_true, t))</tspan> + <tspan x="10px" y="1576px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="1594px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .flatten()</tspan> + <tspan x="10px" y="1594px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> </tspan> - <tspan x="10px" y="1612px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> + <tspan x="10px" y="1612px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="1630px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="1630px"> </tspan> - <tspan x="10px" y="1648px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1648px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>`, but its trait bounds were not satisfied</tspan> </tspan> - <tspan x="10px" y="1666px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="1666px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:35:4</tspan> </tspan> - <tspan x="10px" y="1684px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="1684px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1702px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> + <tspan x="10px" y="1702px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="1720px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> + <tspan x="10px" y="1720px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="1738px"> + <tspan x="10px" y="1738px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="1756px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>`, but its trait bounds were not satisfied</tspan> + <tspan x="10px" y="1756px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t))</tspan> </tspan> - <tspan x="10px" y="1774px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:35:4</tspan> + <tspan x="10px" y="1774px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1792px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1792px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> </tspan> - <tspan x="10px" y="1810px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="1810px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> </tspan> - <tspan x="10px" y="1828px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> + <tspan x="10px" y="1828px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> </tspan> - <tspan x="10px" y="1846px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="1846px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> </tspan> - <tspan x="10px" y="1864px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t))</tspan> + <tspan x="10px" y="1864px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1882px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1882px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="1900px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> + <tspan x="10px" y="1900px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> </tspan> - <tspan x="10px" y="1918px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> + <tspan x="10px" y="1918px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="1936px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> + <tspan x="10px" y="1936px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="1954px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> + <tspan x="10px" y="1954px"> </tspan> - <tspan x="10px" y="1972px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1972px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="1990px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="1990px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:43:7</tspan> </tspan> - <tspan x="10px" y="2008px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> + <tspan x="10px" y="2008px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2026px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}>> as IntoIterator>::IntoIter = _`</tspan> + <tspan x="10px" y="2026px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> }).flatten()</tspan> </tspan> - <tspan x="10px" y="2044px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> + <tspan x="10px" y="2044px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="2062px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}>> as IntoIterator>::Item = _`</tspan> + <tspan x="10px" y="2062px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2080px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> + <tspan x="10px" y="2080px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="2098px"><tspan> `Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:31:10: 31:13}>>: IntoIterator`</tspan> + <tspan x="10px" y="2098px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="2116px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> + <tspan x="10px" y="2116px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> </tspan> - <tspan x="10px" y="2134px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> + <tspan x="10px" y="2134px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="2152px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:29:8: 29:23}>>: Iterator`</tspan> + <tspan x="10px" y="2152px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> </tspan> - <tspan x="10px" y="2170px"> + <tspan x="10px" y="2170px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2188px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="2188px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan><tspan class="fg-ansi256-009">.map(|t| {</tspan> </tspan> - <tspan x="10px" y="2206px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:43:7</tspan> + <tspan x="10px" y="2206px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- (is_true, t)</tspan> </tspan> - <tspan x="10px" y="2224px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2224px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- })</tspan><tspan>.flatten()</tspan> </tspan> - <tspan x="10px" y="2242px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> }).flatten()</tspan> + <tspan x="10px" y="2242px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter().flatten()</tspan> </tspan> - <tspan x="10px" y="2260px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="2260px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2278px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2278px"> </tspan> - <tspan x="10px" y="2296px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="2296px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="2314px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="2314px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:39:2</tspan> </tspan> - <tspan x="10px" y="2332px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> + <tspan x="10px" y="2332px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2350px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> + <tspan x="10px" y="2350px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="2368px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> + <tspan x="10px" y="2368px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="2386px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2386px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter().map(|t| {</tspan> </tspan> - <tspan x="10px" y="2404px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan><tspan class="fg-ansi256-009">.map(|t| {</tspan> + <tspan x="10px" y="2404px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> (is_true, t)</tspan> </tspan> - <tspan x="10px" y="2422px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- (is_true, t)</tspan> + <tspan x="10px" y="2422px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> }).flatten()</tspan> </tspan> - <tspan x="10px" y="2440px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- })</tspan><tspan>.flatten()</tspan> + <tspan x="10px" y="2440px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> </tspan> - <tspan x="10px" y="2458px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter().flatten()</tspan> + <tspan x="10px" y="2458px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> <tspan x="10px" y="2476px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2494px"> + <tspan x="10px" y="2494px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="2512px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="2512px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="2530px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:39:2</tspan> + <tspan x="10px" y="2530px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> </tspan> - <tspan x="10px" y="2548px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2548px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="2566px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="2566px"> </tspan> - <tspan x="10px" y="2584px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> + <tspan x="10px" y="2584px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>`, but its trait bounds were not satisfied</tspan> </tspan> - <tspan x="10px" y="2602px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter().map(|t| {</tspan> + <tspan x="10px" y="2602px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:46:4</tspan> </tspan> - <tspan x="10px" y="2620px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> (is_true, t)</tspan> + <tspan x="10px" y="2620px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2638px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> }).flatten()</tspan> + <tspan x="10px" y="2638px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="2656px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> + <tspan x="10px" y="2656px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="2674px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="2674px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter().map(|t| {</tspan> </tspan> - <tspan x="10px" y="2692px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2692px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> (is_true, t)</tspan> </tspan> - <tspan x="10px" y="2710px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="2710px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2728px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="2728px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> </tspan> - <tspan x="10px" y="2746px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> + <tspan x="10px" y="2746px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> </tspan> - <tspan x="10px" y="2764px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> + <tspan x="10px" y="2764px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> </tspan> - <tspan x="10px" y="2782px"> + <tspan x="10px" y="2782px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> </tspan> - <tspan x="10px" y="2800px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>`, but its trait bounds were not satisfied</tspan> + <tspan x="10px" y="2800px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2818px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:46:4</tspan> + <tspan x="10px" y="2818px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2836px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2836px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> </tspan> - <tspan x="10px" y="2854px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="2854px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="2872px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> + <tspan x="10px" y="2872px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="2890px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter().map(|t| {</tspan> + <tspan x="10px" y="2890px"> </tspan> - <tspan x="10px" y="2908px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> (is_true, t)</tspan> + <tspan x="10px" y="2908px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="2926px"><tspan class="fg-ansi256-012 bold">...</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="2926px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:53:28</tspan> </tspan> - <tspan x="10px" y="2944px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> + <tspan x="10px" y="2944px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="2962px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> + <tspan x="10px" y="2962px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> </tspan> - <tspan x="10px" y="2980px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> + <tspan x="10px" y="2980px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="2998px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> + <tspan x="10px" y="2998px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3016px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3016px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="3034px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3034px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="3052px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> + <tspan x="10px" y="3052px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> </tspan> - <tspan x="10px" y="3070px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}>> as IntoIterator>::IntoIter = _`</tspan> + <tspan x="10px" y="3070px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="3088px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> + <tspan x="10px" y="3088px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> </tspan> - <tspan x="10px" y="3106px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}>> as IntoIterator>::Item = _`</tspan> + <tspan x="10px" y="3106px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3124px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> + <tspan x="10px" y="3124px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="3142px"><tspan> `Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:41:23: 41:26}>>: IntoIterator`</tspan> + <tspan x="10px" y="3142px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- .map(|t| (is_true, t))</tspan><tspan>.flatten()</tspan> </tspan> - <tspan x="10px" y="3160px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> + <tspan x="10px" y="3160px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter().flatten()</tspan> </tspan> - <tspan x="10px" y="3178px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> + <tspan x="10px" y="3178px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3196px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:40:8: 40:23}>>: Iterator`</tspan> + <tspan x="10px" y="3196px"> </tspan> - <tspan x="10px" y="3214px"> + <tspan x="10px" y="3214px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="3232px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="3232px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:50:2</tspan> </tspan> - <tspan x="10px" y="3250px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:53:28</tspan> + <tspan x="10px" y="3250px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3268px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3268px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="3286px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> + <tspan x="10px" y="3286px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="3304px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="3304px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="3322px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3322px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> </tspan> - <tspan x="10px" y="3340px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="3340px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> </tspan> - <tspan x="10px" y="3358px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="3358px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> </tspan> - <tspan x="10px" y="3376px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `flatten`</tspan> + <tspan x="10px" y="3376px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3394px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL</tspan> + <tspan x="10px" y="3394px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> </tspan> - <tspan x="10px" y="3412px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds</tspan> + <tspan x="10px" y="3412px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> </tspan> - <tspan x="10px" y="3430px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3430px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> </tspan> - <tspan x="10px" y="3448px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="3448px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> </tspan> - <tspan x="10px" y="3466px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- .map(|t| (is_true, t))</tspan><tspan>.flatten()</tspan> + <tspan x="10px" y="3466px"> </tspan> - <tspan x="10px" y="3484px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> ts.into_iter().flatten()</tspan> + <tspan x="10px" y="3484px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>`, but its trait bounds were not satisfied</tspan> </tspan> - <tspan x="10px" y="3502px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3502px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:56:4</tspan> </tspan> - <tspan x="10px" y="3520px"> + <tspan x="10px" y="3520px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3538px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: `(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="3538px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> </tspan> - <tspan x="10px" y="3556px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:50:2</tspan> + <tspan x="10px" y="3556px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> </tspan> - <tspan x="10px" y="3574px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3574px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter()</tspan> </tspan> - <tspan x="10px" y="3592px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="3592px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> </tspan> - <tspan x="10px" y="3610px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> + <tspan x="10px" y="3610px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> })</tspan> </tspan> - <tspan x="10px" y="3628px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> ts.into_iter()</tspan> + <tspan x="10px" y="3628px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> </tspan> - <tspan x="10px" y="3646px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> + <tspan x="10px" y="3646px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> </tspan> - <tspan x="10px" y="3664px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|</tspan><tspan> })</tspan> + <tspan x="10px" y="3664px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> </tspan> - <tspan x="10px" y="3682px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">|__________^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">`(bool, HashSet<u8>)` is not an iterator</tspan> + <tspan x="10px" y="3682px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> </tspan> <tspan x="10px" y="3700px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3718px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)`</tspan> + <tspan x="10px" y="3718px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> </tspan> - <tspan x="10px" y="3736px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: required for `(bool, HashSet<u8>)` to implement `IntoIterator`</tspan> + <tspan x="10px" y="3736px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> </tspan> - <tspan x="10px" y="3754px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required by a bound in `Flatten`</tspan> + <tspan x="10px" y="3754px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> </tspan> - <tspan x="10px" y="3772px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL</tspan> + <tspan x="10px" y="3772px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> </tspan> <tspan x="10px" y="3790px"> </tspan> - <tspan x="10px" y="3808px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: the method `collect` exists for struct `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>`, but its trait bounds were not satisfied</tspan> + <tspan x="10px" y="3808px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 12 previous errors</tspan> </tspan> - <tspan x="10px" y="3826px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/multiline-removal-suggestion.rs:56:4</tspan> + <tspan x="10px" y="3826px"> </tspan> - <tspan x="10px" y="3844px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> + <tspan x="10px" y="3844px"><tspan class="bold">Some errors have detailed explanations: E0277, E0599.</tspan> </tspan> - <tspan x="10px" y="3862px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">/</tspan><tspan> hm.into_iter()</tspan> + <tspan x="10px" y="3862px"><tspan class="bold">For more information about an error, try `rustc --explain E0277`.</tspan> </tspan> - <tspan x="10px" y="3880px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|(is_true, ts)| {</tspan> -</tspan> - <tspan x="10px" y="3898px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> ts.into_iter()</tspan> -</tspan> - <tspan x="10px" y="3916px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .map(|t| (is_true, t)).flatten()</tspan> -</tspan> - <tspan x="10px" y="3934px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> })</tspan> -</tspan> - <tspan x="10px" y="3952px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .flatten()</tspan> -</tspan> - <tspan x="10px" y="3970px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> .collect()</tspan> -</tspan> - <tspan x="10px" y="3988px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan class="fg-ansi256-009 bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">method cannot be called due to unsatisfied trait bounds</tspan> -</tspan> - <tspan x="10px" y="4006px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|_________|</tspan> -</tspan> - <tspan x="10px" y="4024px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> -</tspan> - <tspan x="10px" y="4042px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> -</tspan> - <tspan x="10px" y="4060px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: the following trait bounds were not satisfied:</tspan> -</tspan> - <tspan x="10px" y="4078px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}>> as IntoIterator>::IntoIter = _`</tspan> -</tspan> - <tspan x="10px" y="4096px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> -</tspan> - <tspan x="10px" y="4114px"><tspan> `<Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}>> as IntoIterator>::Item = _`</tspan> -</tspan> - <tspan x="10px" y="4132px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> -</tspan> - <tspan x="10px" y="4150px"><tspan> `Flatten<Map<std::vec::IntoIter<HashSet<u8>>, {closure@$DIR/multiline-removal-suggestion.rs:53:10: 53:13}>>: IntoIterator`</tspan> -</tspan> - <tspan x="10px" y="4168px"><tspan> which is required by `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> -</tspan> - <tspan x="10px" y="4186px"><tspan> `Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> -</tspan> - <tspan x="10px" y="4204px"><tspan> which is required by `&mut Flatten<Map<std::collections::hash_map::IntoIter<bool, Vec<HashSet<u8>>>, {closure@$DIR/multiline-removal-suggestion.rs:51:8: 51:23}>>: Iterator`</tspan> -</tspan> - <tspan x="10px" y="4222px"> -</tspan> - <tspan x="10px" y="4240px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 12 previous errors</tspan> -</tspan> - <tspan x="10px" y="4258px"> -</tspan> - <tspan x="10px" y="4276px"><tspan class="bold">Some errors have detailed explanations: E0277, E0599.</tspan> -</tspan> - <tspan x="10px" y="4294px"><tspan class="bold">For more information about an error, try `rustc --explain E0277`.</tspan> -</tspan> - <tspan x="10px" y="4312px"> + <tspan x="10px" y="3880px"> </tspan> </text> diff --git a/tests/ui/explicit-tail-calls/c-variadic.rs b/tests/ui/explicit-tail-calls/c-variadic.rs new file mode 100644 index 00000000000..e6eebe4228e --- /dev/null +++ b/tests/ui/explicit-tail-calls/c-variadic.rs @@ -0,0 +1,14 @@ +#![expect(incomplete_features)] +#![feature(c_variadic, explicit_tail_calls)] +#![allow(unused)] + +unsafe extern "C" fn foo(mut ap: ...) -> u32 { + ap.arg::<u32>() +} + +extern "C" fn bar() -> u32 { + unsafe { become foo(1, 2, 3) } + //~^ ERROR c-variadic functions can't be tail-called +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/c-variadic.stderr b/tests/ui/explicit-tail-calls/c-variadic.stderr new file mode 100644 index 00000000000..5293339d218 --- /dev/null +++ b/tests/ui/explicit-tail-calls/c-variadic.stderr @@ -0,0 +1,8 @@ +error: c-variadic functions can't be tail-called + --> $DIR/c-variadic.rs:10:14 + | +LL | unsafe { become foo(1, 2, 3) } + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.rs b/tests/ui/feature-gates/feature-gate-c_variadic.rs index 45c68842093..88d91dbd081 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.rs +++ b/tests/ui/feature-gates/feature-gate-c_variadic.rs @@ -1,10 +1,10 @@ -#![crate_type="lib"] +#![crate_type = "lib"] -pub unsafe extern "C" fn test(_: i32, ap: ...) { } +pub unsafe extern "C" fn test(_: i32, ap: ...) {} //~^ ERROR C-variadic functions are unstable trait Trait { - unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + unsafe extern "C" fn trait_test(_: i32, ap: ...) {} //~^ ERROR C-variadic functions are unstable - //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~| ERROR associated functions cannot have a C variable argument list } diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.stderr b/tests/ui/feature-gates/feature-gate-c_variadic.stderr index e30a2f1ede3..808aa20948d 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.stderr +++ b/tests/ui/feature-gates/feature-gate-c_variadic.stderr @@ -1,14 +1,14 @@ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: associated functions cannot have a C variable argument list --> $DIR/feature-gate-c_variadic.rs:7:45 | -LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} | ^^^^^^^ error[E0658]: C-variadic functions are unstable --> $DIR/feature-gate-c_variadic.rs:3:1 | -LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information = help: add `#![feature(c_variadic)]` to the crate attributes to enable @@ -17,8 +17,8 @@ LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } error[E0658]: C-variadic functions are unstable --> $DIR/feature-gate-c_variadic.rs:7:5 | -LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information = help: add `#![feature(c_variadic)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-sanitize.rs b/tests/ui/feature-gates/feature-gate-sanitize.rs index 40098d93272..768417cfae8 100644 --- a/tests/ui/feature-gates/feature-gate-sanitize.rs +++ b/tests/ui/feature-gates/feature-gate-sanitize.rs @@ -1,4 +1,3 @@ -//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(no_sanitize)] //~ ERROR feature has been removed #[sanitize(address = "on")] diff --git a/tests/ui/feature-gates/feature-gate-sanitize.stderr b/tests/ui/feature-gates/feature-gate-sanitize.stderr index 7c38b351916..513999636a9 100644 --- a/tests/ui/feature-gates/feature-gate-sanitize.stderr +++ b/tests/ui/feature-gates/feature-gate-sanitize.stderr @@ -1,5 +1,5 @@ error[E0557]: feature has been removed - --> $DIR/feature-gate-sanitize.rs:2:12 + --> $DIR/feature-gate-sanitize.rs:1:12 | LL | #![feature(no_sanitize)] | ^^^^^^^^^^^ feature has been removed @@ -8,7 +8,7 @@ LL | #![feature(no_sanitize)] = note: renamed to sanitize(xyz = "on|off") error[E0658]: the `#[sanitize]` attribute is an experimental feature - --> $DIR/feature-gate-sanitize.rs:4:1 + --> $DIR/feature-gate-sanitize.rs:3:1 | LL | #[sanitize(address = "on")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-static_align.rs b/tests/ui/feature-gates/feature-gate-static_align.rs new file mode 100644 index 00000000000..4d8f0e18d94 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align.rs @@ -0,0 +1,11 @@ +#![crate_type = "lib"] + +#[rustc_align_static(16)] +//~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature +static REQUIRES_ALIGNMENT: u64 = 0; + +extern "C" { + #[rustc_align_static(16)] + //~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature + static FOREIGN_STATIC: u32; +} diff --git a/tests/ui/feature-gates/feature-gate-static_align.stderr b/tests/ui/feature-gates/feature-gate-static_align.stderr new file mode 100644 index 00000000000..b45fcdefc9c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-static_align.stderr @@ -0,0 +1,23 @@ +error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature + --> $DIR/feature-gate-static_align.rs:3:1 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information + = help: add `#![feature(static_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[rustc_align_static]` attribute is an experimental feature + --> $DIR/feature-gate-static_align.rs:8:5 + | +LL | #[rustc_align_static(16)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #146177 <https://github.com/rust-lang/rust/issues/146177> for more information + = help: add `#![feature(static_align)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index e5dae4c0069..546aa4052d3 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -539,26 +539,26 @@ mod macro_escape { #[no_std] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod no_std { + //~^ NOTE This attribute does not have an `!`, which means it is applied to this module mod inner { #![no_std] } -//~^ WARN crate-level attribute should be in the root module +//~^ WARN the `#![no_std]` attribute can only be used at the crate root #[no_std] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this function #[no_std] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this struct #[no_std] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias #[no_std] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block } // At time of authorship, #[proc_macro_derive = "2500"] signals error @@ -917,50 +917,50 @@ mod no_builtins { #[recursion_limit="0200"] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod recursion_limit { + //~^ NOTE This attribute does not have an `!`, which means it is applied to this module mod inner { #![recursion_limit="0200"] } -//~^ WARN crate-level attribute should be in the root module +//~^ WARN the `#![recursion_limit]` attribute can only be used at the crate root #[recursion_limit="0200"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this function #[recursion_limit="0200"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this struct #[recursion_limit="0200"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias #[recursion_limit="0200"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block } #[type_length_limit="0100"] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod type_length_limit { + //~^ NOTE This attribute does not have an `!`, which means it is applied to this module mod inner { #![type_length_limit="0100"] } -//~^ WARN crate-level attribute should be in the root module +//~^ WARN the `#![type_length_limit]` attribute can only be used at the crate root #[type_length_limit="0100"] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this function #[type_length_limit="0100"] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this struct #[type_length_limit="0100"] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this type alias #[type_length_limit="0100"] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block } fn main() {} diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index ef74a00e5a1..3c835be5cff 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -209,17 +209,6 @@ help: add a `!` LL | #![reexport_test_harness_main = "2900"] | + -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1 - | -LL | #[no_std] - | ^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_std] - | + - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:1 | @@ -291,28 +280,6 @@ help: add a `!` LL | #![no_builtins] | + -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1 - | -LL | #[recursion_limit="0200"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![recursion_limit="0200"] - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1 - | -LL | #[type_length_limit="0100"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![type_length_limit="0100"] - | + - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 | @@ -409,56 +376,6 @@ help: add a `!` LL | #![reexport_test_harness_main = "2900"] impl S { } | + -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17 - | -LL | mod inner { #![no_std] } - | ^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5 - | -LL | #[no_std] fn f() { } - | ^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_std] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5 - | -LL | #[no_std] struct S; - | ^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_std] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5 - | -LL | #[no_std] type T = S; - | ^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_std] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 - | -LL | #[no_std] impl S { } - | ^^^^^^^^^ - | -help: add a `!` - | -LL | #![no_std] impl S { } - | + - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17 | @@ -757,106 +674,6 @@ help: add a `!` LL | #![no_builtins] impl S { } | + -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17 - | -LL | mod inner { #![recursion_limit="0200"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 - | -LL | #[recursion_limit="0200"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![recursion_limit="0200"] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5 - | -LL | #[recursion_limit="0200"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![recursion_limit="0200"] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5 - | -LL | #[recursion_limit="0200"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![recursion_limit="0200"] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5 - | -LL | #[recursion_limit="0200"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![recursion_limit="0200"] impl S { } - | + - -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17 - | -LL | mod inner { #![type_length_limit="0100"] } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 - | -LL | #[type_length_limit="0100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![type_length_limit="0100"] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5 - | -LL | #[type_length_limit="0100"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![type_length_limit="0100"] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5 - | -LL | #[type_length_limit="0100"] type T = S; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![type_length_limit="0100"] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5 - | -LL | #[type_length_limit="0100"] impl S { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![type_length_limit="0100"] impl S { } - | + - warning: `#[macro_use]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 | @@ -1217,6 +1034,76 @@ LL | #[macro_escape] impl S { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[macro_escape]` can be applied to modules, extern crates, and crates +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:1 + | +LL | #[no_std] + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:1 + | +LL | / mod no_std { +LL | | +LL | | mod inner { #![no_std] } +... | +LL | | } + | |_^ + +warning: the `#![no_std]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:17 + | +LL | mod inner { #![no_std] } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:5 + | +LL | #[no_std] fn f() { } + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:15 + | +LL | #[no_std] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:5 + | +LL | #[no_std] struct S; + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:15 + | +LL | #[no_std] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:5 + | +LL | #[no_std] type T = S; + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:555:15 + | +LL | #[no_std] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_std]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 + | +LL | #[no_std] impl S { } + | ^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:15 + | +LL | #[no_std] impl S { } + | ^^^^^^^^^^ + warning: `#[cold]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:1 | @@ -1476,6 +1363,146 @@ note: This attribute does not have an `!`, which means it is applied to this imp LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:918:1 + | +LL | #[recursion_limit="0200"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:920:1 + | +LL | / mod recursion_limit { +LL | | +LL | | mod inner { #![recursion_limit="0200"] } +... | +LL | | } + | |_^ + +warning: the `#![recursion_limit]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:922:17 + | +LL | mod inner { #![recursion_limit="0200"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:5 + | +LL | #[recursion_limit="0200"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:925:31 + | +LL | #[recursion_limit="0200"] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:5 + | +LL | #[recursion_limit="0200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:929:31 + | +LL | #[recursion_limit="0200"] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:5 + | +LL | #[recursion_limit="0200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:933:31 + | +LL | #[recursion_limit="0200"] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:5 + | +LL | #[recursion_limit="0200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:937:31 + | +LL | #[recursion_limit="0200"] impl S { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:942:1 + | +LL | #[type_length_limit="0100"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:1 + | +LL | / mod type_length_limit { +LL | | +LL | | mod inner { #![type_length_limit="0100"] } +... | +LL | | } + | |_^ + +warning: the `#![type_length_limit]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:946:17 + | +LL | mod inner { #![type_length_limit="0100"] } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:5 + | +LL | #[type_length_limit="0100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:949:33 + | +LL | #[type_length_limit="0100"] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:5 + | +LL | #[type_length_limit="0100"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:953:33 + | +LL | #[type_length_limit="0100"] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:5 + | +LL | #[type_length_limit="0100"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:957:33 + | +LL | #[type_length_limit="0100"] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![type_length_limit]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:5 + | +LL | #[type_length_limit="0100"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:961:33 + | +LL | #[type_length_limit="0100"] impl S { } + | ^^^^^^^^^^ + warning: `#[should_panic]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 | diff --git a/tests/ui/fmt/ifmt-bad-arg.stderr b/tests/ui/fmt/ifmt-bad-arg.stderr index 4344aee83c2..b565b836f21 100644 --- a/tests/ui/fmt/ifmt-bad-arg.stderr +++ b/tests/ui/fmt/ifmt-bad-arg.stderr @@ -62,6 +62,11 @@ LL | format!("", 1, 2); | | | | | argument never used | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 2 format specifiers + | +LL | format!("{}{}", 1, 2); + | ++++ error: argument never used --> $DIR/ifmt-bad-arg.rs:33:22 @@ -102,6 +107,11 @@ LL | format!("", foo=2); | -- ^ named argument never used | | | formatting specifier missing + | +help: format specifiers use curly braces, consider adding a format specifier + | +LL | format!("{}", foo=2); + | ++ error: multiple unused formatting arguments --> $DIR/ifmt-bad-arg.rs:38:32 @@ -111,6 +121,8 @@ LL | format!("{} {}", 1, 2, foo=1, bar=2); | | | | | named argument never used | multiple missing formatting specifiers + | + = note: consider adding 2 format specifiers error: duplicate argument named `foo` --> $DIR/ifmt-bad-arg.rs:40:29 diff --git a/tests/ui/frontmatter/auxiliary/expr.rs b/tests/ui/frontmatter/auxiliary/expr.rs new file mode 100644 index 00000000000..5f694110666 --- /dev/null +++ b/tests/ui/frontmatter/auxiliary/expr.rs @@ -0,0 +1,4 @@ +--- +- +--- +1 diff --git a/tests/ui/frontmatter/auxiliary/makro.rs b/tests/ui/frontmatter/auxiliary/makro.rs index 70707b27bff..1d64fa44bd3 100644 --- a/tests/ui/frontmatter/auxiliary/makro.rs +++ b/tests/ui/frontmatter/auxiliary/makro.rs @@ -1,8 +1,20 @@ extern crate proc_macro; -use proc_macro::TokenStream; +use proc_macro::{Literal, TokenStream}; #[proc_macro] pub fn check(_: TokenStream) -> TokenStream { + // In the following test cases, the `---` may look like the start of frontmatter but it is not! + // That's because it would be backward incompatible to interpret them as such in the latest + // stable edition. That's not only the case due to the feature gate error but also due to the + // fact that we "eagerly" emit errors on malformed frontmatter. + + // issue: <https://github.com/rust-lang/rust/issues/145520> + _ = "---".parse::<TokenStream>(); + // Just a sequence of regular Rust punctuation tokens. assert_eq!(6, "---\n---".parse::<TokenStream>().unwrap().into_iter().count()); + + // issue: <https://github.com/rust-lang/rust/issues/146132> + assert!("---".parse::<Literal>().is_err()); + Default::default() } diff --git a/tests/ui/frontmatter/include-in-expr-ctxt.rs b/tests/ui/frontmatter/include-in-expr-ctxt.rs new file mode 100644 index 00000000000..7b02c9cb8a5 --- /dev/null +++ b/tests/ui/frontmatter/include-in-expr-ctxt.rs @@ -0,0 +1,9 @@ +// Check that an expr-ctxt `include` doesn't try to parse frontmatter and instead +// treats it as a regular Rust token sequence. +//@ check-pass +#![expect(double_negations)] + +fn main() { + // issue: <https://github.com/rust-lang/rust/issues/145945> + const _: () = assert!(-1 == include!("auxiliary/expr.rs")); +} diff --git a/tests/ui/frontmatter/include-in-item-ctxt.rs b/tests/ui/frontmatter/include-in-item-ctxt.rs new file mode 100644 index 00000000000..c8455bc49ab --- /dev/null +++ b/tests/ui/frontmatter/include-in-item-ctxt.rs @@ -0,0 +1,10 @@ +// Ensure that in item ctxts we can `include` files that contain frontmatter. +//@ check-pass + +#![feature(frontmatter)] + +include!("auxiliary/lib.rs"); + +fn main() { + foo(1); +} diff --git a/tests/ui/frontmatter/included-frontmatter.rs b/tests/ui/frontmatter/included-frontmatter.rs deleted file mode 100644 index 57616cd1228..00000000000 --- a/tests/ui/frontmatter/included-frontmatter.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![feature(frontmatter)] - -//@ check-pass - -include!("auxiliary/lib.rs"); - -// auxiliary/lib.rs contains a frontmatter. Ensure that we can use them in an -// `include!` macro. - -fn main() { - foo(1); -} diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/proc-macro-observer.rs index b1cc1460933..6c4c8c57289 100644 --- a/tests/ui/frontmatter/proc-macro-observer.rs +++ b/tests/ui/frontmatter/proc-macro-observer.rs @@ -2,10 +2,9 @@ //@ proc-macro: makro.rs //@ edition: 2021 -makro::check!(); +// Check that a proc-macro doesn't try to parse frontmatter and instead treats +// it as a regular Rust token sequence. See `auxiliary/makro.rs` for details. -// checks that a proc-macro doesn't know or parse frontmatters at all and instead treats -// it as normal Rust code. -// see auxiliary/makro.rs for how it is tested. +makro::check!(); fn main() {} diff --git a/tests/ui/issues/issue-56237.rs b/tests/ui/generics/generic-associated-type-deref-target-56237.rs index 3c0a235f3ec..2050ca377e8 100644 --- a/tests/ui/issues/issue-56237.rs +++ b/tests/ui/generics/generic-associated-type-deref-target-56237.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56237 //@ run-pass use std::ops::Deref; diff --git a/tests/ui/generics/post_monomorphization_error_backtrace.stderr b/tests/ui/generics/post_monomorphization_error_backtrace.stderr index 92c7df73638..6953414f0c2 100644 --- a/tests/ui/generics/post_monomorphization_error_backtrace.stderr +++ b/tests/ui/generics/post_monomorphization_error_backtrace.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0 - --> $DIR/post_monomorphization_error_backtrace.rs:6:31 + --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::<T>() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 @@ -17,10 +17,10 @@ LL | assert_zst::<U>() | ^^^^^^^^^^^^^^^^^ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0 - --> $DIR/post_monomorphization_error_backtrace.rs:6:31 + --> $DIR/post_monomorphization_error_backtrace.rs:6:23 | LL | const V: () = assert!(std::mem::size_of::<T>() == 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here note: erroneous constant encountered --> $DIR/post_monomorphization_error_backtrace.rs:14:5 diff --git a/tests/ui/issues/issue-55731.rs b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.rs index 7b4f4e2cd3b..978abd9fcf5 100644 --- a/tests/ui/issues/issue-55731.rs +++ b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/55731 use std::marker::PhantomData; trait DistributedIterator { diff --git a/tests/ui/issues/issue-55731.stderr b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr index 2c38041642d..40ac1d9d041 100644 --- a/tests/ui/issues/issue-55731.stderr +++ b/tests/ui/higher-ranked/hrtb-associated-type-leak-check-55731.stderr @@ -1,5 +1,5 @@ error: implementation of `DistributedIteratorMulti` is not general enough - --> $DIR/issue-55731.rs:48:5 + --> $DIR/hrtb-associated-type-leak-check-55731.rs:49:5 | LL | / multi(Map { LL | | i: Cloned(PhantomData), diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr new file mode 100644 index 00000000000..86ac1bdad04 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/avoid-inference-constraints-from-blanket-2.rs:27:18 + | +LL | let _: u32 = x; + | --- ^ expected `u32`, found `u64` + | | + | expected due to this + | +help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit + | +LL | let _: u32 = x.try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs new file mode 100644 index 00000000000..b4f853de4aa --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs @@ -0,0 +1,31 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[current] check-pass + +// Regression test for trait-system-refactor-initiative#205. Avoid +// constraining other impl arguments when applying blanket impls. + +// FIXME(-Znext-solver): This currently incompletely constrains the +// argument of `opaque: Trait<?x>` using the blanket impl of trait. +// Ideally we don't do that. + +trait Trait<T> {} + +impl<T> Trait<u64> for T {} +impl Trait<u32> for u64 {} + +fn impls_trait<T: Trait<U>, U>(_: U) -> T { + todo!() +} + +fn foo() -> impl Sized { + let x = Default::default(); + if false { + return impls_trait::<_, _>(x); + } + let _: u32 = x; + //[next]~^ ERROR mismatched types + 1u64 +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs new file mode 100644 index 00000000000..2f29cb4ee6b --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs @@ -0,0 +1,25 @@ +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +#![allow(unconditional_recursion)] + +// Regression test for trait-system-refactor-initiative#205. Avoid +// constraining other impl arguments when applying blanket impls, +// especially if the nested where-bounds of the blanket impl don't +// actually apply for the opaque. + +// FIXME(-Znext-solver): This currently incompletely constrains the +// argument of `opaque: Trait<?x>` using the blanket impl of trait. +// Ideally we don't do that. + +trait Trait<T> {} + +impl<T: Copy> Trait<u32> for T {} +impl Trait<u64> for String {} +fn impls_trait<T: Trait<U>, U>(_: T) {} + +fn test() -> impl Sized { + let x = test(); + impls_trait(x); //~ ERROR the trait bound `String: Trait<u32>` is not satisfied + String::new() +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr new file mode 100644 index 00000000000..a5d19b48481 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `String: Trait<u32>` is not satisfied + --> $DIR/avoid-inference-constraints-from-blanket-3.rs:22:5 + | +LL | impls_trait(x); + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + | + = help: the trait `Trait<u32>` is not implemented for `String` + but trait `Trait<u64>` is implemented for it + = help: for that trait implementation, expected `u64`, found `u32` +note: required for `String` to implement `Trait<u32>` + --> $DIR/avoid-inference-constraints-from-blanket-3.rs:16:15 + | +LL | impl<T: Copy> Trait<u32> for T {} + | ---- ^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `impls_trait` + --> $DIR/avoid-inference-constraints-from-blanket-3.rs:18:19 + | +LL | fn impls_trait<T: Trait<U>, U>(_: T) {} + | ^^^^^^^^ required by this bound in `impls_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs new file mode 100644 index 00000000000..bb3acfde5bc --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for trait-system-refactor-initiative#205. Avoid constraining +// the opaque type when applying blanket impls. + +trait Trait<T> {} + +impl<T> Trait<T> for T {} +impl Trait<u32> for u64 {} + +fn impls_trait<T: Trait<U>, U>() -> T { + todo!() +} + +fn foo() -> impl Sized { + if false { + // `opaque: Trait<u32>` shouldn't constrain `opaque` to `u32` via the blanket impl + return impls_trait::<_, u32>(); + } + 1u64 +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs new file mode 100644 index 00000000000..e7aaf6fa135 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs @@ -0,0 +1,23 @@ +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![allow(unconditional_recursion)] + +// Regression test for trait-system-refactor-initiative#182. If multiple +// opaque types result in different item bounds, do not apply them. + +trait Trait<T> {} +impl<T, U> Trait<T> for U {} + +fn impls_trait<T: Trait<U>, U>(_: T) -> U { + todo!() +} + +fn overlap<T, U>() -> (impl Trait<T>, impl Trait<U>) { + let mut x = overlap::<T, U>().0; + x = overlap::<T, U>().1; + let u = impls_trait(x); + let _: u32 = u; + ((), ()) +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs new file mode 100644 index 00000000000..d91efe181e3 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs @@ -0,0 +1,37 @@ +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![allow(unconditional_recursion)] + +// Regression test for trait-system-refactor-initiative#18, making sure +// we support being sub unified with more than 1 opaque type. + +trait Id { + type This; +} +impl Id for &'static str { + type This = &'static str; +} +fn to_assoc<T: Id>(x: T) -> <T as Id>::This { + todo!() +} + +fn mirror1() -> (impl Id<This = &'static str>, impl Sized) { + let mut opaque = mirror1().0; + opaque = mirror1().1; + let x = to_assoc(opaque); + // `?x` equals both opaques, make sure we still use the applicable + // item bound. + x.len(); + (x, x) +} +fn mirror2() -> (impl Sized, impl Id<This = &'static str>) { + let mut opaque = mirror2().0; + opaque = mirror2().1; + let x = to_assoc(opaque); + // `?x` equals both opaques, make sure we still use the applicable + // item bound. + x.len(); + (x, x) +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs b/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs new file mode 100644 index 00000000000..fca5db3e20f --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs @@ -0,0 +1,27 @@ +//@ compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![allow(unconditional_recursion)] + +// Test for trait-system-refactor-initiative#182 making sure +// that we don't incorrectly normalize to rigid aliases if the +// opaque type only has a trait bound. + +trait Id { + type This; +} +impl<T> Id for Vec<T> { + type This = Vec<T>; +} +fn to_assoc<T: Id>(x: T) -> <T as Id>::This { + todo!() +} + +fn mirror<T>(x: Vec<T>) -> impl Id { + let x = to_assoc(mirror(x)); + // `?x` equals `<opaque::<T> as Id>::This`. We should not infer `?x` + // to be a rigid alias here. + let _: Vec<u32> = x; + x +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs b/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs new file mode 100644 index 00000000000..50bb3995b94 --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs @@ -0,0 +1,19 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for trait-system-refactor-initiative#196. +fn iterator(b: bool) -> impl Iterator<Item = String> { + if b { + // We need to eagerly figure out the type of `i` here by using + // the `<opaque as IntoIterator>::Item` obligation. This means + // we not only have to consider item bounds, but also blanket impls. + for i in iterator(false) { + i.len(); + } + } + + vec![].into_iter() +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs b/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs new file mode 100644 index 00000000000..7c2766ade3f --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![allow(unconditional_recursion)] + +// Regression test for trait-system-refactor-initiative#182. + +trait Id { + type This; +} +impl<T> Id for T { + type This = T; +} +fn to_assoc<T>(x: T) -> <T as Id>::This { + x +} + +fn mirror<T>(x: Vec<T>) -> impl Id<This = Vec<T>> { + let x = to_assoc(mirror(x)); + // `?x` equals `<opaque::<T> as Id>::This`. We need to eagerly infer the + // type of `?x` to prevent this method call from resulting in an error. + // + // We could use both the item bound to normalize to `Vec<T>`, or the + // blanket impl to normalize to `opaque::<T>`. We have to go with the + // item bound. + x.len(); + x +} +fn main() {} diff --git a/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs b/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs new file mode 100644 index 00000000000..36dcbacbe6f --- /dev/null +++ b/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +#![allow(unconditional_recursion)] +// Regression test for trait-system-refactor-initiative#182. + +trait Id { + type This; +} +impl<T> Id for Vec<T> { + type This = Vec<T>; +} +fn to_assoc<T: Id>(x: T) -> <T as Id>::This { + todo!() +} + +fn mirror<T>(x: Vec<T>) -> impl Id<This = Vec<T>> { + let x = to_assoc(mirror(x)); + // `?x` equals `<opaque::<T> as Id>::This`. We need to eagerly infer the + // type of `?x` to prevent this method call from resulting in an error. + x.len(); + x +} +fn main() {} diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index 45df8cc9c0c..10e8dbf41cc 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -1,14 +1,24 @@ -error[E0282]: type annotations needed - --> $DIR/recursive-in-exhaustiveness.rs:19:17 +error[E0282]: type annotations needed for `(_,)` + --> $DIR/recursive-in-exhaustiveness.rs:19:9 | LL | let (x,) = (build(x),); - | ^^^^^^^^ cannot infer type + | ^^^^ + | +help: consider giving this pattern a type, where the placeholders `_` are specified + | +LL | let (x,): (_,) = (build(x),); + | ++++++ -error[E0282]: type annotations needed - --> $DIR/recursive-in-exhaustiveness.rs:29:17 +error[E0282]: type annotations needed for `((_,),)` + --> $DIR/recursive-in-exhaustiveness.rs:29:9 | LL | let (x,) = (build2(x),); - | ^^^^^^^^^ cannot infer type + | ^^^^ + | +help: consider giving this pattern a type, where the placeholders `_` are specified + | +LL | let (x,): ((_,),) = (build2(x),); + | +++++++++ error[E0282]: type annotations needed --> $DIR/recursive-in-exhaustiveness.rs:40:5 diff --git a/tests/ui/imports/auxiliary/reexported-trait-56175.rs b/tests/ui/imports/auxiliary/reexported-trait-56175.rs new file mode 100644 index 00000000000..51a991bef59 --- /dev/null +++ b/tests/ui/imports/auxiliary/reexported-trait-56175.rs @@ -0,0 +1,17 @@ +mod private { + pub trait Trait { + fn trait_method(&self) { + } + } + pub trait TraitB { + fn trait_method_b(&self) { + } + } +} + +pub struct FooStruct; +pub use crate::private::Trait; +impl crate::private::Trait for FooStruct {} + +pub use crate::private::TraitB as TraitBRename; +impl crate::private::TraitB for FooStruct {} diff --git a/tests/ui/issues/issue-56175.rs b/tests/ui/imports/private-types-suggested-without-extern-crate-56175.rs index daffe806a90..ce001edad1b 100644 --- a/tests/ui/issues/issue-56175.rs +++ b/tests/ui/imports/private-types-suggested-without-extern-crate-56175.rs @@ -1,5 +1,6 @@ +// https://github.com/rust-lang/rust/issues/56175 //@ edition:2018 -//@ aux-crate:reexported_trait=reexported-trait.rs +//@ aux-crate:reexported_trait=reexported-trait-56175.rs fn main() { reexported_trait::FooStruct.trait_method(); diff --git a/tests/ui/issues/issue-56175.stderr b/tests/ui/imports/private-types-suggested-without-extern-crate-56175.stderr index df4cd6ce8a7..1e8285c80ac 100644 --- a/tests/ui/issues/issue-56175.stderr +++ b/tests/ui/imports/private-types-suggested-without-extern-crate-56175.stderr @@ -1,10 +1,10 @@ error[E0599]: no method named `trait_method` found for struct `FooStruct` in the current scope - --> $DIR/issue-56175.rs:5:33 + --> $DIR/private-types-suggested-without-extern-crate-56175.rs:6:33 | LL | reexported_trait::FooStruct.trait_method(); | ^^^^^^^^^^^^ | - ::: $DIR/auxiliary/reexported-trait.rs:3:12 + ::: $DIR/auxiliary/reexported-trait-56175.rs:3:12 | LL | fn trait_method(&self) { | ------------ the method is available for `FooStruct` here @@ -12,7 +12,7 @@ LL | fn trait_method(&self) { = help: items from traits can only be used if the trait is in scope help: trait `Trait` which provides `trait_method` is implemented but not in scope; perhaps you want to import it | -LL + use reexported_trait::Trait; +LL + use reexported_trait_56175::Trait; | help: there is a method `trait_method_b` with a similar name | @@ -20,12 +20,12 @@ LL | reexported_trait::FooStruct.trait_method_b(); | ++ error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope - --> $DIR/issue-56175.rs:7:33 + --> $DIR/private-types-suggested-without-extern-crate-56175.rs:8:33 | LL | reexported_trait::FooStruct.trait_method_b(); | ^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/reexported-trait.rs:7:12 + ::: $DIR/auxiliary/reexported-trait-56175.rs:7:12 | LL | fn trait_method_b(&self) { | -------------- the method is available for `FooStruct` here @@ -33,7 +33,7 @@ LL | fn trait_method_b(&self) { = help: items from traits can only be used if the trait is in scope help: trait `TraitB` which provides `trait_method_b` is implemented but not in scope; perhaps you want to import it | -LL + use reexported_trait::TraitBRename; +LL + use reexported_trait_56175::TraitBRename; | help: there is a method `trait_method` with a similar name | diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.rs b/tests/ui/inference/note-and-explain-ReVar-124973.rs index f1e24645636..aa4b909fa76 100644 --- a/tests/ui/inference/note-and-explain-ReVar-124973.rs +++ b/tests/ui/inference/note-and-explain-ReVar-124973.rs @@ -3,6 +3,7 @@ #![feature(c_variadic)] async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {} -//~^ ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds +//~^ ERROR functions cannot be both `async` and C-variadic +//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds fn main() {} diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.stderr b/tests/ui/inference/note-and-explain-ReVar-124973.stderr index 574f6508e4c..964fbc4a4fb 100644 --- a/tests/ui/inference/note-and-explain-ReVar-124973.stderr +++ b/tests/ui/inference/note-and-explain-ReVar-124973.stderr @@ -1,3 +1,9 @@ +error: functions cannot be both `async` and C-variadic + --> $DIR/note-and-explain-ReVar-124973.rs:5:1 + | +LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {} + | ^^^^^ `async` because of this ^^^ C-variadic because of this + error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds --> $DIR/note-and-explain-ReVar-124973.rs:5:73 | @@ -8,6 +14,6 @@ LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {} | = note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/issues/auxiliary/issue-57271-lib.rs b/tests/ui/infinite/auxiliary/aux-57271-lib.rs index ff625668a9d..ff625668a9d 100644 --- a/tests/ui/issues/auxiliary/issue-57271-lib.rs +++ b/tests/ui/infinite/auxiliary/aux-57271-lib.rs diff --git a/tests/ui/issues/issue-57271.rs b/tests/ui/infinite/mutually-recursive-infinite-types-57271.rs index 20d081ecb3c..cb20770b486 100644 --- a/tests/ui/issues/issue-57271.rs +++ b/tests/ui/infinite/mutually-recursive-infinite-types-57271.rs @@ -1,8 +1,9 @@ -//@ aux-build:issue-57271-lib.rs +// https://github.com/rust-lang/rust/issues/57271 +//@ aux-build:aux-57271-lib.rs -extern crate issue_57271_lib; +extern crate aux_57271_lib; -use issue_57271_lib::BaseType; +use aux_57271_lib::BaseType; pub enum ObjectType { //~ ERROR recursive types `ObjectType` and `TypeSignature` have infinite size Class(ClassTypeSignature), diff --git a/tests/ui/issues/issue-57271.stderr b/tests/ui/infinite/mutually-recursive-infinite-types-57271.stderr index a61419c61d7..8bf1b470062 100644 --- a/tests/ui/issues/issue-57271.stderr +++ b/tests/ui/infinite/mutually-recursive-infinite-types-57271.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive types `ObjectType` and `TypeSignature` have infinite size - --> $DIR/issue-57271.rs:7:1 + --> $DIR/mutually-recursive-infinite-types-57271.rs:8:1 | LL | pub enum ObjectType { | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/inline-const/const-expr-generic-err.stderr b/tests/ui/inline-const/const-expr-generic-err.stderr index e053e88db17..26039ba6d44 100644 --- a/tests/ui/inline-const/const-expr-generic-err.stderr +++ b/tests/ui/inline-const/const-expr-generic-err.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0 - --> $DIR/const-expr-generic-err.rs:4:21 + --> $DIR/const-expr-generic-err.rs:4:13 | LL | const { assert!(std::mem::size_of::<T>() == 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-expr-generic-err.rs:4:5 diff --git a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs index cdf8aa85482..db2b4a6ad20 100644 --- a/tests/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/tests/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -5,9 +5,10 @@ //@ [strict]compile-flags: -Zstrict-init-checks //@ needs-subprocess //@ ignore-backends: gcc +//@ edition:2024 #![allow(deprecated, invalid_value)] -#![feature(never_type)] +#![feature(never_type, rustc_private)] use std::{ mem::{self, MaybeUninit, ManuallyDrop}, @@ -15,6 +16,9 @@ use std::{ num, }; +#[cfg(target_os = "linux")] +extern crate libc; + #[allow(dead_code)] struct Foo { x: u8, @@ -108,6 +112,17 @@ fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + 'static, msg: &st fn main() { unsafe { + #[cfg(target_os = "linux")] + { + // This test causes a large amount of crashes. If a system + // has a /proc/sys/kernel/core_pattern that uploads core dumps enabled, + // it will take a long time to complete. Set dumpable to 0 to avoid that. + if libc::prctl(libc::PR_SET_DUMPABLE, 0) < 0 { + let err = std::io::Error::last_os_error(); + panic!("failed to disable core dumps {err:?}"); + } + } + // Uninhabited types test_panic_msg( || mem::uninitialized::<!>(), diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr index 3048a59d0d0..4163d4e0602 100644 --- a/tests/ui/invalid-compile-flags/print-without-arg.stderr +++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr @@ -3,5 +3,5 @@ error: Argument to option 'print' missing --print <INFO>[=<FILE>] Compiler information to print on stdout (or to a file) INFO may be one of - <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models>. + <all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|target-spec-json-schema|tls-models>. diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index e3374eb1e6e..e8adbfd87d7 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,5 +1,5 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/issues/issue-56943.rs b/tests/ui/issues/issue-56943.rs deleted file mode 100644 index 9664567ec9e..00000000000 --- a/tests/ui/issues/issue-56943.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ aux-build:issue-56943.rs - -extern crate issue_56943; - -fn main() { - let _: issue_56943::S = issue_56943::S2; - //~^ ERROR mismatched types [E0308] -} diff --git a/tests/ui/iterators/ranges.stderr b/tests/ui/iterators/ranges.stderr index b9fbcd5304b..f85ce644073 100644 --- a/tests/ui/iterators/ranges.stderr +++ b/tests/ui/iterators/ranges.stderr @@ -8,15 +8,15 @@ LL | for _ in ..10 {} = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` = note: required for `RangeTo<{integer}>` to implement `IntoIterator` -error[E0277]: `RangeToInclusive<{integer}>` is not an iterator +error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator --> $DIR/ranges.rs:4:14 | LL | for _ in ..=10 {} | ^^^^^ if you meant to iterate until a value (including it), add a starting value | - = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = help: the trait `Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>` = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` - = note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator` + = note: required for `std::ops::RangeToInclusive<{integer}>` to implement `IntoIterator` error: aborting due to 2 previous errors diff --git a/tests/ui/issues/issue-57198-pass.rs b/tests/ui/keyword/raw-identifier-for-function-57198.rs index 06f30603c31..41a0cbf4619 100644 --- a/tests/ui/issues/issue-57198-pass.rs +++ b/tests/ui/keyword/raw-identifier-for-function-57198.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57198 //@ run-pass mod m { diff --git a/tests/ui/limits/huge-array-simple-64.stderr b/tests/ui/limits/huge-array-simple-64.full-debuginfo.stderr index 46df288d4f7..8ce93ab1884 100644 --- a/tests/ui/limits/huge-array-simple-64.stderr +++ b/tests/ui/limits/huge-array-simple-64.full-debuginfo.stderr @@ -1,5 +1,5 @@ error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture - --> $DIR/huge-array-simple-64.rs:7:9 + --> $DIR/huge-array-simple-64.rs:12:9 | LL | let _fat: [u8; (1<<61)+(1<<31)] = | ^^^^ diff --git a/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr b/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr new file mode 100644 index 00000000000..8ce93ab1884 --- /dev/null +++ b/tests/ui/limits/huge-array-simple-64.no-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `[u8; 2305843011361177600]` are too big for the target architecture + --> $DIR/huge-array-simple-64.rs:12:9 + | +LL | let _fat: [u8; (1<<61)+(1<<31)] = + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/huge-array-simple-64.rs b/tests/ui/limits/huge-array-simple-64.rs index d2838e0d41e..0c000940062 100644 --- a/tests/ui/limits/huge-array-simple-64.rs +++ b/tests/ui/limits/huge-array-simple-64.rs @@ -1,3 +1,8 @@ +// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2 +// NOTE: The .stderr for both revisions shall be identical. +//@ revisions: no-debuginfo full-debuginfo +//@[no-debuginfo] compile-flags: -Cdebuginfo=0 +//@[full-debuginfo] compile-flags: -Cdebuginfo=2 //@ build-fail //@ ignore-32bit diff --git a/tests/ui/limits/huge-array.stderr b/tests/ui/limits/huge-array.full-debuginfo.stderr index ce0c0d650c2..0a9c8c67ce9 100644 --- a/tests/ui/limits/huge-array.stderr +++ b/tests/ui/limits/huge-array.full-debuginfo.stderr @@ -1,5 +1,5 @@ error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the target architecture - --> $DIR/huge-array.rs:4:9 + --> $DIR/huge-array.rs:9:9 | LL | let s: [T; 1518600000] = [t; 1518600000]; | ^ diff --git a/tests/ui/limits/huge-array.no-debuginfo.stderr b/tests/ui/limits/huge-array.no-debuginfo.stderr new file mode 100644 index 00000000000..0a9c8c67ce9 --- /dev/null +++ b/tests/ui/limits/huge-array.no-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `[[u8; 1518599999]; 1518600000]` are too big for the target architecture + --> $DIR/huge-array.rs:9:9 + | +LL | let s: [T; 1518600000] = [t; 1518600000]; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/huge-array.rs b/tests/ui/limits/huge-array.rs index 97cfd1ff8fb..0cf59027694 100644 --- a/tests/ui/limits/huge-array.rs +++ b/tests/ui/limits/huge-array.rs @@ -1,3 +1,8 @@ +// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2 +// NOTE: The .stderr for both revisions shall be identical. +//@ revisions: no-debuginfo full-debuginfo +//@[no-debuginfo] compile-flags: -Cdebuginfo=0 +//@[full-debuginfo] compile-flags: -Cdebuginfo=2 //@ build-fail fn generic<T: Copy>(t: T) { diff --git a/tests/ui/limits/issue-15919-64.stderr b/tests/ui/limits/issue-15919-64.full-debuginfo.stderr index cd443f2065b..54434675d25 100644 --- a/tests/ui/limits/issue-15919-64.stderr +++ b/tests/ui/limits/issue-15919-64.full-debuginfo.stderr @@ -1,5 +1,5 @@ error: values of the type `[usize; usize::MAX]` are too big for the target architecture - --> $DIR/issue-15919-64.rs:5:9 + --> $DIR/issue-15919-64.rs:10:9 | LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; | ^ diff --git a/tests/ui/limits/issue-15919-64.no-debuginfo.stderr b/tests/ui/limits/issue-15919-64.no-debuginfo.stderr new file mode 100644 index 00000000000..54434675d25 --- /dev/null +++ b/tests/ui/limits/issue-15919-64.no-debuginfo.stderr @@ -0,0 +1,8 @@ +error: values of the type `[usize; usize::MAX]` are too big for the target architecture + --> $DIR/issue-15919-64.rs:10:9 + | +LL | let x = [0usize; 0xffff_ffff_ffff_ffff]; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/limits/issue-15919-64.rs b/tests/ui/limits/issue-15919-64.rs index 7e6200882a9..c1eee1d95ba 100644 --- a/tests/ui/limits/issue-15919-64.rs +++ b/tests/ui/limits/issue-15919-64.rs @@ -1,3 +1,8 @@ +// FIXME(#61117): Remove revisions once x86_64-gnu-debug CI job sets rust.debuginfo-level-tests=2 +// NOTE: The .stderr for both revisions shall be identical. +//@ revisions: no-debuginfo full-debuginfo +//@[no-debuginfo] compile-flags: -Cdebuginfo=0 +//@[full-debuginfo] compile-flags: -Cdebuginfo=2 //@ build-fail //@ ignore-32bit diff --git a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs index 92cb60bb16d..dac878c1cd9 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs @@ -20,4 +20,4 @@ pub fn lib_main() { unsafe { f(42); } } -//~? ERROR Dlltool could not create import library with +//~? ERROR dlltool could not create import library with diff --git a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr index 90cca83d1c1..5f3c29c3a21 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr @@ -1,4 +1,4 @@ -error: Dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX: +error: dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX: $DLLTOOL: Syntax error in def file $DEF_FILE:1␍ diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 203211d0d56..3a3b450f3c5 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -29,44 +29,6 @@ LL | #[no_link] | ^^^^^^^^^^ error: unused attribute - --> $DIR/unused-attr-duplicate.rs:21:1 - | -LL | #![recursion_limit = "256"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:20:1 - | -LL | #![recursion_limit = "128"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:24:1 - | -LL | #![type_length_limit = "1"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:23:1 - | -LL | #![type_length_limit = "1048576"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:27:1 - | -LL | #![no_std] - | ^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:26:1 - | -LL | #![no_std] - | ^^^^^^^^^^ - -error: unused attribute --> $DIR/unused-attr-duplicate.rs:31:1 | LL | #![windows_subsystem = "windows"] @@ -305,6 +267,44 @@ LL | #![crate_name = "unused_attr_duplicate"] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: unused attribute + --> $DIR/unused-attr-duplicate.rs:21:1 + | +LL | #![recursion_limit = "256"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:20:1 + | +LL | #![recursion_limit = "128"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:24:1 + | +LL | #![type_length_limit = "1"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:23:1 + | +LL | #![type_length_limit = "1048576"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:27:1 + | +LL | #![no_std] + | ^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:26:1 + | +LL | #![no_std] + | ^^^^^^^^^^ + +error: unused attribute --> $DIR/unused-attr-duplicate.rs:29:1 | LL | #![no_implicit_prelude] diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr index af64be8f6e9..0c6825026ed 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr +++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr @@ -1,19 +1,3 @@ -error: crate-level attribute should be an inner attribute - --> $DIR/unused-attr-macro-rules.rs:11:1 - | -LL | #[recursion_limit="1"] - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/unused-attr-macro-rules.rs:1:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ -help: add a `!` - | -LL | #![recursion_limit="1"] - | + - error: `#[macro_use]` attribute cannot be used on macro defs --> $DIR/unused-attr-macro-rules.rs:7:1 | @@ -22,6 +6,11 @@ LL | #[macro_use] | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[macro_use]` can be applied to modules, extern crates, and crates +note: the lint level is defined here + --> $DIR/unused-attr-macro-rules.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ error: `#[path]` attribute cannot be used on macro defs --> $DIR/unused-attr-macro-rules.rs:9:1 @@ -32,5 +21,19 @@ LL | #[path="foo"] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = help: `#[path]` can only be applied to modules +error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` + --> $DIR/unused-attr-macro-rules.rs:11:1 + | +LL | #[recursion_limit="1"] + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: This attribute does not have an `!`, which means it is applied to this macro def + --> $DIR/unused-attr-macro-rules.rs:12:1 + | +LL | / macro_rules! foo { +LL | | () => {}; +LL | | } + | |_^ + error: aborting due to 3 previous errors diff --git a/tests/ui/macros/assert-desugaring-145770.rs b/tests/ui/macros/assert-desugaring-145770.rs new file mode 100644 index 00000000000..d56e771ecfb --- /dev/null +++ b/tests/ui/macros/assert-desugaring-145770.rs @@ -0,0 +1,23 @@ +//! Regression test for #145770. +//! +//! Changing the `assert!` desugaring from an `if !cond {}` to `match` expression is +//! backwards-incompatible, and may need to be done over an edition boundary or limit editions for +//! which the desguaring change impacts. + +//@ check-pass + +#[derive(Debug)] +struct F { + data: bool +} + +impl std::ops::Not for F { + type Output = bool; + fn not(self) -> Self::Output { !self.data } +} + +fn main() { + let f = F { data: true }; + + assert!(f); +} diff --git a/tests/ui/macros/assert-macro-lifetimes.rs b/tests/ui/macros/assert-macro-lifetimes.rs deleted file mode 100644 index cc259283204..00000000000 --- a/tests/ui/macros/assert-macro-lifetimes.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass -#[derive(PartialEq, Eq, Hash)] -struct S; -fn main() { - let foo = std::rc::Rc::new(std::cell::RefCell::new(std::collections::HashMap::<S, S>::new())); - // Ensure that the lifetimes of the borrow do not leak past the end of `main`. - assert!(matches!(foo.borrow().get(&S).unwrap(), S)) -} diff --git a/tests/ui/macros/format-unused-lables.stderr b/tests/ui/macros/format-unused-lables.stderr index fad87fa2aee..90eed8dd86b 100644 --- a/tests/ui/macros/format-unused-lables.stderr +++ b/tests/ui/macros/format-unused-lables.stderr @@ -7,6 +7,11 @@ LL | println!("Test", 123, 456, 789); | | | argument never used | | argument never used | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 3 format specifiers + | +LL | println!("Test{}{}{}", 123, 456, 789); + | ++++++ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:6:9 @@ -19,6 +24,11 @@ LL | 456, | ^^^ argument never used LL | 789 | ^^^ argument never used + | +help: format specifiers use curly braces, consider adding 3 format specifiers + | +LL | println!("Test2{}{}{}", + | ++++++ error: named argument never used --> $DIR/format-unused-lables.rs:11:35 @@ -27,6 +37,11 @@ LL | println!("Some stuff", UNUSED="args"); | ------------ ^^^^^^ named argument never used | | | formatting specifier missing + | +help: format specifiers use curly braces, consider adding a format specifier + | +LL | println!("Some stuff{}", UNUSED="args"); + | ++ error: multiple unused formatting arguments --> $DIR/format-unused-lables.rs:14:9 diff --git a/tests/ui/macros/issue-61053-duplicate-binder.stderr b/tests/ui/macros/issue-61053-duplicate-binder.stderr index 7c7cb26b407..1ecbc3f86d0 100644 --- a/tests/ui/macros/issue-61053-duplicate-binder.stderr +++ b/tests/ui/macros/issue-61053-duplicate-binder.stderr @@ -2,9 +2,9 @@ error: duplicate matcher binding --> $DIR/issue-61053-duplicate-binder.rs:7:20 | LL | ($x:tt $x:tt) => { $x }; - | -- ^^ + | -- ^^ duplicate binding | | - | previous declaration + | previous binding | note: the lint level is defined here --> $DIR/issue-61053-duplicate-binder.rs:1:9 diff --git a/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs b/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs index 695a752fe17..5ac50c943d0 100644 --- a/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs +++ b/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs @@ -92,6 +92,12 @@ macro_rules! combinations { }}; } +macro_rules! int_struct { + ($n: literal) => { + struct ${concat(E, $n)}; + } +} + fn main() { create_things!(behold); behold_separated_idents_in_a_fn(); @@ -112,4 +118,16 @@ fn main() { assert_eq!(VAR_123, 2); combinations!(_hello, "a", b, "b"); + + int_struct!(1_0); + int_struct!(2); + int_struct!(3___0); + int_struct!(7_); + int_struct!(08); + + let _ = E1_0; + let _ = E2; + let _ = E3___0; + let _ = E7_; + let _ = E08; } diff --git a/tests/ui/macros/metavar-expressions/concat-usage-errors.rs b/tests/ui/macros/metavar-expressions/concat-usage-errors.rs index 7d8756de9e2..277ad240b1b 100644 --- a/tests/ui/macros/metavar-expressions/concat-usage-errors.rs +++ b/tests/ui/macros/metavar-expressions/concat-usage-errors.rs @@ -140,7 +140,9 @@ macro_rules! bad_literal_non_string { //~| ERROR metavariables of `${concat(..)}` must be of type //~| ERROR metavariables of `${concat(..)}` must be of type //~| ERROR metavariables of `${concat(..)}` must be of type - //~| ERROR metavariables of `${concat(..)}` must be of type + //~| ERROR floats are not supported as metavariables of `${concat(..)}` + //~| ERROR integer metavariables of `${concat(..)}` must not be suffixed + //~| ERROR integer metavariables of `${concat(..)}` must not be suffixed } } @@ -149,7 +151,6 @@ macro_rules! bad_tt_literal { const ${concat(_foo, $tt)}: () = (); //~^ ERROR metavariables of `${concat(..)}` must be of type //~| ERROR metavariables of `${concat(..)}` must be of type - //~| ERROR metavariables of `${concat(..)}` must be of type } } @@ -178,13 +179,14 @@ fn main() { bad_literal_string!("1.0"); bad_literal_string!("'1'"); - bad_literal_non_string!(1); bad_literal_non_string!(-1); bad_literal_non_string!(1.0); bad_literal_non_string!('1'); bad_literal_non_string!(false); + bad_literal_non_string!(4f64); + bad_literal_non_string!(5u8); + bad_literal_non_string!(6_u8); - bad_tt_literal!(1); bad_tt_literal!(1.0); bad_tt_literal!('1'); } diff --git a/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr b/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr index 8be3e792ec3..c124b76cb78 100644 --- a/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr +++ b/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr @@ -130,7 +130,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t LL | ${concat($ex, aaaa)} | ^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported error: variable `foo` is not recognized in meta-variable expression --> $DIR/concat-usage-errors.rs:37:30 @@ -276,7 +276,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t LL | const ${concat(_foo, $literal)}: () = (); | ^^^^^^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` --> $DIR/concat-usage-errors.rs:138:31 @@ -284,7 +284,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t LL | const ${concat(_foo, $literal)}: () = (); | ^^^^^^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` @@ -293,7 +293,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t LL | const ${concat(_foo, $literal)}: () = (); | ^^^^^^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` @@ -302,43 +302,45 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t LL | const ${concat(_foo, $literal)}: () = (); | ^^^^^^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` +error: floats are not supported as metavariables of `${concat(..)}` --> $DIR/concat-usage-errors.rs:138:31 | LL | const ${concat(_foo, $literal)}: () = (); | ^^^^^^^ + +error: integer metavariables of `${concat(..)}` must not be suffixed + --> $DIR/concat-usage-errors.rs:138:31 | - = note: currently only string literals are supported - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^ -error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` - --> $DIR/concat-usage-errors.rs:149:31 +error: integer metavariables of `${concat(..)}` must not be suffixed + --> $DIR/concat-usage-errors.rs:138:31 | -LL | const ${concat(_foo, $tt)}: () = (); - | ^^ +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^ | - = note: currently only string literals are supported + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` - --> $DIR/concat-usage-errors.rs:149:31 + --> $DIR/concat-usage-errors.rs:151:31 | LL | const ${concat(_foo, $tt)}: () = (); | ^^ | - = note: currently only string literals are supported - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: currently only string and integer literals are supported error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` - --> $DIR/concat-usage-errors.rs:149:31 + --> $DIR/concat-usage-errors.rs:151:31 | LL | const ${concat(_foo, $tt)}: () = (); | ^^ | - = note: currently only string literals are supported + = note: currently only string and integer literals are supported = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 43 previous errors +error: aborting due to 44 previous errors diff --git a/tests/ui/mir/alignment/packed.rs b/tests/ui/mir/alignment/packed.rs index aa79880a21a..cf908365e1a 100644 --- a/tests/ui/mir/alignment/packed.rs +++ b/tests/ui/mir/alignment/packed.rs @@ -12,7 +12,7 @@ fn main() { // Test that we can use addr_of! to get the address of a packed member which according to its // type is not aligned, but because it is a projection from a packed type is a valid place. let ptr0 = std::ptr::addr_of!(memory[0].tail); - let ptr1 = std::ptr::addr_of!(memory[1].tail); + let ptr1 = std::ptr::addr_of!(memory[0].tail); // Even if ptr0 happens to be aligned by chance, ptr1 is not. assert!(!ptr0.is_aligned() || !ptr1.is_aligned()); diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs index 9277994d9b3..dc0d14bf9d6 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs @@ -4,7 +4,6 @@ fn main() {} -fn foo(_: Bar, ...) -> impl {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention -//~| ERROR cannot find type `Bar` in this scope +unsafe extern "C" fn foo(_: Bar, ...) -> impl {} +//~^ ERROR cannot find type `Bar` in this scope //~| ERROR at least one trait must be specified diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr index 4a1aa49eb6e..31a393e7367 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -1,21 +1,15 @@ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16 - | -LL | fn foo(_: Bar, ...) -> impl {} - | ^^^ - error: at least one trait must be specified - --> $DIR/issue-83499-input-output-iteration-ice.rs:7:24 + --> $DIR/issue-83499-input-output-iteration-ice.rs:7:42 | -LL | fn foo(_: Bar, ...) -> impl {} - | ^^^^ +LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {} + | ^^^^ error[E0412]: cannot find type `Bar` in this scope - --> $DIR/issue-83499-input-output-iteration-ice.rs:7:11 + --> $DIR/issue-83499-input-output-iteration-ice.rs:7:29 | -LL | fn foo(_: Bar, ...) -> impl {} - | ^^^ not found in this scope +LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {} + | ^^^ not found in this scope -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/mir/unsized-extern-static.stderr b/tests/ui/mir/unsized-extern-static.stderr index 93aed3549d7..c0810e650ef 100644 --- a/tests/ui/mir/unsized-extern-static.stderr +++ b/tests/ui/mir/unsized-extern-static.stderr @@ -5,6 +5,11 @@ LL | println!("C", unsafe { &symbol }); | --- ^^^^^^^^^^^^^^^^^^ argument never used | | | formatting specifier missing + | +help: format specifiers use curly braces, consider adding a format specifier + | +LL | println!("C{}", unsafe { &symbol }); + | ++ error[E0277]: the size for values of type `[i8]` cannot be known at compilation time --> $DIR/unsized-extern-static.rs:6:5 diff --git a/tests/ui/issues/auxiliary/issue-56943.rs b/tests/ui/mismatched_types/auxiliary/aux-56943.rs index 65b9beb91f9..65b9beb91f9 100644 --- a/tests/ui/issues/auxiliary/issue-56943.rs +++ b/tests/ui/mismatched_types/auxiliary/aux-56943.rs diff --git a/tests/ui/mismatched_types/type-mismatch-in-extern-crate-56943.rs b/tests/ui/mismatched_types/type-mismatch-in-extern-crate-56943.rs new file mode 100644 index 00000000000..9970b27c847 --- /dev/null +++ b/tests/ui/mismatched_types/type-mismatch-in-extern-crate-56943.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust/issues/56943 +//@ aux-build:aux-56943.rs + +extern crate aux_56943; + +fn main() { + let _: aux_56943::S = aux_56943::S2; + //~^ ERROR mismatched types [E0308] +} diff --git a/tests/ui/issues/issue-56943.stderr b/tests/ui/mismatched_types/type-mismatch-in-extern-crate-56943.stderr index 60a2e92dc71..2315267701d 100644 --- a/tests/ui/issues/issue-56943.stderr +++ b/tests/ui/mismatched_types/type-mismatch-in-extern-crate-56943.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types - --> $DIR/issue-56943.rs:6:29 + --> $DIR/type-mismatch-in-extern-crate-56943.rs:7:27 | -LL | let _: issue_56943::S = issue_56943::S2; - | -------------- ^^^^^^^^^^^^^^^ expected `S`, found `S2` +LL | let _: aux_56943::S = aux_56943::S2; + | ------------ ^^^^^^^^^^^^^ expected `S`, found `S2` | | | expected due to this diff --git a/tests/ui/issues/issue-56128.rs b/tests/ui/modules/pub-use-handling-in-modules-56128.rs index cc170f60250..cc170f60250 100644 --- a/tests/ui/issues/issue-56128.rs +++ b/tests/ui/modules/pub-use-handling-in-modules-56128.rs diff --git a/tests/ui/new-range/disabled.rs b/tests/ui/new-range/disabled.rs index 1a5fe3f9743..6ba29f5ca9a 100644 --- a/tests/ui/new-range/disabled.rs +++ b/tests/ui/new-range/disabled.rs @@ -6,20 +6,20 @@ fn main() { // Unchanged let a: core::range::RangeFull = ..; let b: core::range::RangeTo<u8> = ..2; - let c: core::range::RangeToInclusive<u8> = ..=3; let _: core::ops::RangeFull = a; let _: core::ops::RangeTo<u8> = b; - let _: core::ops::RangeToInclusive<u8> = c; // Changed let a: core::range::legacy::RangeFrom<u8> = 1..; let b: core::range::legacy::Range<u8> = 2..3; let c: core::range::legacy::RangeInclusive<u8> = 4..=5; + let d: core::range::legacy::RangeToInclusive<u8> = ..=3; let a: core::ops::RangeFrom<u8> = a; let b: core::ops::Range<u8> = b; let c: core::ops::RangeInclusive<u8> = c; + let d: core::ops::RangeToInclusive<u8> = d; let _: core::ops::RangeFrom<u8> = a.into_iter(); let _: core::ops::Range<u8> = b.into_iter(); diff --git a/tests/ui/new-range/enabled.rs b/tests/ui/new-range/enabled.rs index a5fb76ad52b..5ddbba492e7 100644 --- a/tests/ui/new-range/enabled.rs +++ b/tests/ui/new-range/enabled.rs @@ -7,18 +7,18 @@ fn main() { // Unchanged let a: core::range::RangeFull = ..; let b: core::range::RangeTo<u8> = ..2; - let c: core::range::RangeToInclusive<u8> = ..=3; let _: core::ops::RangeFull = a; let _: core::ops::RangeTo<u8> = b; - let _: core::ops::RangeToInclusive<u8> = c; // Changed let a: core::range::RangeFrom<u8> = 1..; let b: core::range::Range<u8> = 2..3; let c: core::range::RangeInclusive<u8> = 4..=5; + let d: core::range::RangeToInclusive<u8> = ..=3; let _: core::range::IterRangeFrom<u8> = a.into_iter(); let _: core::range::IterRange<u8> = b.into_iter(); let _: core::range::IterRangeInclusive<u8> = c.into_iter(); + // RangeToInclusive has no Iterator implementation } diff --git a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs new file mode 100644 index 00000000000..a5084b55aac --- /dev/null +++ b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs @@ -0,0 +1,33 @@ +#![feature(proc_macro_quote, proc_macro_span)] + +extern crate proc_macro; + +use proc_macro::{Ident, Literal, Span, TokenStream, TokenTree, quote}; + +#[proc_macro] +pub fn bad_tup_indexing(input: TokenStream) -> TokenStream { + let tt = input.into_iter().next().unwrap(); + let TokenTree::Literal(indexing_expr) = tt else { + unreachable!(); + }; + quote! { (42,).$indexing_expr } +} + +// Expects {IDENT, COMMA, LITERAL} +#[proc_macro] +pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream { + let mut input = input.into_iter(); + + let ident = input.next().unwrap(); + let _comma = input.next().unwrap(); + let lit = input.next().unwrap(); + + let TokenTree::Ident(ident) = ident else { + unreachable!("id"); + }; + let TokenTree::Literal(indexing_expr) = lit else { + unreachable!("lit"); + }; + + quote! { $ident.$indexing_expr } +} diff --git a/tests/ui/issues/issue-55587.rs b/tests/ui/parser/invalid-variable-definition-55587.rs index d9100cf555b..f2c7c0a8e6c 100644 --- a/tests/ui/issues/issue-55587.rs +++ b/tests/ui/parser/invalid-variable-definition-55587.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/55587 use std::path::Path; fn main() { diff --git a/tests/ui/issues/issue-55587.stderr b/tests/ui/parser/invalid-variable-definition-55587.stderr index 7a5d0e28100..08c951582e3 100644 --- a/tests/ui/issues/issue-55587.stderr +++ b/tests/ui/parser/invalid-variable-definition-55587.stderr @@ -1,5 +1,5 @@ error[E0164]: expected tuple struct or tuple variant, found associated function `Path::new` - --> $DIR/issue-55587.rs:4:9 + --> $DIR/invalid-variable-definition-55587.rs:5:9 | LL | let Path::new(); | ^^^^^^^^^^^ `fn` calls are not allowed in patterns diff --git a/tests/ui/parser/issues/issue-59418.rs b/tests/ui/parser/issues/issue-59418.rs deleted file mode 100644 index 0fa191d4a7e..00000000000 --- a/tests/ui/parser/issues/issue-59418.rs +++ /dev/null @@ -1,18 +0,0 @@ -struct X(i32,i32,i32); - -fn main() { - let a = X(1, 2, 3); - let b = a.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", b); - let c = (1, 2, 3); - let d = c.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", d); - let s = X { 0suffix: 0, 1: 1, 2: 2 }; - //~^ ERROR suffixes on a tuple index are invalid - match s { - X { 0suffix: _, .. } => {} - //~^ ERROR suffixes on a tuple index are invalid - } -} diff --git a/tests/ui/parser/issues/issue-59418.stderr b/tests/ui/parser/issues/issue-59418.stderr deleted file mode 100644 index 347051e9f92..00000000000 --- a/tests/ui/parser/issues/issue-59418.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:5:15 - | -LL | let b = a.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:9:15 - | -LL | let d = c.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:12:17 - | -LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:15:13 - | -LL | X { 0suffix: _, .. } => {} - | ^^^^^^^ invalid suffix `suffix` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs new file mode 100644 index 00000000000..557c67738d3 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -0,0 +1,32 @@ +//! See #59418. +//! +//! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction. + +//@ proc-macro: tuple-index-suffix-proc-macro-aux.rs + +extern crate tuple_index_suffix_proc_macro_aux; +use tuple_index_suffix_proc_macro_aux as aux; + +fn main() { + struct TupStruct(i32); + let tup_struct = TupStruct(42); + + // Previously, #60186 had carve outs for `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. Now, + // they all hard error. + + aux::bad_tup_indexing!(0usize); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0isize); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of the #60186 carve outs. + + aux::bad_tup_indexing!(0u8); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0u64); + //~^ ERROR suffixes on a tuple index are invalid + + // NOTE: didn't bother with trying to figure out how to generate `struct P { 0u32: u32 }` using + // *only* `proc_macro` without help with `syn`/`quote`, looks like you can't with just + // `proc_macro::quote`? +} diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr new file mode 100644 index 00000000000..47d179d3555 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -0,0 +1,26 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:17:28 + | +LL | aux::bad_tup_indexing!(0usize); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:19:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:24:28 + | +LL | aux::bad_tup_indexing!(0u8); + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:26:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); + | ^^^^ invalid suffix `u64` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/tuple-index-suffix.rs b/tests/ui/parser/tuple-index-suffix.rs new file mode 100644 index 00000000000..c4769500005 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.rs @@ -0,0 +1,79 @@ +//! Regression test for both the original regression in #59418 where invalid suffixes in indexing +//! positions were accidentally accepted, and also for the removal of the temporary carve out that +//! mitigated ecosystem impact following trying to reject #59418 (this was implemented as a FCW +//! tracked in #60210). +//! +//! Check that we hard error on invalid suffixes in tuple indexing subexpressions and struct numeral +//! field names. + +struct X(i32,i32,i32); + +fn main() { + let tup_struct = X(1, 2, 3); + let invalid_tup_struct_suffix = tup_struct.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + //~^ ERROR suffixes on a tuple index are invalid + + let tup = (1, 2, 3); + let invalid_tup_suffix = tup.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_suffix = tup.0u32; + //~^ ERROR suffixes on a tuple index are invalid + + numeral_struct_field_name_suffix_invalid(); + numeral_struct_field_name_suffix_previous_carve_out(); +} + +// Previously, there were very limited carve outs as a ecosystem impact mitigation implemented in +// #60186. *Only* `{i,u}{32,usize}` suffixes were temporarily accepted. Now, they all hard error. +fn previous_carve_outs() { + // Previously temporarily accepted by a pseudo-FCW (#60210), now hard error. + + let previous_carve_out_i32 = (42,).0i32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_i32 = (42,).0u32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_isize = (42,).0isize; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_usize = (42,).0usize; //~ ERROR suffixes on a tuple index are invalid + + // Not part of the carve outs! + let error_i8 = (42,).0i8; //~ ERROR suffixes on a tuple index are invalid + let error_u8 = (42,).0u8; //~ ERROR suffixes on a tuple index are invalid + let error_i16 = (42,).0i16; //~ ERROR suffixes on a tuple index are invalid + let error_u16 = (42,).0u16; //~ ERROR suffixes on a tuple index are invalid + let error_i64 = (42,).0i64; //~ ERROR suffixes on a tuple index are invalid + let error_u64 = (42,).0u64; //~ ERROR suffixes on a tuple index are invalid + let error_i128 = (42,).0i128; //~ ERROR suffixes on a tuple index are invalid + let error_u128 = (42,).0u128; //~ ERROR suffixes on a tuple index are invalid +} + +fn numeral_struct_field_name_suffix_invalid() { + let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match invalid_struct_name { + X { 0suffix: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +fn numeral_struct_field_name_suffix_previous_carve_out() { + let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match carve_out_struct_name { + X { 0u32: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +// Unfortunately, it turns out `std::mem::offset_of!` uses the same expect suffix code path. +fn offset_of_suffix() { + #[repr(C)] + pub struct Struct<T>(u8, T); + + // Previous pseudo-FCW carve outs + assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of carve outs + assert_eq!(std::mem::offset_of!(Struct<u32>, 0u8), 0); + //~^ ERROR suffixes on a tuple index are invalid +} diff --git a/tests/ui/parser/tuple-index-suffix.stderr b/tests/ui/parser/tuple-index-suffix.stderr new file mode 100644 index 00000000000..6d96c6d3cbf --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.stderr @@ -0,0 +1,134 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:13:48 + | +LL | let invalid_tup_struct_suffix = tup_struct.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:15:59 + | +LL | let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:19:34 + | +LL | let invalid_tup_suffix = tup.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:21:45 + | +LL | let previous_carve_out_tup_suffix = tup.0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:33:40 + | +LL | let previous_carve_out_i32 = (42,).0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:34:40 + | +LL | let previous_carve_out_i32 = (42,).0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:35:42 + | +LL | let previous_carve_out_isize = (42,).0isize; + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:36:42 + | +LL | let previous_carve_out_usize = (42,).0usize; + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:39:26 + | +LL | let error_i8 = (42,).0i8; + | ^^^ invalid suffix `i8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:40:26 + | +LL | let error_u8 = (42,).0u8; + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:41:27 + | +LL | let error_i16 = (42,).0i16; + | ^^^^ invalid suffix `i16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:42:27 + | +LL | let error_u16 = (42,).0u16; + | ^^^^ invalid suffix `u16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:43:27 + | +LL | let error_i64 = (42,).0i64; + | ^^^^ invalid suffix `i64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:44:27 + | +LL | let error_u64 = (42,).0u64; + | ^^^^ invalid suffix `u64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:45:28 + | +LL | let error_i128 = (42,).0i128; + | ^^^^^ invalid suffix `i128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:46:28 + | +LL | let error_u128 = (42,).0u128; + | ^^^^^ invalid suffix `u128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:50:35 + | +LL | let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:53:13 + | +LL | X { 0suffix: _, .. } => {} + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:59:37 + | +LL | let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:62:13 + | +LL | X { 0u32: _, .. } => {} + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:73:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct<u32>, 0usize), 0); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:77:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct<u32>, 0u8), 0); + | ^^^ invalid suffix `u8` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 243924e6c53..4db056f15a5 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -4,25 +4,28 @@ fn main() {} fn f1_1(x: isize, ...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR `...` is not supported for non-extern functions fn f1_2(...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR `...` is not supported for non-extern functions + +unsafe extern "Rust" fn f1_3(...) {} +//~^ ERROR `...` is not supported for `extern "Rust"` functions extern "C" fn f2_1(x: isize, ...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f2_2(...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f2_3(..., x: isize) {} //~^ ERROR `...` must be the last argument of a C-variadic function extern "C" fn f3_1(x: isize, ...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f3_2(...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f3_3(..., x: isize) {} //~^ ERROR `...` must be the last argument of a C-variadic function @@ -33,12 +36,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {} const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~| ERROR functions with a C variable argument list must be unsafe //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(..., x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~| ERROR functions with a C variable argument list must be unsafe //~| ERROR `...` must be the last argument of a C-variadic function extern "C" { @@ -50,30 +53,30 @@ struct X; impl X { fn i_f1(x: isize, ...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn i_f2(...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn i_f3(..., x: isize, ...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list //~| ERROR `...` must be the last argument of a C-variadic function fn i_f4(..., x: isize, ...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list //~| ERROR `...` must be the last argument of a C-variadic function const fn i_f5(x: isize, ...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list //~| ERROR functions cannot be both `const` and C-variadic //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time } trait T { fn t_f1(x: isize, ...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn t_f2(x: isize, ...); - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn t_f3(...) {} - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn t_f4(...); - //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + //~^ ERROR associated functions cannot have a C variable argument list fn t_f5(..., x: isize) {} //~^ ERROR `...` must be the last argument of a C-variadic function fn t_f6(..., x: isize); diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index 5c55cc38b56..0cd78318de6 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -1,181 +1,225 @@ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: `...` is not supported for non-extern functions --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19 | LL | fn f1_1(x: isize, ...) {} | ^^^ + | + = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: `...` is not supported for non-extern functions --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9 | LL | fn f1_2(...) {} | ^^^ + | + = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: `...` is not supported for `extern "Rust"` functions --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | +LL | unsafe extern "Rust" fn f1_3(...) {} + | ------------- ^^^ + | | + | `extern "Rust"` because of this + | + = help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:15:30 + | LL | extern "C" fn f2_1(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f2_1(x: isize, ...) {} + | ++++++ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 | LL | extern "C" fn f2_2(...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f2_2(...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 + --> $DIR/variadic-ffi-semantic-restrictions.rs:21:20 | LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30 +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:24:30 | LL | extern "C" fn f3_1(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f3_1(x: isize, ...) {} + | ++++++ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20 +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20 | LL | extern "C" fn f3_2(...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f3_2(...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20 + --> $DIR/variadic-ffi-semantic-restrictions.rs:30:20 | LL | extern "C" fn f3_3(..., x: isize) {} | ^^^ error: functions cannot be both `const` and C-variadic - --> $DIR/variadic-ffi-semantic-restrictions.rs:30:1 + --> $DIR/variadic-ffi-semantic-restrictions.rs:33:1 | LL | const unsafe extern "C" fn f4_1(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this error: functions cannot be both `const` and C-variadic - --> $DIR/variadic-ffi-semantic-restrictions.rs:34:1 + --> $DIR/variadic-ffi-semantic-restrictions.rs:37:1 | LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36 +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | const unsafe extern "C" fn f4_2(x: isize, ...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:39:26 + --> $DIR/variadic-ffi-semantic-restrictions.rs:42:26 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^ error: functions cannot be both `const` and C-variadic - --> $DIR/variadic-ffi-semantic-restrictions.rs:39:1 + --> $DIR/variadic-ffi-semantic-restrictions.rs:42:1 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41 +error: functions with a C variable argument list must be unsafe + --> $DIR/variadic-ffi-semantic-restrictions.rs:42:41 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | const unsafe extern "C" fn f4_3(..., x: isize, ...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:45:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:48:13 | LL | fn e_f2(..., x: isize); | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:52:23 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:55:23 | LL | fn i_f1(x: isize, ...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:57:13 | LL | fn i_f2(...) {} | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13 | LL | fn i_f3(..., x: isize, ...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:56:28 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28 | LL | fn i_f3(..., x: isize, ...) {} | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:62:13 | LL | fn i_f4(..., x: isize, ...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:59:28 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:62:28 | LL | fn i_f4(..., x: isize, ...) {} | ^^^ error: functions cannot be both `const` and C-variadic - --> $DIR/variadic-ffi-semantic-restrictions.rs:62:5 + --> $DIR/variadic-ffi-semantic-restrictions.rs:65:5 | LL | const fn i_f5(x: isize, ...) {} | ^^^^^ ^^^ C-variadic because of this | | | `const` because of this -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:69:23 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:72:23 | LL | fn t_f1(x: isize, ...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:74:23 | LL | fn t_f2(x: isize, ...); | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:76:13 | LL | fn t_f3(...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13 +error: associated functions cannot have a C variable argument list + --> $DIR/variadic-ffi-semantic-restrictions.rs:78:13 | LL | fn t_f4(...); | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:80:13 | LL | fn t_f5(..., x: isize) {} | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 | LL | fn t_f6(..., x: isize); | ^^^ error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:30:43 + --> $DIR/variadic-ffi-semantic-restrictions.rs:33:43 | LL | const unsafe extern "C" fn f4_1(x: isize, ...) {} | ^^^ - value is dropped here @@ -183,7 +227,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, ...) {} | the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36 + --> $DIR/variadic-ffi-semantic-restrictions.rs:37:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^ - value is dropped here @@ -191,13 +235,13 @@ LL | const extern "C" fn f4_2(x: isize, ...) {} | the destructor for this type cannot be evaluated in constant functions error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29 + --> $DIR/variadic-ffi-semantic-restrictions.rs:65:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ - value is dropped here | | | the destructor for this type cannot be evaluated in constant functions -error: aborting due to 32 previous errors +error: aborting due to 33 previous errors For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/print-request/print-lints-help.stderr b/tests/ui/print-request/print-lints-help.stderr index bc48b2fa73c..297a3aa79e1 100644 --- a/tests/ui/print-request/print-lints-help.stderr +++ b/tests/ui/print-request/print-lints-help.stderr @@ -1,6 +1,6 @@ error: unknown print request: `lints` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `target-spec-json-schema`, `tls-models` = help: use `-Whelp` to print a list of lints = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index 951e7cd1012..b6ec8842634 100644 --- a/tests/ui/print_type_sizes/async.rs +++ b/tests/ui/print_type_sizes/async.rs @@ -1,3 +1,5 @@ +// FIXME(#61117): Respect debuginfo-level-tests, do not force debuginfo=0 +//@ compile-flags: -C debuginfo=0 //@ compile-flags: -C panic=abort -Z print-type-sizes --crate-type lib //@ needs-deterministic-layouts //@ edition:2021 diff --git a/tests/ui/range/issue-54505-no-literals.stderr b/tests/ui/range/issue-54505-no-literals.stderr index c6d4384bcd3..62e2fe4a838 100644 --- a/tests/ui/range/issue-54505-no-literals.stderr +++ b/tests/ui/range/issue-54505-no-literals.stderr @@ -207,7 +207,7 @@ LL | take_range(std::ops::RangeToInclusive { end: 5 }); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-literals.rs:12:4 | @@ -227,7 +227,7 @@ LL | take_range(::std::ops::RangeToInclusive { end: 5 }); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-literals.rs:12:4 | diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index 2aa1d584046..866a82afb7e 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -112,7 +112,7 @@ LL | take_range(..=42); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `core::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505-no-std.rs:25:4 | diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr index 8b669b2910f..4d94c6c2d09 100644 --- a/tests/ui/range/issue-54505.stderr +++ b/tests/ui/range/issue-54505.stderr @@ -112,7 +112,7 @@ LL | take_range(..=42); | arguments to this function are incorrect | = note: expected reference `&_` - found struct `RangeToInclusive<{integer}>` + found struct `std::ops::RangeToInclusive<{integer}>` note: function defined here --> $DIR/issue-54505.rs:10:4 | diff --git a/tests/ui/recursion_limit/empty.rs b/tests/ui/recursion_limit/empty.rs index 5987fa2f881..a901267d847 100644 --- a/tests/ui/recursion_limit/empty.rs +++ b/tests/ui/recursion_limit/empty.rs @@ -1,9 +1,7 @@ // Test the parse error for an empty recursion_limit -#![recursion_limit = ""] //~ ERROR `limit` must be a non-negative integer - //~| NOTE `limit` must be a non-negative integer - //~| ERROR `limit` must be a non-negative integer - //~| NOTE `limit` must be a non-negative integer - //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +#![recursion_limit = ""] +//~^ ERROR `limit` must be a non-negative integer +//~| NOTE `limit` must be a non-negative integer fn main() {} diff --git a/tests/ui/recursion_limit/empty.stderr b/tests/ui/recursion_limit/empty.stderr index 2f730677507..9afe9e6db56 100644 --- a/tests/ui/recursion_limit/empty.stderr +++ b/tests/ui/recursion_limit/empty.stderr @@ -6,15 +6,5 @@ LL | #![recursion_limit = ""] | | | `limit` must be a non-negative integer -error: `limit` must be a non-negative integer - --> $DIR/empty.rs:3:1 - | -LL | #![recursion_limit = ""] - | ^^^^^^^^^^^^^^^^^^^^^--^ - | | - | `limit` must be a non-negative integer - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/recursion_limit/invalid_digit.rs b/tests/ui/recursion_limit/invalid_digit.rs index 79d8f3708ba..1d0e6a18227 100644 --- a/tests/ui/recursion_limit/invalid_digit.rs +++ b/tests/ui/recursion_limit/invalid_digit.rs @@ -1,8 +1,6 @@ // Test the parse error for an invalid digit in recursion_limit -#![recursion_limit = "-100"] //~ ERROR `limit` must be a non-negative integer - //~| NOTE not a valid integer - //~| ERROR `limit` must be a non-negative integer - //~| NOTE not a valid integer - //~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +#![recursion_limit = "-100"] +//~^ ERROR `limit` must be a non-negative integer +//~| NOTE not a valid integer fn main() {} diff --git a/tests/ui/recursion_limit/invalid_digit.stderr b/tests/ui/recursion_limit/invalid_digit.stderr index 4fda3039032..9c2d1422df2 100644 --- a/tests/ui/recursion_limit/invalid_digit.stderr +++ b/tests/ui/recursion_limit/invalid_digit.stderr @@ -6,15 +6,5 @@ LL | #![recursion_limit = "-100"] | | | not a valid integer -error: `limit` must be a non-negative integer - --> $DIR/invalid_digit.rs:3:1 - | -LL | #![recursion_limit = "-100"] - | ^^^^^^^^^^^^^^^^^^^^^------^ - | | - | not a valid integer - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/recursion_limit/invalid_digit_type.stderr b/tests/ui/recursion_limit/invalid_digit_type.stderr index a122262f1df..489e8bd82c2 100644 --- a/tests/ui/recursion_limit/invalid_digit_type.stderr +++ b/tests/ui/recursion_limit/invalid_digit_type.stderr @@ -1,10 +1,14 @@ -error: malformed `recursion_limit` attribute input +error[E0539]: malformed `recursion_limit` attribute input --> $DIR/invalid_digit_type.rs:1:1 | LL | #![recursion_limit = 123] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + | ^^^^^^^^^^^^^^^^^^^^^---^ + | | | + | | expected a string literal here + | help: must be of the form: `#![recursion_limit = "N"]` | = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute> error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/recursion_limit/invalid_macro.rs b/tests/ui/recursion_limit/invalid_macro.rs index 7db67a8d162..eae348523db 100644 --- a/tests/ui/recursion_limit/invalid_macro.rs +++ b/tests/ui/recursion_limit/invalid_macro.rs @@ -1,4 +1,4 @@ -#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute +#![recursion_limit = foo!()] //~ ERROR attribute value must be a literal macro_rules! foo { () => {"128"}; diff --git a/tests/ui/recursion_limit/invalid_macro.stderr b/tests/ui/recursion_limit/invalid_macro.stderr index b4dbc9fcb13..de1df3e9a35 100644 --- a/tests/ui/recursion_limit/invalid_macro.stderr +++ b/tests/ui/recursion_limit/invalid_macro.stderr @@ -1,10 +1,8 @@ -error: malformed `recursion_limit` attribute input - --> $DIR/invalid_macro.rs:1:1 +error: attribute value must be a literal + --> $DIR/invalid_macro.rs:1:22 | LL | #![recursion_limit = foo!()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` - | - = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute> + | ^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/recursion_limit/no-value.stderr b/tests/ui/recursion_limit/no-value.stderr index 4a0ad04f271..eafc50bafb4 100644 --- a/tests/ui/recursion_limit/no-value.stderr +++ b/tests/ui/recursion_limit/no-value.stderr @@ -1,4 +1,4 @@ -error: malformed `recursion_limit` attribute input +error[E0539]: malformed `recursion_limit` attribute input --> $DIR/no-value.rs:3:1 | LL | #![recursion_limit] @@ -8,3 +8,4 @@ LL | #![recursion_limit] error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/recursion_limit/overflow.rs b/tests/ui/recursion_limit/overflow.rs index 7cd1d572e09..24cb8e286a8 100644 --- a/tests/ui/recursion_limit/overflow.rs +++ b/tests/ui/recursion_limit/overflow.rs @@ -3,8 +3,5 @@ #![recursion_limit = "999999999999999999999999"] //~^ ERROR `limit` must be a non-negative integer //~| NOTE `limit` is too large -//~| ERROR `limit` must be a non-negative integer -//~| NOTE `limit` is too large -//~| NOTE duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` fn main() {} diff --git a/tests/ui/recursion_limit/overflow.stderr b/tests/ui/recursion_limit/overflow.stderr index 6057177deb2..5a8548b7c7f 100644 --- a/tests/ui/recursion_limit/overflow.stderr +++ b/tests/ui/recursion_limit/overflow.stderr @@ -6,15 +6,5 @@ LL | #![recursion_limit = "999999999999999999999999"] | | | `limit` is too large -error: `limit` must be a non-negative integer - --> $DIR/overflow.rs:3:1 - | -LL | #![recursion_limit = "999999999999999999999999"] - | ^^^^^^^^^^^^^^^^^^^^^--------------------------^ - | | - | `limit` is too large - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-58712.rs b/tests/ui/resolve/missing-type-in-scope-58712.rs index 930bec6889b..b9ff74e426d 100644 --- a/tests/ui/issues/issue-58712.rs +++ b/tests/ui/resolve/missing-type-in-scope-58712.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58712 struct AddrVec<H, A> { h: H, a: A, diff --git a/tests/ui/issues/issue-58712.stderr b/tests/ui/resolve/missing-type-in-scope-58712.stderr index f4bd4d1e826..d7e06eee856 100644 --- a/tests/ui/issues/issue-58712.stderr +++ b/tests/ui/resolve/missing-type-in-scope-58712.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `DeviceId` in this scope - --> $DIR/issue-58712.rs:6:20 + --> $DIR/missing-type-in-scope-58712.rs:7:20 | LL | impl<H> AddrVec<H, DeviceId> { | ^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | impl<H, DeviceId> AddrVec<H, DeviceId> { | ++++++++++ error[E0412]: cannot find type `DeviceId` in this scope - --> $DIR/issue-58712.rs:8:29 + --> $DIR/missing-type-in-scope-58712.rs:9:29 | LL | pub fn device(&self) -> DeviceId { | ^^^^^^^^ not found in this scope diff --git a/tests/ui/simd/const-err-trumps-simd-err.stderr b/tests/ui/simd/const-err-trumps-simd-err.stderr index 6d25a28c92c..93d1fce637f 100644 --- a/tests/ui/simd/const-err-trumps-simd-err.stderr +++ b/tests/ui/simd/const-err-trumps-simd-err.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation panicked: assertion failed: LANE < 4 - --> $DIR/const-err-trumps-simd-err.rs:17:21 + --> $DIR/const-err-trumps-simd-err.rs:17:13 | LL | const { assert!(LANE < 4); } // the error should be here... - | ^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here + | ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here note: erroneous constant encountered --> $DIR/const-err-trumps-simd-err.rs:17:5 diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs new file mode 100644 index 00000000000..93241db09f9 --- /dev/null +++ b/tests/ui/static/static-align.rs @@ -0,0 +1,26 @@ +//@ run-pass +#![feature(static_align)] + +#[rustc_align_static(64)] +static A: u8 = 0; + +#[rustc_align_static(64)] +static B: u8 = 0; + +#[rustc_align_static(128)] +#[no_mangle] +static EXPORTED: u64 = 0; + +unsafe extern "C" { + #[rustc_align_static(128)] + #[link_name = "EXPORTED"] + static C: u64; +} + +fn main() { + assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64)); + assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64)); + + assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128)); + unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) }; +} diff --git a/tests/ui/issues/issue-59020.rs b/tests/ui/std/park-timeout-wakeup-59020.rs index 2a34ba52b88..af530bb586c 100644 --- a/tests/ui/issues/issue-59020.rs +++ b/tests/ui/std/park-timeout-wakeup-59020.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/59020 //@ edition:2018 //@ run-pass //@ needs-threads diff --git a/tests/ui/issues/issue-56835.rs b/tests/ui/structs/invalid-self-constructor-56835.rs index 7132d15ee5f..fd8763443f0 100644 --- a/tests/ui/issues/issue-56835.rs +++ b/tests/ui/structs/invalid-self-constructor-56835.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56835 pub struct Foo {} impl Foo { diff --git a/tests/ui/issues/issue-56835.stderr b/tests/ui/structs/invalid-self-constructor-56835.stderr index e949ae7b324..045781ec42b 100644 --- a/tests/ui/issues/issue-56835.stderr +++ b/tests/ui/structs/invalid-self-constructor-56835.stderr @@ -1,11 +1,11 @@ error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/issue-56835.rs:4:12 + --> $DIR/invalid-self-constructor-56835.rs:5:12 | LL | fn bar(Self(foo): Self) {} | ^^^^^^^^^ help: use curly brackets: `Self { /* fields */ }` error[E0164]: expected tuple struct or tuple variant, found self constructor `Self` - --> $DIR/issue-56835.rs:4:12 + --> $DIR/invalid-self-constructor-56835.rs:5:12 | LL | fn bar(Self(foo): Self) {} | ^^^^^^^^^ not a tuple struct or tuple variant diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs new file mode 100644 index 00000000000..b182e1939b3 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -0,0 +1,12 @@ +//@ aux-build:dep.rs + +extern crate dep; +use dep::*; + +struct Local; +impl Trait for Local {} +//~^ ERROR not all trait items implemented +//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` + +fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr new file mode 100644 index 00000000000..b309a64e958 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/apitit-unimplemented-method.rs:7:1 + | +LL | impl Trait for Local {} + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | + = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs new file mode 100644 index 00000000000..ac0de418313 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -0,0 +1,4 @@ +pub trait Trait { + fn foo(_: impl Sized); + fn bar<T>(_: impl Sized); +} diff --git a/tests/ui/issues/issue-59756.fixed b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.fixed index 954ba917626..954ba917626 100644 --- a/tests/ui/issues/issue-59756.fixed +++ b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.fixed diff --git a/tests/ui/issues/issue-59756.rs b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.rs index de349f43f46..570aa7d373b 100644 --- a/tests/ui/issues/issue-59756.rs +++ b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/59756 //@ run-rustfix //@ ignore-test (rustfix needs multiple suggestions) // diff --git a/tests/ui/issues/issue-59756.stderr b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.stderr index 27c07fecd5b..7182109b5a0 100644 --- a/tests/ui/issues/issue-59756.stderr +++ b/tests/ui/suggestions/incompatible-types-in-try-expression-59756.stderr @@ -1,5 +1,5 @@ error[E0308]: try expression alternatives have incompatible types - --> $DIR/issue-59756.rs:13:5 + --> $DIR/incompatible-types-in-try-expression-59756.rs:13:5 | LL | foo()? | ^^^^^^ expected enum `std::result::Result`, found struct `A` diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr index 31f8f1d455a..9e068c311ae 100644 --- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr @@ -5,14 +5,14 @@ LL | let _: &[i8] = data.into(); | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | = help: the following other types implement trait `From<T>`: - `[T; 10]` implements `From<(T, T, T, T, T, T, T, T, T, T)>` - `[T; 11]` implements `From<(T, T, T, T, T, T, T, T, T, T, T)>` - `[T; 12]` implements `From<(T, T, T, T, T, T, T, T, T, T, T, T)>` `[T; 1]` implements `From<(T,)>` `[T; 2]` implements `From<(T, T)>` `[T; 3]` implements `From<(T, T, T)>` `[T; 4]` implements `From<(T, T, T, T)>` `[T; 5]` implements `From<(T, T, T, T, T)>` + `[T; 6]` implements `From<(T, T, T, T, T, T)>` + `[T; 7]` implements `From<(T, T, T, T, T, T, T)>` + `[T; 8]` implements `From<(T, T, T, T, T, T, T, T)>` and 6 others = note: required for `&[u8]` to implement `Into<&[i8]>` diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs new file mode 100644 index 00000000000..fbede7c41cb --- /dev/null +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.rs @@ -0,0 +1,64 @@ +fn no_format_specifier_two_unused_args() { + println!("Hello", "World"); + //~^ ERROR argument never used + //~| NOTE formatting specifier missing + //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding a format specifier +} + +fn no_format_specifier_multiple_unused_args() { + println!("list: ", 1, 2, 3); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE argument never used + //~| NOTE argument never used + //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding 3 format specifiers +} + +fn missing_format_specifiers_one_unused_arg() { + println!("list: {}, {}", 1, 2, 3); + //~^ ERROR argument never used + //~| NOTE formatting specifier missing + //~| NOTE argument never used +} + +fn missing_format_specifiers_multiple_unused_args() { + println!("list: {}", 1, 2, 3); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE argument never used + //~| NOTE argument never used + //~| NOTE consider adding 2 format specifiers +} + +fn unicode_unused_args() { + panic!("👆", "👆", 1); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE argument never used + //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding 2 format specifiers +} + +fn raw_str_unused_arg() { + format_args!(r##"lJÆ�.�"##, r#"r}JÆ" {}"#, 1); + //~^ ERROR multiple unused formatting arguments + //~| NOTE multiple missing formatting specifiers + //~| NOTE argument never used + //~| NOTE argument never used + //~| HELP format specifiers use curly braces, consider adding 2 format specifiers +} + +fn valid_new_lines_unused_args() { + panic!("Expect 2 newlines + +", "👆", 1); + //~^ ERROR multiple unused formatting arguments + //~| NOTE argument never used + //~| NOTE argument never used + //~^^^^^^ NOTE multiple missing formatting specifiers + //~| HELP format specifiers use curly braces, consider adding 2 format specifiers +} + +fn main() { } diff --git a/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr new file mode 100644 index 00000000000..7e997241698 --- /dev/null +++ b/tests/ui/suggestions/missing-format-specifiers-issue-68293.stderr @@ -0,0 +1,96 @@ +error: argument never used + --> $DIR/missing-format-specifiers-issue-68293.rs:2:23 + | +LL | println!("Hello", "World"); + | ------- ^^^^^^^ argument never used + | | + | formatting specifier missing + | +help: format specifiers use curly braces, consider adding a format specifier + | +LL | println!("Hello{}", "World"); + | ++ + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:10:24 + | +LL | println!("list: ", 1, 2, 3); + | -------- ^ ^ ^ argument never used + | | | | + | | | argument never used + | | argument never used + | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 3 format specifiers + | +LL | println!("list: {}{}{}", 1, 2, 3); + | ++++++ + +error: argument never used + --> $DIR/missing-format-specifiers-issue-68293.rs:20:36 + | +LL | println!("list: {}, {}", 1, 2, 3); + | -------------- ^ argument never used + | | + | formatting specifier missing + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:27:29 + | +LL | println!("list: {}", 1, 2, 3); + | ---------- ^ ^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | + = note: consider adding 2 format specifiers + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:36:17 + | +LL | panic!("👆", "👆", 1); + | ---- ^^^^ ^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 2 format specifiers + | +LL | panic!("👆{}{}", "👆", 1); + | ++++ + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:45:35 + | +LL | format_args!(r##"lJÆ�.�"##, r#"r}JÆ" {}"#, 1); + | --------------- ^^^^^^^^^^^^^^ ^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 2 format specifiers + | +LL | format_args!(r##"lJÆ�.�{}{}"##, r#"r}JÆ" {}"#, 1); + | ++++ + +error: multiple unused formatting arguments + --> $DIR/missing-format-specifiers-issue-68293.rs:56:4 + | +LL | panic!("Expect 2 newlines + | ____________- +LL | | +LL | | ", "👆", 1); + | | - ^^^^ ^ argument never used + | | | | + | |_| argument never used + | multiple missing formatting specifiers + | +help: format specifiers use curly braces, consider adding 2 format specifiers + | +LL | panic!("Expect 2 newlines +LL | +LL ~ {}{}", "👆", 1); + | + +error: aborting due to 7 previous errors + diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs index d367dd5b299..ddd4313bd5e 100644 --- a/tests/ui/trait-bounds/more_maybe_bounds.rs +++ b/tests/ui/trait-bounds/more_maybe_bounds.rs @@ -21,6 +21,20 @@ fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {} // FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`. fn baz<T>() where T: Iterator<Item: ?Trait1> {} +//~^ ERROR this relaxed bound is not permitted here + +struct S1<T>(T); + +impl<T> S1<T> { + fn f() where T: ?Trait1 {} + //~^ ERROR this relaxed bound is not permitted here +} + +trait Trait5<'a> {} + +struct S2<T>(T) where for<'a> T: ?Trait5<'a>; +//~^ ERROR this relaxed bound is not permitted here +//~| ERROR bound modifier `?` can only be applied to default traits like `Sized` struct S; impl !Trait2 for S {} diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr index 8dd83fc7728..0d78cfd5820 100644 --- a/tests/ui/trait-bounds/more_maybe_bounds.stderr +++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr @@ -1,3 +1,27 @@ +error: this relaxed bound is not permitted here + --> $DIR/more_maybe_bounds.rs:23:37 + | +LL | fn baz<T>() where T: Iterator<Item: ?Trait1> {} + | ^^^^^^^ + | + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item + +error: this relaxed bound is not permitted here + --> $DIR/more_maybe_bounds.rs:29:21 + | +LL | fn f() where T: ?Trait1 {} + | ^^^^^^^ + | + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item + +error: this relaxed bound is not permitted here + --> $DIR/more_maybe_bounds.rs:35:34 + | +LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>; + | ^^^^^^^^^^^ + | + = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item + error: bound modifier `?` can only be applied to default traits like `Sized` --> $DIR/more_maybe_bounds.rs:17:20 | @@ -16,5 +40,11 @@ error: bound modifier `?` can only be applied to default traits like `Sized` LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {} | ^^^^^^^ -error: aborting due to 3 previous errors +error: bound modifier `?` can only be applied to default traits like `Sized` + --> $DIR/more_maybe_bounds.rs:35:34 + | +LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>; + | ^^^^^^^^^^^ + +error: aborting due to 7 previous errors diff --git a/tests/ui/issues/issue-58857.rs b/tests/ui/trait-bounds/negative-bound-not-supported-58857.rs index 4350d7e5b40..0a0b70a216b 100644 --- a/tests/ui/issues/issue-58857.rs +++ b/tests/ui/trait-bounds/negative-bound-not-supported-58857.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58857 struct Conj<A> {a : A} trait Valid {} diff --git a/tests/ui/issues/issue-58857.stderr b/tests/ui/trait-bounds/negative-bound-not-supported-58857.stderr index ac70bc725e2..05347a891b4 100644 --- a/tests/ui/issues/issue-58857.stderr +++ b/tests/ui/trait-bounds/negative-bound-not-supported-58857.stderr @@ -1,5 +1,5 @@ error: negative bounds are not supported - --> $DIR/issue-58857.rs:4:9 + --> $DIR/negative-bound-not-supported-58857.rs:5:9 | LL | impl<A: !Valid> Conj<A>{} | ^ diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs index da28d9a47c3..c89aaa62d99 100644 --- a/tests/ui/traits/const-traits/const-impl-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-trait.rs @@ -1,7 +1,5 @@ +//@ check-pass //@ compile-flags: -Znext-solver -//@ known-bug: #110395 - -// Broken until `(): const PartialEq` #![allow(incomplete_features)] #![feature(const_trait_impl, const_cmp, const_destruct)] diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr deleted file mode 100644 index cbb68d8c983..00000000000 --- a/tests/ui/traits/const-traits/const-impl-trait.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0277]: the trait bound `(): const PartialEq` is not satisfied - --> $DIR/const-impl-trait.rs:34:17 - | -LL | assert!(cmp(&())); - | --- ^^^ - | | - | required by a bound introduced by this call - | -note: required by a bound in `cmp` - --> $DIR/const-impl-trait.rs:11:23 - | -LL | const fn cmp(a: &impl [const] PartialEq) -> bool { - | ^^^^^^^^^^^^^^^^^ required by this bound in `cmp` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.rs b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs index 1a3012de06f..78c25ccd6e5 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-use.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs @@ -1,5 +1,4 @@ -//@ known-bug: #110395 - +//@ check-pass #![feature(const_trait_impl, const_default, const_cmp, derive_const)] pub struct A; diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr deleted file mode 100644 index 4ea11a0c7ed..00000000000 --- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0277]: the trait bound `(): [const] PartialEq` is not satisfied - --> $DIR/derive-const-use.rs:16:14 - | -LL | #[derive_const(Default, PartialEq)] - | --------- in this derive macro expansion -LL | pub struct S((), A); - | ^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs index ee04f74c8a6..9b03ec7553d 100644 --- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs +++ b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.rs @@ -1,24 +1,23 @@ -// Ensure that we don't consider `const Trait` to -// match the macro fragment specifier `ty` as that would be a breaking -// change theoretically speaking. Syntactically trait object types can -// be "bare", i.e., lack the prefix `dyn`. -// By contrast, `?Trait` *does* match `ty` and therefore an arm like -// `?$Trait:path` would never be reached. -// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`. -// `[const] Trait` is already an error for a `ty` fragment, -// so we do not need to prevent that. +// Ensure that we don't consider `const Trait` to match the macro fragment specifier `ty` +// as that would be a breaking change theoretically speaking. +// +// Syntactically trait object types can be "bare", i.e., lack the prefix `dyn`. +// By contrast, `?Trait` *does* match `ty` and therefore an arm like `?$Trait:path` +// would never be reached. See `parser/macro/macro-bare-trait-object-maybe-trait-bound.rs`. + +//@ check-pass (KEEP THIS AS A PASSING TEST!) macro_rules! check { - ($Type:ty) => { - compile_error!("ty"); - }; - (const $Trait:path) => {}; - ([const] $Trait:path) => { [const] Trait }; + ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + + // DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES! + + (const $Trait:path) => { /* KEEP THIS EMPTY! */ }; + // We don't need to check `[const] Trait` here since that matches the `ty` fragment + // already anyway since `[` may begin a slice or array type. However, it'll then + // subsequently fail due to #146122 (section 3). } check! { const Trait } -check! { [const] Trait } -//~^ ERROR: expected identifier, found `]` -//~| ERROR: const trait impls are experimental fn main() {} diff --git a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr b/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr deleted file mode 100644 index a4e77154b17..00000000000 --- a/tests/ui/traits/const-traits/macro-bare-trait-objects-const-trait-bounds.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: expected identifier, found `]` - --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:16 - | -LL | ($Type:ty) => { - | -------- while parsing argument for this `ty` macro fragment -... -LL | check! { [const] Trait } - | ^ expected identifier - -error[E0658]: const trait impls are experimental - --> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:11 - | -LL | check! { [const] Trait } - | ^^^^^ - | - = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information - = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs index 35e964eacec..3f70ffa7d10 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.rs @@ -1,22 +1,32 @@ // Demonstrates and records a theoretical regressions / breaking changes caused by the -// introduction of const trait bounds. +// introduction of `const` and `[const]` trait bounds. -// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018. +// Setting the edition to >2015 since we didn't regress `demo! { dyn const }` in Rust 2015. +// See also test `traits/const-traits/macro-dyn-const-2015.rs`. //@ edition:2018 trait Trait {} macro_rules! demo { - (impl $c:ident Trait) => { impl $c Trait {} }; - //~^ ERROR inherent - //~| WARN trait objects without an explicit `dyn` are deprecated - //~| WARN this is accepted in the current edition - (dyn $c:ident Trait) => { dyn $c Trait {} }; //~ ERROR macro expansion + ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + //~^ ERROR ty + //~| ERROR ty + //~| ERROR ty + //~| ERROR ty + + // DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES! + + (impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ }; + (dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ }; + + (impl [const] Trait) => { /* KEEP THIS EMPTY! */ }; + (dyn [const] Trait) => { /* KEEP THIS EMPTY! */ }; } -demo! { impl const Trait } -//~^ ERROR const trait impls are experimental +demo! { impl const Trait } //~ ERROR const trait impls are experimental +demo! { dyn const Trait } //~ ERROR const trait impls are experimental -demo! { dyn const Trait } +demo! { impl [const] Trait } //~ ERROR const trait impls are experimental +demo! { dyn [const] Trait } //~ ERROR const trait impls are experimental fn main() {} diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr index 7a4061d9c18..383936b9df1 100644 --- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr +++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr @@ -1,31 +1,49 @@ -error: inherent impls cannot be const - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40 +error: ty + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19 | -LL | (impl $c:ident Trait) => { impl $c Trait {} }; - | ^^^^^ inherent impl for this type +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + | ^^^^^^^^^^^^^^^^^^^^ ... LL | demo! { impl const Trait } - | -------------------------- - | | | - | | const because of this - | in this macro invocation + | -------------------------- in this macro invocation | - = note: only trait implementations may be annotated with `const` = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: macro expansion ignores keyword `dyn` and any tokens following - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31 +error: ty + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19 | -LL | (dyn $c:ident Trait) => { dyn $c Trait {} }; - | ^^^ +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + | ^^^^^^^^^^^^^^^^^^^^ ... LL | demo! { dyn const Trait } - | ------------------------- caused by the macro expansion here + | ------------------------- in this macro invocation | - = note: the usage of `demo!` is likely invalid in item context + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: ty + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19 + | +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | demo! { impl [const] Trait } + | ---------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: ty + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19 + | +LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | demo! { dyn [const] Trait } + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: const trait impls are experimental - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14 + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:26:14 | LL | demo! { impl const Trait } | ^^^^^ @@ -34,24 +52,36 @@ LL | demo! { impl const Trait } = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40 +error[E0658]: const trait impls are experimental + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:27:13 | -LL | (impl $c:ident Trait) => { impl $c Trait {} }; - | ^^^^^ -... -LL | demo! { impl const Trait } - | -------------------------- in this macro invocation +LL | demo! { dyn const Trait } + | ^^^^^ | - = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html> - = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default - = note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might have intended to implement this trait for a given type + = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:29:14 + | +LL | demo! { impl [const] Trait } + | ^^^^^^^ + | + = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/macro-const-trait-bound-theoretical-regression.rs:30:13 | -LL | (impl $c:ident Trait) => { impl $c Trait for /* Type */ {} }; - | ++++++++++++++ +LL | demo! { dyn [const] Trait } + | ^^^^^^^ + | + = note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/macro-dyn-const-2015.rs b/tests/ui/traits/const-traits/macro-dyn-const-2015.rs index fadfbe66788..0dfa482b986 100644 --- a/tests/ui/traits/const-traits/macro-dyn-const-2015.rs +++ b/tests/ui/traits/const-traits/macro-dyn-const-2015.rs @@ -1,14 +1,19 @@ -// Ensure that the introduction of const trait bound didn't regress this code in Rust 2015. -// See also `mbe-const-trait-bound-theoretical-regression.rs`. +// Ensure that the introduction of `const` and `[const]` trait bounds didn't regress this +// Rust 2015 code. See also test `macro-const-trait-bound-theoretical-regression.rs`. //@ edition: 2015 -//@ check-pass +//@ check-pass (KEEP THIS AS A PASSING TEST!) macro_rules! check { - ($ty:ty) => { compile_error!("ty"); }; - (dyn $c:ident) => {}; + ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + + // DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES! + + (dyn $c:ident) => { /* KEEP THIS EMPTY! */ }; + (dyn [$c:ident]) => { /* KEEP THIS EMPTY! */ }; } check! { dyn const } +check! { dyn [const] } fn main() {} diff --git a/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs b/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs new file mode 100644 index 00000000000..75077577b8c --- /dev/null +++ b/tests/ui/traits/const-traits/macro-maybe-const-trait-bounds.rs @@ -0,0 +1,25 @@ +// Ensure that we don't consider `[` to begin trait bounds to contain breakages. +// Only `[const]` in its entirety begins a trait bound. +// See also test `macro-const-trait-bound-theoretical-regression.rs`. + +//@ check-pass (KEEP THIS AS A PASSING TEST!) +// Setting the edition to >2015 since we didn't regress `check! { dyn [const] Trait }` in Rust 2015. +// See also test `traits/const-traits/macro-dyn-const-2015.rs`. +//@ edition:2018 + +macro_rules! check { + ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS! + + // DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES! + + (dyn [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ }; + (impl [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ }; +} + +check!(dyn [T] Trait); + +// issue: <https://github.com/rust-lang/rust/issues/146417> +check!(impl [T] Trait); +check!(impl [T: Bound] Trait); + +fn main() {} diff --git a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs deleted file mode 100644 index 745b6ee9bc5..00000000000 --- a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs +++ /dev/null @@ -1,31 +0,0 @@ -//@ check-pass -//@ compile-flags: -Zexperimental-default-bounds - -#![feature(auto_traits, lang_items, no_core, rustc_attrs, trait_alias)] -#![no_std] -#![no_core] - -#[lang = "pointee_sized"] -trait PointeeSized {} - -#[lang = "meta_sized"] -trait MetaSized: PointeeSized {} - -#[lang = "sized"] -trait Sized: MetaSized {} - -#[lang = "default_trait1"] -auto trait DefaultTrait1 {} - -#[lang = "default_trait2"] -auto trait DefaultTrait2 {} - -trait Trait<Rhs: ?Sized = Self> {} -trait Trait1 : Trait {} - -trait Trait2 { - type Type; -} -trait Trait3<T> = Trait2<Type = T>; - -fn main() {} diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs index e7cca41a47e..2e1a5d2424b 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs @@ -13,32 +13,37 @@ #![no_core] #[lang = "pointee_sized"] -trait PointeeSized {} +trait PointeeSized: ?Leak {} #[lang = "meta_sized"] -trait MetaSized: PointeeSized {} +trait MetaSized: PointeeSized + ?Leak {} #[lang = "sized"] -trait Sized: MetaSized {} +trait Sized: MetaSized + ?Leak {} #[lang = "copy"] -pub trait Copy {} +pub trait Copy: ?Leak {} impl<'a, T: ?Sized> Copy for &'a T {} #[lang = "legacy_receiver"] -trait Receiver {} +trait Receiver: ?Leak {} impl<T: ?Sized + ?Leak> Receiver for &T {} +impl<T: ?Sized + ?Leak> Receiver for &mut T {} #[lang = "unsize"] -trait Unsize<T: ?Sized + ?Leak> {} +trait Unsize<T: ?Sized + ?Leak>: ?Leak {} #[lang = "coerce_unsized"] -trait CoerceUnsized<T: ?Leak + ?Sized> {} +trait CoerceUnsized<T: ?Leak + ?Sized>: ?Leak {} impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {} +// Omit `T: ?Leak` and `U: ?Leak`. +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'b mut T {} #[lang = "dispatch_from_dyn"] -trait DispatchFromDyn<T: ?Leak> {} +trait DispatchFromDyn<T: ?Leak>: ?Leak {} impl<'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {} +// Omit `T: ?Leak` and `U: ?Leak`. +impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} #[lang = "default_trait1"] auto trait Leak {} @@ -47,25 +52,52 @@ struct NonLeakS; impl !Leak for NonLeakS {} struct LeakS; -trait Trait { - fn leak_foo(&self) {} - fn maybe_leak_foo(&self) where Self: ?Leak {} +fn bounds_check() { + trait LeakTr {} + + trait MaybeLeakTr: ?Leak {} + + impl MaybeLeakTr for NonLeakS {} + + impl LeakTr for LeakS {} + impl MaybeLeakTr for LeakS {} + + let _: &dyn LeakTr = &NonLeakS; + //~^ ERROR the trait bound `NonLeakS: bounds_check::LeakTr` is not satisfied + let _: &dyn LeakTr = &LeakS; + + let _: &(dyn LeakTr + ?Leak) = &NonLeakS; + let _: &(dyn LeakTr + ?Leak) = &LeakS; + + let _: &dyn MaybeLeakTr = &NonLeakS; + let _: &dyn MaybeLeakTr = &LeakS; } -impl Trait for NonLeakS {} -impl Trait for LeakS {} - -fn main() { - let _: &dyn Trait = &NonLeakS; - //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied - let _: &dyn Trait = &LeakS; - let _: &(dyn Trait + ?Leak) = &LeakS; - let x: &(dyn Trait + ?Leak) = &NonLeakS; - x.leak_foo(); - //~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied - x.maybe_leak_foo(); +fn dyn_compat_check() { + trait DynCompatCheck1: ?Leak { + fn foo(&self) {} + } + + trait DynCompatCheck2: ?Leak { + fn mut_foo(&mut self) {} + } + + impl DynCompatCheck1 for NonLeakS {} + impl DynCompatCheck2 for NonLeakS {} + + let _: &(dyn DynCompatCheck1 + ?Leak) = &NonLeakS; + // There is no `?Leak` bound on corresponding `DispatchFromDyn` impl. + let _: &dyn DynCompatCheck2 = &NonLeakS; + //~^ ERROR the trait `DynCompatCheck2` is not dyn compatible +} + +fn args_check() { + trait LeakTr {} + // Ensure that we validate the generic args of relaxed bounds in trait object types. - let _: dyn Trait + ?Leak<(), Undefined = ()>; + let _: dyn LeakTr + ?Leak<(), Undefined = ()>; //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied //~| ERROR associated type `Undefined` not found for `Leak` } + +fn main() {} diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr index b19c082a1b8..b96a2915c33 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -1,49 +1,57 @@ -error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied - --> $DIR/maybe-bounds-in-dyn-traits.rs:59:25 +error[E0277]: the trait bound `NonLeakS: bounds_check::LeakTr` is not satisfied + --> $DIR/maybe-bounds-in-dyn-traits.rs:65:26 | -LL | let _: &dyn Trait = &NonLeakS; - | ^^^^^^^^^ unsatisfied trait bound +LL | let _: &dyn LeakTr = &NonLeakS; + | ^^^^^^^^^ unsatisfied trait bound | -help: the trait `Leak` is not implemented for `NonLeakS` - --> $DIR/maybe-bounds-in-dyn-traits.rs:46:1 +help: the trait `bounds_check::LeakTr` is not implemented for `NonLeakS` + --> $DIR/maybe-bounds-in-dyn-traits.rs:51:1 | LL | struct NonLeakS; | ^^^^^^^^^^^^^^^ - = note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak` + = help: the trait `bounds_check::LeakTr` is implemented for `LeakS` + = note: required for the cast from `&NonLeakS` to `&dyn bounds_check::LeakTr + Leak` -error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied - --> $DIR/maybe-bounds-in-dyn-traits.rs:64:7 - | -LL | x.leak_foo(); - | ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait` - | -note: required by a bound in `Trait::leak_foo` - --> $DIR/maybe-bounds-in-dyn-traits.rs:51:5 - | -LL | fn leak_foo(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` +error[E0038]: the trait `DynCompatCheck2` is not dyn compatible + --> $DIR/maybe-bounds-in-dyn-traits.rs:90:17 + | +LL | fn mut_foo(&mut self) {} + | --------- help: consider changing method `mut_foo`'s `self` parameter to be `&self`: `&Self` +... +LL | let _: &dyn DynCompatCheck2 = &NonLeakS; + | ^^^^^^^^^^^^^^^ `DynCompatCheck2` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> + --> $DIR/maybe-bounds-in-dyn-traits.rs:82:20 + | +LL | trait DynCompatCheck2: ?Leak { + | --------------- this trait is not dyn compatible... +LL | fn mut_foo(&mut self) {} + | ^^^^^^^^^ ...because method `mut_foo`'s `self` parameter cannot be dispatched on + = help: only type `NonLeakS` implements `DynCompatCheck2`; consider using it directly instead. error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/maybe-bounds-in-dyn-traits.rs:68:25 + --> $DIR/maybe-bounds-in-dyn-traits.rs:98:26 | -LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; - | ^^^^-------------------- help: remove the unnecessary generics - | | - | expected 0 generic arguments +LL | let _: dyn LeakTr + ?Leak<(), Undefined = ()>; + | ^^^^-------------------- help: remove the unnecessary generics + | | + | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/maybe-bounds-in-dyn-traits.rs:44:12 + --> $DIR/maybe-bounds-in-dyn-traits.rs:49:12 | LL | auto trait Leak {} | ^^^^ error[E0220]: associated type `Undefined` not found for `Leak` - --> $DIR/maybe-bounds-in-dyn-traits.rs:68:34 + --> $DIR/maybe-bounds-in-dyn-traits.rs:98:35 | -LL | let _: dyn Trait + ?Leak<(), Undefined = ()>; - | ^^^^^^^^^ associated type `Undefined` not found +LL | let _: dyn LeakTr + ?Leak<(), Undefined = ()>; + | ^^^^^^^^^ associated type `Undefined` not found error: aborting due to 4 previous errors -Some errors have detailed explanations: E0107, E0220, E0277. -For more information about an error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0038, E0107, E0220, E0277. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs index b3801baaf70..ac4c4aca2ef 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs @@ -14,18 +14,22 @@ #![no_std] #![no_core] +#[lang = "copy"] +pub trait Copy: ?Leak {} + #[lang = "pointee_sized"] -trait PointeeSized {} +trait PointeeSized: ?Leak {} #[lang = "meta_sized"] -trait MetaSized: PointeeSized {} +trait MetaSized: PointeeSized + ?Leak {} #[lang = "sized"] -trait Sized: MetaSized {} +trait Sized: MetaSized + ?Leak {} #[lang = "legacy_receiver"] -trait LegacyReceiver {} +trait LegacyReceiver: ?Leak {} impl<T: ?Sized + ?Leak> LegacyReceiver for &T {} +// Omit `T: ?Leak`. impl<T: ?Sized> LegacyReceiver for &mut T {} #[lang = "default_trait1"] @@ -38,83 +42,40 @@ struct LeakS; mod supertraits { use crate::*; - trait MaybeLeakT1: ?Leak {} - trait MaybeLeakT2 where Self: ?Leak {} + trait MaybeLeak: ?Leak {} + impl MaybeLeak for NonLeakS {} - impl MaybeLeakT1 for NonLeakS {} - impl MaybeLeakT2 for NonLeakS {} + trait LeakT {} + impl LeakT for NonLeakS {} + //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied } -mod maybe_self_assoc_type { +mod assoc_type_maybe_bounds { use crate::*; - trait TestBase1<T: ?Sized> {} - trait TestBase2<T: ?Leak + ?Sized> {} - - trait Test1<T> { - type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak; - //~^ ERROR the trait bound `Self: Leak` is not satisfied - type LeakSelf: TestBase1<Self>; - } - - trait Test2<T> { - type MaybeLeakSelf: TestBase2<Self> where Self: ?Leak; - type LeakSelf: TestBase2<Self>; - } - - trait Test3 { + trait Test1 { type Leak1 = LeakS; type Leak2 = NonLeakS; //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied } - trait Test4 { + trait Test2 { type MaybeLeak1: ?Leak = LeakS; type MaybeLeak2: ?Leak = NonLeakS; } - - trait Test5: ?Leak { - // ok, because assoc types have implicit where Self: Leak - type MaybeLeakSelf1: TestBase1<Self>; - type MaybeLeakSelf2: TestBase2<Self>; - } -} - -mod maybe_self_assoc_const { - use crate::*; - - const fn size_of<T: ?Sized>() -> usize { - 0 - } - - trait Trait { - const CLeak: usize = size_of::<Self>(); - const CNonLeak: usize = size_of::<Self>() where Self: ?Leak; - //~^ ERROR the trait bound `Self: Leak` is not satisfied - } } mod methods { use crate::*; - trait Trait { - fn leak_foo(&self) {} - fn maybe_leak_foo(&self) where Self: ?Leak {} - fn mut_leak_foo(&mut self) {} - // there is no relax bound on corresponding Receiver impl - fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} - //~^ ERROR `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` + trait ReceiveCheck1: ?Leak { + fn foo(&self) {} } - impl Trait for NonLeakS {} - impl Trait for LeakS {} - - fn foo() { - LeakS.leak_foo(); - LeakS.maybe_leak_foo(); - NonLeakS.leak_foo(); - //~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied - NonLeakS.maybe_leak_foo(); + trait ReceiveCheck2: ?Leak { + // There is no `?Leak` bound on corresponding `LegacyReceiver` impl. + fn mut_foo(&mut self) {} + //~^ ERROR `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` } } diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr index 372bf817600..ab62ab81b21 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr @@ -1,81 +1,49 @@ error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied - --> $DIR/maybe-bounds-in-traits.rs:67:22 + --> $DIR/maybe-bounds-in-traits.rs:49:20 | -LL | type Leak2 = NonLeakS; - | ^^^^^^^^ unsatisfied trait bound +LL | impl LeakT for NonLeakS {} + | ^^^^^^^^ unsatisfied trait bound | help: the trait `Leak` is not implemented for `NonLeakS` - --> $DIR/maybe-bounds-in-traits.rs:34:1 + --> $DIR/maybe-bounds-in-traits.rs:38:1 | LL | struct NonLeakS; | ^^^^^^^^^^^^^^^ -note: required by a bound in `Test3::Leak2` - --> $DIR/maybe-bounds-in-traits.rs:67:9 +note: required by a bound in `LeakT` + --> $DIR/maybe-bounds-in-traits.rs:48:5 | -LL | type Leak2 = NonLeakS; - | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2` +LL | trait LeakT {} + | ^^^^^^^^^^^^^^ required by this bound in `LeakT` -error[E0277]: the trait bound `Self: Leak` is not satisfied - --> $DIR/maybe-bounds-in-traits.rs:55:29 +error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied + --> $DIR/maybe-bounds-in-traits.rs:58:22 | -LL | type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak; - | ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self` +LL | type Leak2 = NonLeakS; + | ^^^^^^^^ unsatisfied trait bound | -note: required by a bound in `TestBase1` - --> $DIR/maybe-bounds-in-traits.rs:51:21 +help: the trait `Leak` is not implemented for `NonLeakS` + --> $DIR/maybe-bounds-in-traits.rs:38:1 | -LL | trait TestBase1<T: ?Sized> {} - | ^ required by this bound in `TestBase1` -help: consider further restricting `Self` +LL | struct NonLeakS; + | ^^^^^^^^^^^^^^^ +note: required by a bound in `Test1::Leak2` + --> $DIR/maybe-bounds-in-traits.rs:58:9 | -LL | trait Test1<T>: Leak { - | ++++++ +LL | type Leak2 = NonLeakS; + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test1::Leak2` error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature - --> $DIR/maybe-bounds-in-traits.rs:105:31 + --> $DIR/maybe-bounds-in-traits.rs:77:20 | -LL | fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {} - | ^^^^^^^^^ +LL | fn mut_foo(&mut self) {} + | ^^^^^^^^^ | = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>` -error[E0277]: the trait bound `Self: Leak` is not satisfied - --> $DIR/maybe-bounds-in-traits.rs:92:43 - | -LL | const CNonLeak: usize = size_of::<Self>() where Self: ?Leak; - | ^^^^ the trait `Leak` is not implemented for `Self` - | -note: required by a bound in `size_of` - --> $DIR/maybe-bounds-in-traits.rs:86:22 - | -LL | const fn size_of<T: ?Sized>() -> usize { - | ^ required by this bound in `size_of` -help: consider further restricting `Self` - | -LL | trait Trait: Leak { - | ++++++ - -error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied - --> $DIR/maybe-bounds-in-traits.rs:115:18 - | -LL | NonLeakS.leak_foo(); - | ^^^^^^^^ unsatisfied trait bound - | -help: the trait `Leak` is not implemented for `NonLeakS` - --> $DIR/maybe-bounds-in-traits.rs:34:1 - | -LL | struct NonLeakS; - | ^^^^^^^^^^^^^^^ -note: required by a bound in `methods::Trait::leak_foo` - --> $DIR/maybe-bounds-in-traits.rs:101:9 - | -LL | fn leak_foo(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo` - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-58212.rs b/tests/ui/traits/generic-trait-impl-aliased-array-58212.rs index f266db603bf..a71194ba806 100644 --- a/tests/ui/issues/issue-58212.rs +++ b/tests/ui/traits/generic-trait-impl-aliased-array-58212.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/58212 //@ check-pass trait FromUnchecked { diff --git a/tests/ui/issues/issue-57156.rs b/tests/ui/traits/trait-object-lifetime-bounds-57156.rs index 12251509abd..8f5bef7fe13 100644 --- a/tests/ui/issues/issue-57156.rs +++ b/tests/ui/traits/trait-object-lifetime-bounds-57156.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57156 //@ check-pass trait Foo<Args> { diff --git a/tests/ui/issues/issue-56229.rs b/tests/ui/traits/trait-objects-with-supertraits-56229.rs index 1c6dd72ed2d..27cae968a6a 100644 --- a/tests/ui/issues/issue-56229.rs +++ b/tests/ui/traits/trait-objects-with-supertraits-56229.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56229 //@ check-pass trait Mirror { diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr index 9f289852809..4757daec997 100644 --- a/tests/ui/transmutability/uninhabited.stderr +++ b/tests/ui/transmutability/uninhabited.stderr @@ -41,10 +41,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:41:17 + --> $DIR/uninhabited.rs:41:9 | LL | assert!(false); - | ^^^^^ evaluation of `yawning_void_struct::_` failed here + | ^^^^^^^^^^^^^^ evaluation of `yawning_void_struct::_` failed here error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void` --> $DIR/uninhabited.rs:71:41 @@ -68,10 +68,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:63:17 + --> $DIR/uninhabited.rs:63:9 | LL | assert!(false); - | ^^^^^ evaluation of `yawning_void_enum::_` failed here + | ^^^^^^^^^^^^^^ evaluation of `yawning_void_enum::_` failed here error[E0277]: `u128` cannot be safely transmuted into `DistantVoid` --> $DIR/uninhabited.rs:92:43 @@ -95,10 +95,10 @@ LL | | }> | |__________^ required by this bound in `is_maybe_transmutable` error[E0080]: evaluation panicked: assertion failed: false - --> $DIR/uninhabited.rs:87:17 + --> $DIR/uninhabited.rs:87:9 | LL | assert!(false); - | ^^^^^ evaluation of `distant_void::_` failed here + | ^^^^^^^^^^^^^^ evaluation of `distant_void::_` failed here error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error` --> $DIR/uninhabited.rs:108:42 diff --git a/tests/ui/type-alias-impl-trait/fallback.rs b/tests/ui/type-alias-impl-trait/fallback.rs deleted file mode 100644 index a2f25acca0d..00000000000 --- a/tests/ui/type-alias-impl-trait/fallback.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Tests that we correctly handle opaque types being used opaquely, -// even within their defining scope. -// -#![feature(type_alias_impl_trait)] - -type Foo = impl Copy; - -enum Wrapper<T> { - First(T), - Second, -} - -// This method constrains `Foo` to be `bool` -#[define_opaque(Foo)] -fn constrained_foo() -> Foo { - true -} - -// This method does not constrain `Foo`. -// Per RFC 2071, function bodies may either -// fully constrain an opaque type, or place no -// constraints on it. -#[define_opaque(Foo)] -fn unconstrained_foo() -> Wrapper<Foo> { - Wrapper::Second - //~^ ERROR: type annotations needed -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/fallback.stderr b/tests/ui/type-alias-impl-trait/fallback.stderr deleted file mode 100644 index 1eb0afb13a8..00000000000 --- a/tests/ui/type-alias-impl-trait/fallback.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0283]: type annotations needed - --> $DIR/fallback.rs:25:5 - | -LL | fn unconstrained_foo() -> Wrapper<Foo> { - | ------------ type must be known at this point -LL | Wrapper::Second - | ^^^^^^^^^^^^^^^ - | | - | cannot infer type of the type parameter `T` declared on the enum `Wrapper` - | return type was inferred to be `Wrapper<_>` here - | - = note: cannot satisfy `_: Copy` -help: consider specifying the generic argument - | -LL | Wrapper::<T>::Second - | +++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs index 343bcae175a..2c41cb80aea 100644 --- a/tests/ui/type/type-name-basic.rs +++ b/tests/ui/type/type-name-basic.rs @@ -107,4 +107,19 @@ pub fn main() { } let a = Wrap(&()).get(); v!(a, "type_name_basic::main::Wrap<&()>::get::Info"); + + struct Issue146249<T>(T); + impl Issue146249<Box<dyn FnOnce()>> { + pub fn bar(&self) { + let f = || {}; + v!( + f, + "type_name_basic::main::Issue146249<\ + alloc::boxed::Box<dyn core::ops::function::FnOnce()>\ + >::bar::{{closure}}" + ); + } + } + let v: Issue146249<Box<dyn FnOnce()>> = Issue146249(Box::new(|| {})); + v.bar(); } diff --git a/tests/ui/issues/issue-57924.rs b/tests/ui/typeck/self-constructor-type-args-not-allowed-57924.rs index 8846912a8ff..2b3b11c3f38 100644 --- a/tests/ui/issues/issue-57924.rs +++ b/tests/ui/typeck/self-constructor-type-args-not-allowed-57924.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/57924 pub struct Gcm<E>(E); impl<E> Gcm<E> { diff --git a/tests/ui/issues/issue-57924.stderr b/tests/ui/typeck/self-constructor-type-args-not-allowed-57924.stderr index 40435fd0f0a..b5be5b39eb8 100644 --- a/tests/ui/issues/issue-57924.stderr +++ b/tests/ui/typeck/self-constructor-type-args-not-allowed-57924.stderr @@ -1,5 +1,5 @@ error[E0109]: type arguments are not allowed on self constructor - --> $DIR/issue-57924.rs:5:16 + --> $DIR/self-constructor-type-args-not-allowed-57924.rs:6:16 | LL | Self::<E>(e) | ---- ^ type argument not allowed diff --git a/tests/ui/issues/issue-56199.rs b/tests/ui/typeck/self-constructor-type-error-56199.rs index ba11582a9d5..b08d6918980 100644 --- a/tests/ui/issues/issue-56199.rs +++ b/tests/ui/typeck/self-constructor-type-error-56199.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/56199 enum Foo {} struct Bar {} diff --git a/tests/ui/issues/issue-56199.stderr b/tests/ui/typeck/self-constructor-type-error-56199.stderr index eb6d7005979..6e9d0fcd90c 100644 --- a/tests/ui/issues/issue-56199.stderr +++ b/tests/ui/typeck/self-constructor-type-error-56199.stderr @@ -1,5 +1,5 @@ error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/issue-56199.rs:6:17 + --> $DIR/self-constructor-type-error-56199.rs:7:17 | LL | let _ = Self; | ^^^^ @@ -7,7 +7,7 @@ LL | let _ = Self; = help: did you mean to use one of the enum's variants? error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/issue-56199.rs:8:17 + --> $DIR/self-constructor-type-error-56199.rs:9:17 | LL | let _ = Self(); | ^^^^^^ @@ -15,13 +15,13 @@ LL | let _ = Self(); = help: did you mean to use one of the enum's variants? error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/issue-56199.rs:15:17 + --> $DIR/self-constructor-type-error-56199.rs:16:17 | LL | let _ = Self; | ^^^^ help: use curly brackets: `Self { /* fields */ }` error: the `Self` constructor can only be used with tuple or unit structs - --> $DIR/issue-56199.rs:17:17 + --> $DIR/self-constructor-type-error-56199.rs:18:17 | LL | let _ = Self(); | ^^^^^^ help: use curly brackets: `Self { /* fields */ }` diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 924fb98ae18..96d85d1e7c1 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -55,7 +55,7 @@ use self::prelude::*; */ #[doc = "inner doc attribute"] #[allow(dead_code, unused_variables)] -#[no_std] +#[attr = NoStd] mod attributes { /// outer single-line doc comment diff --git a/triagebot.toml b/triagebot.toml index bf9bfee4306..2d58c616bc2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1308,21 +1308,32 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +# Content-based mentions + [mentions."#[miri::intrinsic_fallback_is_spec]"] type = "content" message = """ -`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, +⚠️ `#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, and explores the possible non-determinism of the intrinsic. """ cc = ["@rust-lang/miri"] + [mentions."#[rustc_allow_const_fn_unstable"] type = "content" message = """ -`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable +⚠️ `#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable implementation details on stable. """ cc = ["@rust-lang/wg-const-eval"] +[mentions."#[rustc_intrinsic_const_stable_indirect]"] +type = "content" +message = """ +⚠️ `#[rustc_intrinsic_const_stable_indirect]` controls whether intrinsics can be exposed to stable const +code; adding it needs t-lang approval. +""" +cc = ["@rust-lang/wg-const-eval"] + # ------------------------------------------------------------------------------ # PR assignments |
