diff options
1242 files changed, 21093 insertions, 11754 deletions
diff --git a/Cargo.lock b/Cargo.lock index cafc623c185..1c1607e4c1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -229,18 +229,12 @@ dependencies = [ ] [[package]] -name = "ar" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" - -[[package]] name = "ar_archive_writer" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733" dependencies = [ - "object 0.32.2", + "object 0.35.0", ] [[package]] @@ -1619,6 +1613,17 @@ dependencies = [ ] [[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1671,6 +1676,7 @@ dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", + "serde", ] [[package]] @@ -1881,6 +1887,12 @@ dependencies = [ ] [[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2110,6 +2122,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] +name = "lexopt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" + +[[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2623,7 +2641,7 @@ dependencies = [ "indexmap", "memchr", "ruzstd 0.5.0", - "wasmparser", + "wasmparser 0.118.2", ] [[package]] @@ -2639,6 +2657,15 @@ dependencies = [ [[package]] name = "object" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" @@ -3418,14 +3445,13 @@ dependencies = [ name = "run_make_support" version = "0.2.0" dependencies = [ - "ar", "bstr", "build_helper", - "gimli 0.28.1", + "gimli 0.31.0", "object 0.34.0", "regex", "similar", - "wasmparser", + "wasmparser 0.118.2", ] [[package]] @@ -3812,7 +3838,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder", + "wasm-encoder 0.200.0", "windows", ] @@ -4385,6 +4411,7 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ + "either", "itertools", "rustc_apfloat", "rustc_arena", @@ -5257,6 +5284,15 @@ dependencies = [ ] [[package]] +name = "spdx" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +dependencies = [ + "smallvec", +] + +[[package]] name = "spdx-expression" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6305,6 +6341,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] +name = "wasm-component-ld" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314d932d5e84c9678751b85498b1482b2f32f185744e449d3ce0b1d400376dad" +dependencies = [ + "anyhow", + "clap", + "lexopt", + "tempfile", + "wasmparser 0.210.0", + "wat", + "wit-component", +] + +[[package]] +name = "wasm-component-ld-wrapper" +version = "0.1.0" +dependencies = [ + "wasm-component-ld", +] + +[[package]] name = "wasm-encoder" version = "0.200.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6314,6 +6372,40 @@ dependencies = [ ] [[package]] +name = "wasm-encoder" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e3764d9d6edabd8c9e16195e177be0d20f6ab942ad18af52860f12f82bc59a" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-encoder" +version = "0.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e7d931a1120ef357f32b74547646b6fa68ea25e377772b72874b131a9ed70d4" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm-metadata" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "012729d1294907fcb0866f08460ab95426a6d0b176a599619b84cac7653452b4" +dependencies = [ + "anyhow", + "indexmap", + "serde", + "serde_derive", + "serde_json", + "spdx", + "wasm-encoder 0.210.0", + "wasmparser 0.210.0", +] + +[[package]] name = "wasmparser" version = "0.118.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6324,6 +6416,42 @@ dependencies = [ ] [[package]] +name = "wasmparser" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7bbcd21e7581619d9f6ca00f8c4f08f1cacfe58bf63f83af57cd0476f1026f5" +dependencies = [ + "ahash", + "bitflags 2.5.0", + "hashbrown", + "indexmap", + "semver", + "serde", +] + +[[package]] +name = "wast" +version = "211.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25506dd82d00da6b14a87436b3d52b1d264083fa79cdb72a0d1b04a8595ccaa" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder 0.211.1", +] + +[[package]] +name = "wat" +version = "1.211.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb716ca6c86eecac2d82541ffc39860118fc0af9309c4f2670637bea2e1bdd7d" +dependencies = [ + "wast", +] + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6551,6 +6679,43 @@ dependencies = [ ] [[package]] +name = "wit-component" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a450bdb5d032acf1fa0865451fa0c6f50e62f2d31eaa8dba967c2e2d068694a4" +dependencies = [ + "anyhow", + "bitflags 2.5.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.210.0", + "wasm-metadata", + "wasmparser 0.210.0", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.210.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a965cbd439af19a4b44a54a97ab8957d86f02d01320efc9e31c1d3605c6710" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.210.0", +] + +[[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index 93c520b0d68..ce87a8c20b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ members = [ "src/tools/opt-dist", "src/tools/coverage-dump", "src/tools/rustc-perf-wrapper", + "src/tools/wasm-component-ld", ] exclude = [ @@ -104,6 +105,9 @@ rustc-demangle.debug = 0 [profile.release.package.lld-wrapper] debug = 0 strip = true +[profile.release.package.wasm-component-ld-wrapper] +debug = 0 +strip = true [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on diff --git a/RELEASES.md b/RELEASES.md index 9e658568dc9..0ecd472efb6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -67,7 +67,7 @@ Stabilized APIs - [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add) - [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub) - [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub) -- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) +- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from) - [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from) - [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read) - [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile) @@ -91,9 +91,9 @@ Stabilized APIs - [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii) - [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start) - [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end) -- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) -- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) -- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) +- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii) +- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start) +- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end) - [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS) - [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits) - [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits) diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index 3cb56a7d312..5008069542f 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -27,7 +27,7 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] # tidy-alphabetical-start -jemalloc = ['jemalloc-sys'] +jemalloc = ['dep:jemalloc-sys'] llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler'] diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index 7ba58406ef1..29766fc9d87 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -34,7 +34,7 @@ fn main() { // See the comment at the top of this file for an explanation of this. - #[cfg(feature = "jemalloc-sys")] + #[cfg(feature = "jemalloc")] { use std::os::raw::{c_int, c_void}; diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 5031e7a6705..7448f066d0a 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -21,10 +21,10 @@ default = ["nightly", "randomize"] # rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain # without depending on rustc_data_structures, rustc_macros and rustc_serialize nightly = [ - "rustc_data_structures", + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_serialize", "rustc_index/nightly", - "rustc_macros", - "rustc_serialize", ] -randomize = ["rand", "rand_xoshiro", "nightly"] +randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"] # tidy-alphabetical-end diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 78332d66f03..52ec41f643c 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -627,7 +627,7 @@ impl Step for Size { #[inline] unsafe fn forward_unchecked(start: Self, count: usize) -> Self { - Self::from_bytes(u64::forward_unchecked(start.bytes(), count)) + Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) }) } #[inline] @@ -642,7 +642,7 @@ impl Step for Size { #[inline] unsafe fn backward_unchecked(start: Self, count: usize) -> Self { - Self::from_bytes(u64::backward_unchecked(start.bytes(), count)) + Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) }) } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 1c1163551db..39d0f2c7305 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -482,7 +482,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { - visit_opt(lt, |lt| noop_visit_lifetime(lt, vis)); + visit_opt(lt, |lt| vis.visit_lifetime(lt)); vis.visit_mt(mt); } TyKind::BareFn(bft) => { @@ -925,7 +925,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>( vis.visit_id(id); visit_attrs(attrs, vis); vis.visit_ident(ident); - visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); + visit_vec(bounds, |bound| vis.visit_param_bound(bound)); match kind { GenericParamKind::Lifetime => {} GenericParamKind::Type { default } => { @@ -983,7 +983,7 @@ fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mu } WherePredicate::RegionPredicate(rp) => { let WhereRegionPredicate { span, lifetime, bounds } = rp; - noop_visit_lifetime(lifetime, vis); + vis.visit_lifetime(lifetime); visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); vis.visit_span(span); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index efe19566152..9478da236c3 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -699,8 +699,7 @@ impl Token { false } - /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? - /// That is, is this a pre-parsed expression dropped into the token stream + /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { if let Interpolated(nt) = &self.kind diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index a78c91e0615..1905574073f 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -14,8 +14,8 @@ rustc_span = { path = "../rustc_span", optional = true } [features] default = ["nightly"] nightly = [ - "rustc_serialize", - "rustc_data_structures", - "rustc_macros", - "rustc_span", + "dep:rustc_serialize", + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_span", ] diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 666e7763e62..de0874af934 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -187,7 +187,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .emit(); } hir::InlineAsmOperand::Const { - anon_const: self.lower_anon_const(anon_const), + anon_const: self.lower_anon_const_to_anon_const(anon_const), } } InlineAsmOperand::Sym { sym } => { @@ -222,18 +222,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; // Wrap the expression in an AnonConst. - let parent_def_id = self.current_hir_id_owner; + let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); - self.create_def( - parent_def_id.def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - *op_sp, - ); + // HACK(min_generic_const_args): see lower_anon_const + if !expr.is_potential_trivial_const_arg() { + self.create_def( + parent_def_id, + node_id, + kw::Empty, + DefKind::AnonConst, + *op_sp, + ); + } let anon_const = AnonConst { id: node_id, value: P(expr) }; hir::InlineAsmOperand::SymFn { - anon_const: self.lower_anon_const(&anon_const), + anon_const: self.lower_anon_const_to_anon_const(&anon_const), } } } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 678cac210f4..6df2c15ce60 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -38,7 +38,7 @@ use crate::{ImplTraitPosition, ResolverAstLoweringExt}; -use super::{ImplTraitContext, LoweringContext, ParamMode}; +use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use ast::visit::Visitor; use hir::def::{DefKind, PartialRes, Res}; @@ -259,8 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self_param_id: pat_node_id, }; self_resolver.visit_block(block); - let block = this.lower_block(block, false); - this.mk_expr(hir::ExprKind::Block(block, None), block.span) + this.lower_target_expr(&block) } else { let pat_hir_id = this.lower_node_id(pat_node_id); this.generate_arg(pat_hir_id, span) @@ -273,26 +272,81 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - // Generates fully qualified call for the resulting body. + // FIXME(fn_delegation): Alternatives for target expression lowering: + // https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600. + fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> { + if block.stmts.len() == 1 + && let StmtKind::Expr(expr) = &block.stmts[0].kind + { + return self.lower_expr_mut(expr); + } + + let block = self.lower_block(block, false); + self.mk_expr(hir::ExprKind::Block(block, None), block.span) + } + + // Generates expression for the resulting body. If possible, `MethodCall` is used + // to allow autoref/autoderef for target expression. For example in: + // + // trait Trait : Sized { + // fn by_value(self) -> i32 { 1 } + // fn by_mut_ref(&mut self) -> i32 { 2 } + // fn by_ref(&self) -> i32 { 3 } + // } + // + // struct NewType(SomeType); + // impl Trait for NewType { + // reuse Trait::* { self.0 } + // } + // + // `self.0` will automatically coerce. fn finalize_body_lowering( &mut self, delegation: &Delegation, args: Vec<hir::Expr<'hir>>, span: Span, ) -> hir::Expr<'hir> { - let path = self.lower_qpath( - delegation.id, - &delegation.qself, - &delegation.path, - ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), - None, - ); - let args = self.arena.alloc_from_iter(args); - let path_expr = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); - let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(path_expr, args), span)); + let has_generic_args = + delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some()); + + let call = if self + .get_resolution_id(delegation.id, span) + .and_then(|def_id| Ok(self.has_self(def_id, span))) + .unwrap_or_default() + && delegation.qself.is_none() + && !has_generic_args + { + let ast_segment = delegation.path.segments.last().unwrap(); + let segment = self.lower_path_segment( + delegation.path.span, + ast_segment, + ParamMode::Optional, + ParenthesizedGenericArgs::Err, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + let segment = self.arena.alloc(segment); + + self.arena.alloc(hir::Expr { + hir_id: self.next_id(), + kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span), + span, + }) + } else { + let path = self.lower_qpath( + delegation.id, + &delegation.qself, + &delegation.path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span)); + self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span)) + }; let block = self.arena.alloc(hir::Block { stmts: &[], expr: Some(call), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 218fa974022..d870f9fe0ae 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -75,10 +75,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::ConstBlock(c) => { - let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock { - def_id: this.local_def_id(c.id), - hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), + let c = self.with_new_scopes(c.value.span, |this| { + let def_id = this.local_def_id(c.id); + hir::ConstBlock { + def_id, + hir_id: this.lower_node_id(c.id), + body: this.with_def_id_parent(def_id, |this| { + this.lower_const_body(c.value.span, Some(&c.value)) + }), + } }); hir::ExprKind::ConstBlock(c) } @@ -377,17 +382,14 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut generic_args = ThinVec::new(); for (idx, arg) in args.into_iter().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_hir_id_owner; + let parent_def_id = self.current_def_id_parent; let node_id = self.next_node_id(); - // Add a definition for the in-band const def. - self.create_def( - parent_def_id.def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - f.span, - ); + // HACK(min_generic_const_args): see lower_anon_const + if !arg.is_potential_trivial_const_arg() { + // Add a definition for the in-band const def. + self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); + } let anon_const = AnonConst { id: node_id, value: arg }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); @@ -622,6 +624,7 @@ impl<'hir> LoweringContext<'_, 'hir> { coroutine_source: hir::CoroutineSource, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { + let closure_def_id = self.local_def_id(closure_node_id); let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source); // The `async` desugaring takes a resume argument and maintains a `task_context`, @@ -672,22 +675,24 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime_elision_allowed: false, }); - let body = self.lower_body(move |this| { - this.coroutine_kind = Some(coroutine_kind); + let body = self.with_def_id_parent(closure_def_id, move |this| { + this.lower_body(move |this| { + this.coroutine_kind = Some(coroutine_kind); - let old_ctx = this.task_context; - if task_context.is_some() { - this.task_context = task_context; - } - let res = body(this); - this.task_context = old_ctx; + let old_ctx = this.task_context; + if task_context.is_some() { + this.task_context = task_context; + } + let res = body(this); + this.task_context = old_ctx; - (params, res) + (params, res) + }) }); // `static |<_task_context?>| -> <return_ty> { <body> }`: hir::ExprKind::Closure(self.arena.alloc(hir::Closure { - def_id: self.local_def_id(closure_node_id), + def_id: closure_def_id, binder: hir::ClosureBinder::Default, capture_clause, bound_generic_params: &[], @@ -966,27 +971,30 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { + let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; - let body_id = this.lower_fn_body(decl, |this| { - this.coroutine_kind = coroutine_kind; - let e = this.lower_expr_mut(body); - coroutine_kind = this.coroutine_kind; - e - }); - let coroutine_option = - this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); - (body_id, coroutine_option) + this.with_def_id_parent(closure_def_id, move |this| { + let mut coroutine_kind = if this + .attrs + .get(&closure_hir_id.local_id) + .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) + { + Some(hir::CoroutineKind::Coroutine(Movability::Movable)) + } else { + None + }; + let body_id = this.lower_fn_body(decl, |this| { + this.coroutine_kind = coroutine_kind; + let e = this.lower_expr_mut(body); + coroutine_kind = this.coroutine_kind; + e + }); + let coroutine_option = + this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); + (body_id, coroutine_option) + }) }); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); @@ -994,7 +1002,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { - def_id: self.local_def_id(closure_id), + def_id: closure_def_id, binder: binder_clause, capture_clause, bound_generic_params, @@ -1066,6 +1074,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn_decl_span: Span, fn_arg_span: Span, ) -> hir::ExprKind<'hir> { + let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); assert_matches!( @@ -1075,27 +1084,29 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let body = self.with_new_scopes(fn_decl_span, |this| { - let inner_decl = - FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - - // Transform `async |x: u8| -> X { ... }` into - // `|x: u8| || -> X { ... }`. - let body_id = this.lower_body(|this| { - let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( - &inner_decl, - |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), - fn_decl_span, - body.span, - coroutine_kind, - hir::CoroutineSource::Closure, - ); + this.with_def_id_parent(closure_def_id, |this| { + let inner_decl = + FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; + + // Transform `async |x: u8| -> X { ... }` into + // `|x: u8| || -> X { ... }`. + let body_id = this.lower_body(|this| { + let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments( + &inner_decl, + |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), + fn_decl_span, + body.span, + coroutine_kind, + hir::CoroutineSource::Closure, + ); - let hir_id = this.lower_node_id(coroutine_kind.closure_id()); - this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); + let hir_id = this.lower_node_id(coroutine_kind.closure_id()); + this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); - (parameters, expr) - }); - body_id + (parameters, expr) + }); + body_id + }) }); let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); @@ -1106,7 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None); let c = self.arena.alloc(hir::Closure { - def_id: self.local_def_id(closure_id), + def_id: closure_def_id, binder: binder_clause, capture_clause, bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 44f37b5533a..23729124e21 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -181,7 +181,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { intravisit::walk_generic_param(self, param); } - fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) { + fn visit_const_param_default(&mut self, param: HirId, ct: &'hir ConstArg<'hir>) { self.with_parent(param, |this| { intravisit::walk_const_param_default(this, ct); }) @@ -229,6 +229,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_anon_const(&mut self, constant: &'hir AnonConst) { + // FIXME: use real span? self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant)); self.with_parent(constant.hir_id, |this| { @@ -244,6 +245,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) { + // FIXME: use real span? + self.insert(DUMMY_SP, const_arg.hir_id, Node::ConstArg(const_arg)); + + self.with_parent(const_arg.hir_id, |this| { + intravisit::walk_const_arg(this, const_arg); + }); + } + fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { self.insert(expr.span, expr.hir_id, Node::Expr(expr)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 0ad23b53566..f990b4ba69b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -61,7 +61,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { for (def_id, info) in lctx.children { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!(matches!(owner, hir::MaybeOwner::Phantom)); + debug_assert!( + matches!(owner, hir::MaybeOwner::Phantom), + "duplicate copy of {def_id:?} in lctx.children" + ); *owner = info; } } @@ -713,7 +716,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id, def_id: self.local_def_id(v.id), data: self.lower_variant_data(hir_id, &v.data), - disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)), + disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)), ident: self.lower_ident(v.ident), span: self.lower_span(v.span), } @@ -1601,7 +1604,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let Some((span, hir_id, def_id)) = host_param_parts { let const_node_id = self.next_node_id(); - let anon_const = + let anon_const_did = self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span); let const_id = self.next_id(); @@ -1609,7 +1612,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let bool_id = self.next_id(); self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); - self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id))); + self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id))); let const_body = self.lower_body(|this| { ( @@ -1624,6 +1627,17 @@ impl<'hir> LoweringContext<'_, 'hir> { ) }); + let default_ac = self.arena.alloc(hir::AnonConst { + def_id: anon_const_did, + hir_id: const_id, + body: const_body, + span, + }); + let default_ct = self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(default_ac), + is_desugared_from_effects: false, + }); let param = hir::GenericParam { def_id, hir_id, @@ -1648,12 +1662,7 @@ impl<'hir> LoweringContext<'_, 'hir> { )), )), // FIXME(effects) we might not need a default. - default: Some(self.arena.alloc(hir::AnonConst { - def_id: anon_const, - hir_id: const_id, - body: const_body, - span, - })), + default: Some(default_ct), is_host_effect: true, synthetic: true, }, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 24748d2d009..0f5f4d8023b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -120,6 +120,18 @@ struct LoweringContext<'a, 'hir> { is_in_dyn_type: bool, current_hir_id_owner: hir::OwnerId, + /// Why do we need this in addition to [`Self::current_hir_id_owner`]? + /// + /// Currently (as of June 2024), anonymous constants are not HIR owners; however, + /// they do get their own DefIds. Some of these DefIds have to be created during + /// AST lowering, rather than def collection, because we can't tell until after + /// name resolution whether an anonymous constant will end up instead being a + /// [`hir::ConstArgKind::Path`]. However, to compute which generics are + /// available to an anonymous constant nested inside another, we need to make + /// sure that the parent is recorded as the parent anon const, not the enclosing + /// item. So we need to track parent defs differently from HIR owners, since they + /// will be finer-grained in the case of anon consts. + current_def_id_parent: LocalDefId, item_local_id_counter: hir::ItemLocalId, trait_map: ItemLocalMap<Box<[TraitCandidate]>>, @@ -162,6 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { attrs: SortedMap::default(), children: Vec::default(), current_hir_id_owner: hir::CRATE_OWNER_ID, + current_def_id_parent: CRATE_DEF_ID, item_local_id_counter: hir::ItemLocalId::ZERO, node_id_to_local_id: Default::default(), trait_map: Default::default(), @@ -592,7 +605,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO); debug_assert_eq!(_old, None); - let item = f(self); + let item = self.with_def_id_parent(def_id, f); debug_assert_eq!(def_id, item.def_id().def_id); // `f` should have consumed all the elements in these vectors when constructing `item`. debug_assert!(self.impl_trait_defs.is_empty()); @@ -612,6 +625,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.children.push((def_id, hir::MaybeOwner::Owner(info))); } + fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T { + let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent); + let result = f(self); + self.current_def_id_parent = current_def_id_parent; + result + } + /// Installs the remapping `remap` in scope while `f` is being executed. /// This causes references to the `LocalDefId` keys to be changed to /// refer to the values instead. @@ -806,7 +826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, kind, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( - self.current_hir_id_owner.def_id, + self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent? param, kw::UnderscoreLifetime, DefKind::LifetimeParam, @@ -1044,7 +1064,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AssocItemConstraintKind::Equality { term } => { let term = match term { Term::Ty(ty) => self.lower_ty(ty, itctx).into(), - Term::Const(c) => self.lower_anon_const(c).into(), + Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(), }; hir::AssocItemConstraintKind::Equality { term } } @@ -1150,42 +1170,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ty, ); - // Construct an AnonConst where the expr is the "ty"'s path. - - let parent_def_id = self.current_hir_id_owner; - let node_id = self.next_node_id(); - let span = self.lower_span(ty.span); - - // Add a definition for the in-band const def. - let def_id = self.create_def( - parent_def_id.def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - span, - ); - - let path_expr = Expr { - id: ty.id, - kind: ExprKind::Path(None, path.clone()), - span, - attrs: AttrVec::new(), - tokens: None, - }; - - let ct = self.with_new_scopes(span, |this| { - self.arena.alloc(hir::AnonConst { - def_id, - hir_id: this.lower_node_id(node_id), - body: this - .lower_const_body(path_expr.span, Some(&path_expr)), - span, - }) - }); - return GenericArg::Const(ConstArg { - value: ct, - is_desugared_from_effects: false, - }); + let ct = + self.lower_const_path_to_const_arg(path, res, ty.id, ty.span); + return GenericArg::Const(ct); } } } @@ -1193,10 +1180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArg::Type(self.lower_ty(ty, itctx)) } - ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg { - value: self.lower_anon_const(ct), - is_desugared_from_effects: false, - }), + ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)), } } @@ -1355,7 +1339,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Array(ty, length) => { hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) } - TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), + TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const_to_anon_const(expr)), TyKind::TraitObject(bounds, kind) => { let mut lifetime_bound = None; let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { @@ -1429,7 +1413,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); self.create_def( - self.current_hir_id_owner.def_id, + self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent? *def_node_id, ident.name, DefKind::TyParam, @@ -1637,7 +1621,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>], ) -> hir::TyKind<'hir> { let opaque_ty_def_id = self.create_def( - self.current_hir_id_owner.def_id, + self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent? opaque_ty_node_id, kw::Empty, DefKind::OpaqueTy, @@ -2222,7 +2206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { false } }) - .map(|def| self.lower_anon_const(def)); + .map(|def| self.lower_anon_const_to_const_arg(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2360,19 +2344,153 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { "using `_` for array lengths is unstable", ) .stash(c.value.span, StashKey::UnderscoreForArrayLengths); - hir::ArrayLen::Body(self.lower_anon_const(c)) + hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)) } } - _ => hir::ArrayLen::Body(self.lower_anon_const(c)), + _ => hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)), + } + } + + #[instrument(level = "debug", skip(self))] + fn lower_const_path_to_const_arg( + &mut self, + path: &Path, + res: Res<NodeId>, + ty_id: NodeId, + span: Span, + ) -> &'hir hir::ConstArg<'hir> { + let ct_kind = match res { + Res::Def(DefKind::ConstParam, _) => { + let qpath = self.lower_qpath( + ty_id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + hir::ConstArgKind::Path(qpath) + } + _ => { + // Construct an AnonConst where the expr is the "ty"'s path. + + let parent_def_id = self.current_def_id_parent; + let node_id = self.next_node_id(); + let span = self.lower_span(span); + + // Add a definition for the in-band const def. + let def_id = + self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let path_expr = Expr { + id: ty_id, + kind: ExprKind::Path(None, path.clone()), + span, + attrs: AttrVec::new(), + tokens: None, + }; + + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.with_def_id_parent(def_id, |this| { + this.lower_const_body(path_expr.span, Some(&path_expr)) + }), + span, + }) + }); + hir::ConstArgKind::Anon(ct) + } + }; + + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: ct_kind, + is_desugared_from_effects: false, + }) + } + + /// See [`hir::ConstArg`] for when to use this function vs + /// [`Self::lower_anon_const_to_anon_const`]. + fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> { + self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon)) + } + + #[instrument(level = "debug", skip(self))] + fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> { + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + let expr = if let ExprKind::Block(block, _) = &anon.value.kind + && let [stmt] = block.stmts.as_slice() + && let StmtKind::Expr(expr) = &stmt.kind + && let ExprKind::Path(..) = &expr.kind + { + expr + } else { + &anon.value + }; + let maybe_res = + self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); + debug!("res={:?}", maybe_res); + // FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path + if let Some(res) = maybe_res + && let Res::Def(DefKind::ConstParam, _) = res + && let ExprKind::Path(qself, path) = &expr.kind + { + let qpath = self.lower_qpath( + expr.id, + qself, + path, + ParamMode::Optional, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + return ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Path(qpath), + is_desugared_from_effects: false, + }; + } + + let lowered_anon = self.lower_anon_const_to_anon_const(anon); + ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(lowered_anon), + is_desugared_from_effects: false, } } - fn lower_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { - self.arena.alloc(self.with_new_scopes(c.value.span, |this| hir::AnonConst { - def_id: this.local_def_id(c.id), - hir_id: this.lower_node_id(c.id), - body: this.lower_const_body(c.value.span, Some(&c.value)), - span: this.lower_span(c.value.span), + /// See [`hir::ConstArg`] for when to use this function vs + /// [`Self::lower_anon_const_to_const_arg`]. + fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst { + if c.value.is_potential_trivial_const_arg() { + // HACK(min_generic_const_args): see DefCollector::visit_anon_const + // Over there, we guess if this is a bare param and only create a def if + // we think it's not. However we may can guess wrong (see there for example) + // in which case we have to create the def here. + self.create_def( + self.current_def_id_parent, + c.id, + kw::Empty, + DefKind::AnonConst, + c.value.span, + ); + } + + self.arena.alloc(self.with_new_scopes(c.value.span, |this| { + let def_id = this.local_def_id(c.id); + let hir_id = this.lower_node_id(c.id); + hir::AnonConst { + def_id, + hir_id, + body: this.with_def_id_parent(def_id, |this| { + this.lower_const_body(c.value.span, Some(&c.value)) + }), + span: this.lower_span(c.value.span), + } })) } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef408..8f7dd774207 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .type = inherent impl for this type .only_trait = only trait implementations may be annotated with {$annotation} -ast_passes_invalid_label = - invalid label name `{$name}` - ast_passes_invalid_unnamed_field = unnamed fields are not allowed outside of structs or unions .label = unnamed field declared here @@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot ast_passes_item_underscore = `{$kind}` items in this context need a name .label = `_` is not a valid name for this `{$kind}` item -ast_passes_keyword_lifetime = - lifetimes cannot use keyword names - ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern @@ -275,6 +269,9 @@ ast_passes_unsafe_negative_impl = negative impls cannot be unsafe .negative = negative because of this .unsafe = unsafe because of this +ast_passes_unsafe_static = + static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + ast_passes_visibility_not_permitted = visibility qualifiers are not permitted here .enum_variant = enum variants and their fields always share the visibility of the enum they are in diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52c..34aac6e4473 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -38,7 +38,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use thin_vec::thin_vec; -use crate::errors; +use crate::errors::{self, TildeConstReason}; /// Is `self` allowed semantically as the first parameter in an `FnDecl`? enum SelfSemantic { @@ -46,27 +46,12 @@ enum SelfSemantic { No, } -/// What is the context that prevents using `~const`? -// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're -// almost identical. This gets rid of an abstraction layer which might be considered bad. -enum DisallowTildeConstContext<'a> { - TraitObject, - Fn(FnKind<'a>), - Trait(Span), - TraitImpl(Span), - Impl(Span), - TraitAssocTy(Span), - TraitImplAssocTy(Span), - InherentAssocTy(Span), - Item, -} - -enum TraitOrTraitImpl<'a> { +enum TraitOrTraitImpl { Trait { span: Span, constness: Option<Span> }, - TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef }, + TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span }, } -impl<'a> TraitOrTraitImpl<'a> { +impl TraitOrTraitImpl { fn constness(&self) -> Option<Span> { match self { Self::Trait { constness: Some(span), .. } @@ -81,9 +66,9 @@ struct AstValidator<'a> { features: &'a Features, /// The span of the `extern` in an `extern { ... }` block, if any. - extern_mod: Option<&'a Item>, + extern_mod: Option<Span>, - outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>, + outer_trait_or_trait_impl: Option<TraitOrTraitImpl>, has_proc_macro_decls: bool, @@ -92,7 +77,7 @@ struct AstValidator<'a> { /// e.g., `impl Iterator<Item = impl Debug>`. outer_impl_trait: Option<Span>, - disallow_tilde_const: Option<DisallowTildeConstContext<'a>>, + disallow_tilde_const: Option<TildeConstReason>, /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item` /// or `Foo::Bar<impl Trait>` @@ -115,7 +100,7 @@ impl<'a> AstValidator<'a> { trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl { constness, polarity, - trait_ref, + trait_ref: trait_ref.path.span, }), ); f(self); @@ -145,7 +130,7 @@ impl<'a> AstValidator<'a> { fn with_tilde_const( &mut self, - disallowed: Option<DisallowTildeConstContext<'a>>, + disallowed: Option<TildeConstReason>, f: impl FnOnce(&mut Self), ) { let old = mem::replace(&mut self.disallow_tilde_const, disallowed); @@ -224,7 +209,7 @@ impl<'a> AstValidator<'a> { } } TyKind::TraitObject(..) => self - .with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| { + .with_tilde_const(Some(TildeConstReason::TraitObject), |this| { visit::walk_ty(this, t) }), TyKind::Path(qself, path) => { @@ -284,19 +269,6 @@ impl<'a> AstValidator<'a> { self.session.dcx() } - fn check_lifetime(&self, ident: Ident) { - let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty]; - if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); - } - } - - fn check_label(&self, ident: Ident) { - if ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); - } - } - fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) { if let VisibilityKind::Inherited = vis.kind { return; @@ -354,7 +326,7 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) { + fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) { let Const::Yes(span) = constness else { return; }; @@ -367,7 +339,7 @@ impl<'a> AstValidator<'a> { .. } = parent { - Some(trait_ref.path.span.shrink_to_lo()) + Some(trait_ref.shrink_to_lo()) } else { None }; @@ -466,6 +438,11 @@ impl<'a> AstValidator<'a> { } } + /// This ensures that items can only be `unsafe` (or unmarked) outside of extern + /// blocks. + /// + /// This additionally ensures that within extern blocks, items can only be + /// `safe`/`unsafe` inside of a `unsafe`-adorned extern block. fn check_item_safety(&self, span: Span, safety: Safety) { match self.extern_mod_safety { Some(extern_safety) => { @@ -579,7 +556,7 @@ impl<'a> AstValidator<'a> { } fn current_extern_span(&self) -> Span { - self.session.source_map().guess_head_span(self.extern_mod.unwrap().span) + self.session.source_map().guess_head_span(self.extern_mod.unwrap()) } /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`. @@ -923,16 +900,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.walk_ty(ty) } - fn visit_label(&mut self, label: &'a Label) { - self.check_label(label.ident); - visit::walk_label(self, label); - } - - fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) { - self.check_lifetime(lifetime.ident); - visit::walk_lifetime(self, lifetime); - } - fn visit_field_def(&mut self, field: &'a FieldDef) { self.deny_unnamed_field(field); visit::walk_field_def(self, field) @@ -980,7 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_vis(&item.vis); this.visit_ident(item.ident); let disallowed = matches!(constness, Const::No) - .then(|| DisallowTildeConstContext::TraitImpl(item.span)); + .then(|| TildeConstReason::TraitImpl { span: item.span }); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); this.visit_trait_ref(t); this.visit_ty(self_ty); @@ -1035,7 +1002,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_vis(&item.vis); this.visit_ident(item.ident); this.with_tilde_const( - Some(DisallowTildeConstContext::Impl(item.span)), + Some(TildeConstReason::Impl { span: item.span }), |this| this.visit_generics(generics), ); this.visit_ty(self_ty); @@ -1080,7 +1047,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { self.with_in_extern_mod(*safety, |this| { - let old_item = mem::replace(&mut this.extern_mod, Some(item)); + let old_item = mem::replace(&mut this.extern_mod, Some(item.span)); this.visibility_not_permitted( &item.vis, errors::VisibilityNotPermittedNote::IndividualForeignItems, @@ -1154,7 +1121,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_ident(item.ident); let disallowed = is_const_trait .is_none() - .then(|| DisallowTildeConstContext::Trait(item.span)); + .then(|| TildeConstReason::Trait { span: item.span }); this.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) @@ -1215,6 +1182,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Static(box StaticItem { expr, safety, .. }) => { self.check_item_safety(item.span, *safety); + if matches!(safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::UnsafeStatic { span: item.span }); + } if expr.is_none() { self.dcx().emit_err(errors::StaticWithoutBody { @@ -1371,13 +1341,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - fn visit_generic_param(&mut self, param: &'a GenericParam) { - if let GenericParamKind::Lifetime { .. } = param.kind { - self.check_lifetime(param.ident); - } - visit::walk_generic_param(self, param); - } - fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) { match bound { GenericBound::Trait(trait_ref, modifiers) => { @@ -1399,40 +1362,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span }); } (_, BoundConstness::Maybe(span), BoundPolarity::Positive) - if let Some(reason) = &self.disallow_tilde_const => + if let Some(reason) = self.disallow_tilde_const => { - let reason = match reason { - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { - errors::TildeConstReason::Closure - } - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { - errors::TildeConstReason::Function { ident: ident.span } - } - &DisallowTildeConstContext::Trait(span) => { - errors::TildeConstReason::Trait { span } - } - &DisallowTildeConstContext::TraitImpl(span) => { - errors::TildeConstReason::TraitImpl { span } - } - &DisallowTildeConstContext::Impl(span) => { - // FIXME(effects): Consider providing a help message or even a structured - // suggestion for moving such bounds to the assoc const fns if available. - errors::TildeConstReason::Impl { span } - } - &DisallowTildeConstContext::TraitAssocTy(span) => { - errors::TildeConstReason::TraitAssocTy { span } - } - &DisallowTildeConstContext::TraitImplAssocTy(span) => { - errors::TildeConstReason::TraitImplAssocTy { span } - } - &DisallowTildeConstContext::InherentAssocTy(span) => { - errors::TildeConstReason::InherentAssocTy { span } - } - DisallowTildeConstContext::TraitObject => { - errors::TildeConstReason::TraitObject - } - DisallowTildeConstContext::Item => errors::TildeConstReason::Item, - }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } ( @@ -1569,7 +1500,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .and_then(TraitOrTraitImpl::constness) .is_some(); - let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk)); + let disallowed = (!tilde_const_allowed).then(|| match fk { + FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span }, + FnKind::Closure(_, _, _) => TildeConstReason::Closure, + }); self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk)); } @@ -1664,12 +1598,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { AssocItemKind::Type(_) => { let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl { Some(TraitOrTraitImpl::Trait { .. }) => { - DisallowTildeConstContext::TraitAssocTy(item.span) + TildeConstReason::TraitAssocTy { span: item.span } } Some(TraitOrTraitImpl::TraitImpl { .. }) => { - DisallowTildeConstContext::TraitImplAssocTy(item.span) + TildeConstReason::TraitImplAssocTy { span: item.span } } - None => DisallowTildeConstContext::InherentAssocTy(item.span), + None => TildeConstReason::InherentAssocTy { span: item.span }, }); self.with_tilde_const(disallowed, |this| { this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)) @@ -1852,7 +1786,7 @@ pub fn check_crate( outer_trait_or_trait_impl: None, has_proc_macro_decls: false, outer_impl_trait: None, - disallow_tilde_const: Some(DisallowTildeConstContext::Item), + disallow_tilde_const: Some(TildeConstReason::Item), is_impl_trait_banned: false, extern_mod_safety: None, lint_buffer: lints, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb90476450..783bca6b695 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -10,21 +10,6 @@ use rustc_span::{symbol::Ident, Span, Symbol}; use crate::fluent_generated as fluent; #[derive(Diagnostic)] -#[diag(ast_passes_keyword_lifetime)] -pub struct KeywordLifetime { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(ast_passes_invalid_label)] -pub struct InvalidLabel { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] #[diag(ast_passes_visibility_not_permitted, code = E0449)] pub struct VisibilityNotPermitted { #[primary_span] @@ -240,6 +225,13 @@ pub struct InvalidSafetyOnBareFn { } #[derive(Diagnostic)] +#[diag(ast_passes_unsafe_static)] +pub struct UnsafeStatic { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { #[primary_span] @@ -612,7 +604,7 @@ pub struct TildeConstDisallowed { pub reason: TildeConstReason, } -#[derive(Subdiagnostic)] +#[derive(Subdiagnostic, Copy, Clone)] pub enum TildeConstReason { #[note(ast_passes_closure)] Closure, diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 8bf3e670ff2..4cd0d9cb294 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,7 +1,7 @@ use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; +use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError; use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::RegionVariableOrigin; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1cb74849017..f7e4bba3712 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -4,7 +4,7 @@ #![allow(rustc::untranslatable_diagnostic)] use either::Either; -use hir::ClosureKind; +use hir::{ClosureKind, Path}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; @@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::VarDebugInfoContents; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory, FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind, @@ -204,9 +205,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { is_loop_move = true; } + let mut has_suggest_reborrow = false; if !seen_spans.contains(&move_span) { if !closure { - self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans); + self.suggest_ref_or_clone( + mpi, + &mut err, + &mut in_pattern, + move_spans, + moved_place.as_ref(), + &mut has_suggest_reborrow, + ); } let msg_opt = CapturedMessageOpt { @@ -214,6 +223,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { is_loop_message, is_move_msg, is_loop_move, + has_suggest_reborrow, maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations .is_empty(), }; @@ -258,17 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) { if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { // We have a `&mut` ref, we need to reborrow on each iteration (#62112). - err.span_suggestion_verbose( - span.shrink_to_lo(), - format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place) - .map(|n| format!("`{n}`")) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *", - Applicability::MachineApplicable, - ); + self.suggest_reborrow(&mut err, span, moved_place); } } @@ -345,6 +345,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { err: &mut Diag<'infcx>, in_pattern: &mut bool, move_spans: UseSpans<'tcx>, + moved_place: PlaceRef<'tcx>, + has_suggest_reborrow: &mut bool, ) { let move_span = match move_spans { UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span, @@ -434,20 +436,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { let parent = self.infcx.tcx.parent_hir_node(expr.hir_id); let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind - && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id) { - (def_id.as_local(), args, 1) + (typeck.type_dependent_def_id(parent_expr.hir_id), args, 1) } else if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::Call(call, args) = parent_expr.kind && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() { - (def_id.as_local(), args, 0) + (Some(*def_id), args, 0) } else { (None, &[][..], 0) }; + + // If the moved value is a mut reference, it is used in a + // generic function and it's type is a generic param, it can be + // reborrowed to avoid moving. + // for example: + // struct Y(u32); + // x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`. + if let Some(def_id) = def_id + && self.infcx.tcx.def_kind(def_id).is_fn_like() + && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let ty::Param(_) = + self.infcx.tcx.fn_sig(def_id).skip_binder().skip_binder().inputs() + [pos + offset] + .kind() + { + let place = &self.move_data.move_paths[mpi].place; + let ty = place.ty(self.body, self.infcx.tcx).ty; + if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { + *has_suggest_reborrow = true; + self.suggest_reborrow(err, expr.span, moved_place); + return; + } + } + let mut can_suggest_clone = true; if let Some(def_id) = def_id - && let node = self.infcx.tcx.hir_node_by_def_id(def_id) + && let Some(local_def_id) = def_id.as_local() + && let node = self.infcx.tcx.hir_node_by_def_id(local_def_id) && let Some(fn_sig) = node.fn_sig() && let Some(ident) = node.ident() && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) @@ -546,7 +572,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } } - if let Some(pat) = finder.pat { + + self.suggest_ref_for_dbg_args(expr, place, move_span, err); + + // it's useless to suggest inserting `ref` when the span don't comes from local code + if let Some(pat) = finder.pat + && !move_span.is_dummy() + && !self.infcx.tcx.sess.source_map().is_imported(move_span) + { *in_pattern = true; let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())]; if let Some(pat) = finder.parent_pat { @@ -561,6 +594,78 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } + // for dbg!(x) which may take ownership, suggest dbg!(&x) instead + // but here we actually do not check whether the macro name is `dbg!` + // so that we may extend the scope a bit larger to cover more cases + fn suggest_ref_for_dbg_args( + &self, + body: &hir::Expr<'_>, + place: &Place<'tcx>, + move_span: Span, + err: &mut Diag<'infcx>, + ) { + let var_info = self.body.var_debug_info.iter().find(|info| match info.value { + VarDebugInfoContents::Place(ref p) => p == place, + _ => false, + }); + let arg_name = if let Some(var_info) = var_info { + var_info.name + } else { + return; + }; + struct MatchArgFinder { + expr_span: Span, + match_arg_span: Option<Span>, + arg_name: Symbol, + } + impl Visitor<'_> for MatchArgFinder { + fn visit_expr(&mut self, e: &hir::Expr<'_>) { + // dbg! is expanded into a match pattern, we need to find the right argument span + if let hir::ExprKind::Match(expr, ..) = &e.kind + && let hir::ExprKind::Path(hir::QPath::Resolved( + _, + path @ Path { segments: [seg], .. }, + )) = &expr.kind + && seg.ident.name == self.arg_name + && self.expr_span.source_callsite().contains(expr.span) + { + self.match_arg_span = Some(path.span); + } + hir::intravisit::walk_expr(self, e); + } + } + + let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name }; + finder.visit_expr(body); + if let Some(macro_arg_span) = finder.match_arg_span { + err.span_suggestion_verbose( + macro_arg_span.shrink_to_lo(), + "consider borrowing instead of transferring ownership", + "&", + Applicability::MachineApplicable, + ); + } + } + + pub fn suggest_reborrow( + &self, + err: &mut Diag<'infcx>, + span: Span, + moved_place: PlaceRef<'tcx>, + ) { + err.span_suggestion_verbose( + span.shrink_to_lo(), + format!( + "consider creating a fresh reborrow of {} here", + self.describe_place(moved_place) + .map(|n| format!("`{n}`")) + .unwrap_or_else(|| "the mutable reference".to_string()), + ), + "&mut *", + Applicability::MachineApplicable, + ); + } + fn report_use_of_uninitialized( &self, mpi: MovePathIndex, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index b7fbb71a0cf..f97459d16ba 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -768,10 +768,11 @@ struct CapturedMessageOpt { is_loop_message: bool, is_move_msg: bool, is_loop_move: bool, + has_suggest_reborrow: bool, maybe_reinitialized_locations_is_empty: bool, } -impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { +impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// Finds the spans associated to a move or copy of move_place at location. pub(super) fn move_spans( &self, @@ -997,7 +998,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn explain_captures( &mut self, - err: &mut Diag<'_>, + err: &mut Diag<'infcx>, span: Span, move_span: Span, move_spans: UseSpans<'tcx>, @@ -1009,6 +1010,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { is_loop_message, is_move_msg, is_loop_move, + has_suggest_reborrow, maybe_reinitialized_locations_is_empty, } = msg_opt; if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans { @@ -1182,18 +1184,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { if let ty::Ref(_, _, hir::Mutability::Mut) = moved_place.ty(self.body, self.infcx.tcx).ty.kind() { - // If we are in a loop this will be suggested later. - if !is_loop_move { - err.span_suggestion_verbose( + // Suggest `reborrow` in other place for following situations: + // 1. If we are in a loop this will be suggested later. + // 2. If the moved value is a mut reference, it is used in a + // generic function and the corresponding arg's type is generic param. + if !is_loop_move && !has_suggest_reborrow { + self.suggest_reborrow( + err, move_span.shrink_to_lo(), - format!( - "consider creating a fresh reborrow of {} here", - self.describe_place(moved_place.as_ref()) - .map(|n| format!("`{n}`")) - .unwrap_or_else(|| "the mutable reference".to_string()), - ), - "&mut *", - Applicability::MachineApplicable, + moved_place.as_ref(), ); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 4b6c1b29f28..fcf23aa4785 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -554,6 +554,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { is_loop_message: false, is_move_msg: false, is_loop_move: false, + has_suggest_reborrow: false, maybe_reinitialized_locations_is_empty: true, }; if let Some(use_spans) = use_spans { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 55147ee337f..6cf797b4761 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -10,11 +10,11 @@ use rustc_hir::GenericBound::Trait; use rustc_hir::QPath::Resolved; use rustc_hir::WherePredicate::BoundPredicate; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; -use rustc_infer::infer::error_reporting::nice_region_error::{ +use rustc_infer::error_reporting::infer::nice_region_error::{ self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, }; -use rustc_infer::infer::error_reporting::region::unexpected_hidden_region_diagnostic; +use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 02b9c2d48b1..8da4d80badf 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -309,14 +309,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } - fn tag(&self) -> &'static str { - "nll::subtype" - } - #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, @@ -370,7 +366,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx // shouldn't ever fail. Instead, it unconditionally emits an // alias-relate goal. assert!(!self.type_checker.infcx.next_trait_solver()); - self.tcx().dcx().span_delayed_bug( + self.cx().dcx().span_delayed_bug( self.span(), "failure to relate an opaque to itself should result in an error later on", ); @@ -540,7 +536,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating &mut self, obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, ) { - let tcx = self.tcx(); + let tcx = self.cx(); let param_env = self.param_env(); self.register_goals( obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)), @@ -559,7 +555,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating .into_iter() .map(|goal| { Obligation::new( - self.tcx(), + self.cx(), ObligationCause::dummy_with_span(self.span()), goal.param_env, goal.predicate, diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 58928815e89..bffd5672b9b 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,6 +4,7 @@ use crate::errors; use rustc_ast::attr::mk_attr; use rustc_ast::token; use rustc_ast::{self as ast, AttrItem, AttrStyle}; +use rustc_parse::parser::ForceCollect; use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::FileName; @@ -17,13 +18,14 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { )); let start_span = parser.token.span; - let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) { - Ok(ai) => ai, - Err(err) => { - err.emit(); - continue; - } - }; + let AttrItem { unsafety, path, args, tokens: _ } = + match parser.parse_attr_item(ForceCollect::No) { + Ok(ai) => ai, + Err(err) => { + err.emit(); + continue; + } + }; let end_span = parser.token.span; if parser.token != token::Eof { psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) }); diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 3f23e0d9e04..1935005a08c 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, + ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; use rustc_session::Session; @@ -9,7 +9,7 @@ pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) } fn create_dll_import_lib( diff --git a/compiler/rustc_codegen_gcc/.rustfmt.toml b/compiler/rustc_codegen_gcc/.rustfmt.toml index 2a35f0230c6..725aec25a07 100644 --- a/compiler/rustc_codegen_gcc/.rustfmt.toml +++ b/compiler/rustc_codegen_gcc/.rustfmt.toml @@ -1 +1,3 @@ +version = "Two" use_small_heuristics = "Max" +merge_derives = false diff --git a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs index aee46afaeb0..cbf590c0c32 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs @@ -34,7 +34,7 @@ impl Args { "--out-path" => match args.next() { Some(path) if !path.is_empty() => out_path = Some(path), _ => { - return Err("Expected an argument after `--out-path`, found nothing".into()) + return Err("Expected an argument after `--out-path`, found nothing".into()); } }, "--help" => { diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs index 965aedd8be8..bbb711c8428 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/config.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -54,7 +54,7 @@ impl ConfigFile { config.gcc_path = Some(value.as_str().to_string()) } ("gcc-path", _) => { - return failed_config_parsing(config_file, "Expected a string for `gcc-path`") + return failed_config_parsing(config_file, "Expected a string for `gcc-path`"); } ("download-gccjit", TomlValue::Boolean(value)) => { config.download_gccjit = Some(*value) @@ -63,7 +63,7 @@ impl ConfigFile { return failed_config_parsing( config_file, "Expected a boolean for `download-gccjit`", - ) + ); } _ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)), } @@ -73,7 +73,7 @@ impl ConfigFile { return failed_config_parsing( config_file, "At least one of `gcc-path` or `download-gccjit` value must be set", - ) + ); } (Some(_), Some(true)) => { println!( @@ -144,7 +144,7 @@ impl ConfigInfo { _ => { return Err( "Expected a value after `--target-triple`, found nothing".to_string() - ) + ); } }, "--out-dir" => match args.next() { @@ -158,7 +158,7 @@ impl ConfigInfo { self.config_file = Some(arg.to_string()); } _ => { - return Err("Expected a value after `--config-file`, found nothing".to_string()) + return Err("Expected a value after `--config-file`, found nothing".to_string()); } }, "--release-sysroot" => self.sysroot_release_channel = true, @@ -169,7 +169,7 @@ impl ConfigInfo { self.cg_gcc_path = Some(arg.into()); } _ => { - return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()) + return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string()); } }, "--use-backend" => match args.next() { @@ -277,7 +277,7 @@ impl ConfigInfo { self.gcc_path = match gcc_path { Some(path) => path, None => { - return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),)) + return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),)); } }; Ok(()) diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 8d088a3aac3..06f28d13fb3 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -109,7 +109,7 @@ impl TestArg { test_arg.flags.extend_from_slice(&["--features".into(), feature]); } _ => { - return Err("Expected an argument after `--features`, found nothing".into()) + return Err("Expected an argument after `--features`, found nothing".into()); } }, "--use-system-gcc" => { @@ -458,11 +458,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> { .map_err(|error| format!("Failed to retrieve cargo path: {:?}", error)) .and_then(|cargo| { let cargo = cargo.trim().to_owned(); - if cargo.is_empty() { - Err(format!("`cargo` path is empty")) - } else { - Ok(cargo) - } + if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) } })?; let rustc = String::from_utf8( run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))? @@ -471,11 +467,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> { .map_err(|error| format!("Failed to retrieve rustc path: {:?}", error)) .and_then(|rustc| { let rustc = rustc.trim().to_owned(); - if rustc.is_empty() { - Err(format!("`rustc` path is empty")) - } else { - Ok(rustc) - } + if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) } })?; let llvm_filecheck = match run_command_with_env( &[ diff --git a/compiler/rustc_codegen_gcc/build_system/src/utils.rs b/compiler/rustc_codegen_gcc/build_system/src/utils.rs index 3bba8df6c65..e338d1b4992 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/utils.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/utils.rs @@ -175,11 +175,7 @@ pub fn cargo_install(to_install: &str) -> Result<(), String> { pub fn get_os_name() -> Result<String, String> { let output = run_command(&[&"uname"], None)?; let name = std::str::from_utf8(&output.stdout).unwrap_or("").trim().to_string(); - if !name.is_empty() { - Ok(name) - } else { - Err("Failed to retrieve the OS name".to_string()) - } + if !name.is_empty() { Ok(name) } else { Err("Failed to retrieve the OS name".to_string()) } } #[derive(Default, PartialEq)] diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 166dd080cf2..0a99e7213be 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -26,11 +26,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } else { false }; - if on_stack { - param.to_lvalue().get_address(None) - } else { - param.to_rvalue() - } + if on_stack { param.to_lvalue().get_address(None) } else { param.to_rvalue() } } } diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs index 73ff0c37b66..21676f5dbb6 100644 --- a/compiler/rustc_codegen_gcc/src/archive.rs +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, + ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER, }; use rustc_session::Session; @@ -11,7 +11,7 @@ pub(crate) struct ArArchiveBuilderBuilder; impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> { - Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER)) } fn create_dll_import_lib( diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index aa485846cd4..1da691252ab 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -858,11 +858,7 @@ fn modifier_to_gcc( InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { - if modifier == Some('v') { - None - } else { - modifier - } + if modifier == Some('v') { None } else { modifier } } InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 307348f595d..b9e4bd79fe1 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1043,11 +1043,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let llty = place.layout.scalar_pair_element_gcc_type(self, i); let load = self.load(llty, llptr, align); scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { - self.trunc(load, self.type_i1()) - } else { - load - } + if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } }; OperandValue::Pair( @@ -1795,18 +1791,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX. let int_max = |signed: bool, int_width: u64| -> u128 { let shift_amount = 128 - int_width; - if signed { - i128::MAX as u128 >> shift_amount - } else { - u128::MAX >> shift_amount - } + if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount } }; let int_min = |signed: bool, int_width: u64| -> i128 { - if signed { - i128::MIN >> (128 - int_width) - } else { - 0 - } + if signed { i128::MIN >> (128 - int_width) } else { 0 } }; let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 19333689aaa..70f0dc37e39 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -58,11 +58,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { - if type_is_pointer(typ) { - self.context.new_null(typ) - } else { - self.const_int(typ, 0) - } + if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index ca376029735..5969d9b9144 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -21,14 +21,16 @@ pub(crate) unsafe fn codegen( ) { let llcx = &*module_llvm.llcx; let llmod = module_llvm.llmod(); - let usize = match tcx.sess.target.pointer_width { - 16 => llvm::LLVMInt16TypeInContext(llcx), - 32 => llvm::LLVMInt32TypeInContext(llcx), - 64 => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), + let usize = unsafe { + match tcx.sess.target.pointer_width { + 16 => llvm::LLVMInt16TypeInContext(llcx), + 32 => llvm::LLVMInt32TypeInContext(llcx), + 64 => llvm::LLVMInt64TypeInContext(llcx), + tws => bug!("Unsupported target word size for int: {}", tws), + } }; - let i8 = llvm::LLVMInt8TypeInContext(llcx); - let i8p = llvm::LLVMPointerTypeInContext(llcx, 0); + let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; + let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -73,23 +75,25 @@ pub(crate) unsafe fn codegen( true, ); - // __rust_alloc_error_handler_should_panic - let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } - let val = tcx.sess.opts.unstable_opts.oom.should_panic(); - let llval = llvm::LLVMConstInt(i8, val as u64, False); - llvm::LLVMSetInitializer(ll_g, llval); - - let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + unsafe { + // __rust_alloc_error_handler_should_panic + let name = OomStrategy::SYMBOL; + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + if tcx.sess.default_hidden_visibility() { + llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + } + let val = tcx.sess.opts.unstable_opts.oom.should_panic(); + let llval = llvm::LLVMConstInt(i8, val as u64, False); + llvm::LLVMSetInitializer(ll_g, llval); + + let name = NO_ALLOC_SHIM_IS_UNSTABLE; + let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); + if tcx.sess.default_hidden_visibility() { + llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); + } + let llval = llvm::LLVMConstInt(i8, 0, False); + llvm::LLVMSetInitializer(ll_g, llval); } - let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::LLVMSetInitializer(ll_g, llval); if tcx.sess.opts.debuginfo != DebugInfo::None { let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a354f3d3536..f46c6b1c498 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -15,8 +15,8 @@ use crate::errors::{ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::{ - get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder, - ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind, + try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder, + ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER, }; use tracing::trace; @@ -115,7 +115,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { if true { Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() }) } else { - Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols)) + Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER)) } } @@ -291,59 +291,84 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files. // As such we need to use LLVM for them. + +static LLVM_OBJECT_READER: ObjectReader = ObjectReader { + get_symbols: get_llvm_object_symbols, + is_64_bit_object_file: llvm_is_64_bit_object_file, + is_ec_object_file: llvm_is_ec_object_file, + get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment, +}; + +fn should_use_llvm_reader(buf: &[u8]) -> bool { + let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) }; + + // COFF bigobj file, msvc LTO file or import library. See + // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51 + let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF"); + + is_bitcode || is_unsupported_windows_obj_file +} + #[deny(unsafe_op_in_unsafe_fn)] fn get_llvm_object_symbols( buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>, ) -> io::Result<bool> { - let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) }; + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.get_symbols)(buf, f); + } - // COFF bigobj file, msvc LTO file or import library. See - // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51 - let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF"); + let mut state = Box::new(f); - if is_bitcode || is_unsupported_windows_obj_file { - let mut state = Box::new(f); - - let err = unsafe { - llvm::LLVMRustGetSymbols( - buf.as_ptr(), - buf.len(), - std::ptr::addr_of_mut!(*state) as *mut c_void, - callback, - error_callback, - ) - }; + let err = unsafe { + llvm::LLVMRustGetSymbols( + buf.as_ptr(), + buf.len(), + std::ptr::addr_of_mut!(*state) as *mut c_void, + callback, + error_callback, + ) + }; - if err.is_null() { - return Ok(true); - } else { - return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); - } + if err.is_null() { + return Ok(true); + } else { + return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); + } - unsafe extern "C" fn callback( - state: *mut c_void, - symbol_name: *const c_char, - ) -> *mut c_void { - let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; - match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { - Ok(()) => std::ptr::null_mut(), - Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, - } + unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void { + let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; + match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { + Ok(()) => std::ptr::null_mut(), + Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, } + } - unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { - let error = unsafe { CStr::from_ptr(error) }; - Box::into_raw(Box::new(io::Error::new( - io::ErrorKind::Other, - format!("LLVM error: {}", error.to_string_lossy()), - ))) as *mut c_void - } - } else { - get_native_object_symbols(buf, f) + unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void { + let error = unsafe { CStr::from_ptr(error) }; + Box::into_raw(Box::new(io::Error::new( + io::ErrorKind::Other, + format!("LLVM error: {}", error.to_string_lossy()), + ))) as *mut c_void } } +fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool { + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.is_64_bit_object_file)(buf); + } + + unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) } +} + +fn llvm_is_ec_object_file(buf: &[u8]) -> bool { + if !should_use_llvm_reader(buf) { + return (DEFAULT_OBJECT_READER.is_ec_object_file)(buf); + } + + unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) } +} + impl<'a> LlvmArchiveBuilder<'a> { fn build_with_llvm(&mut self, output: &Path) -> io::Result<bool> { let kind = &*self.sess.target.archive_format; diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index aff3e3d7076..aef672631c8 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -727,7 +727,7 @@ pub unsafe fn optimize_thin_module( // into that context. One day, however, we may do this for upstream // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. - let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); + let llcx = unsafe { llvm::LLVMRustContextCreate(cgcx.fewer_names) }; let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _; let mut module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, @@ -750,7 +750,9 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) { + if unsafe { + !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) + } { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); @@ -760,7 +762,8 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) { + if unsafe { !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) } + { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve"); @@ -770,7 +773,8 @@ pub unsafe fn optimize_thin_module( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) { + if unsafe { !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) } + { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize"); @@ -779,7 +783,9 @@ pub unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); - if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) { + if unsafe { + !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) + } { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); diff --git a/compiler/rustc_codegen_llvm/src/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs index 2741f7d848e..2eee9f8c5a3 100644 --- a/compiler/rustc_codegen_llvm/src/back/profiling.rs +++ b/compiler/rustc_codegen_llvm/src/back/profiling.rs @@ -46,13 +46,15 @@ pub unsafe extern "C" fn selfprofile_before_pass_callback( pass_name: *const c_char, ir_name: *const c_char, ) { - let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); - let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); - let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); - llvm_self_profiler.before_pass_callback(pass_name, ir_name); + unsafe { + let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8"); + let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8"); + llvm_self_profiler.before_pass_callback(pass_name, ir_name); + } } pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) { - let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>); + let llvm_self_profiler = unsafe { &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>) }; llvm_self_profiler.after_pass_callback(); } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 2fda19bf0c9..ddd52e80edf 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -428,9 +428,10 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void if user.is_null() { return; } - let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)); + let (cgcx, dcx) = + unsafe { *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)) }; - match llvm::diagnostic::Diagnostic::unpack(info) { + match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } { llvm::diagnostic::InlineAsm(inline) => { report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source); } @@ -454,14 +455,14 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void }); } llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => { - let message = llvm::build_string(|s| { + let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); dcx.emit_warn(FromLlvmDiag { message }); } llvm::diagnostic::Unsupported(diagnostic_ref) => { - let message = llvm::build_string(|s| { + let message = llvm::build_string(|s| unsafe { llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) }) .expect("non-UTF8 diagnostic"); @@ -564,37 +565,39 @@ pub(crate) unsafe fn llvm_optimize( let llvm_plugins = config.llvm_plugins.join(","); - let result = llvm::LLVMRustOptimize( - module.module_llvm.llmod(), - &*module.module_llvm.tm, - to_pass_builder_opt_level(opt_level), - opt_stage, - cgcx.opts.cg.linker_plugin_lto.enabled(), - config.no_prepopulate_passes, - config.verify_llvm_ir, - using_thin_buffers, - config.merge_functions, - unroll_loops, - config.vectorize_slp, - config.vectorize_loop, - config.no_builtins, - config.emit_lifetime_markers, - sanitizer_options.as_ref(), - pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.instrument_coverage, - instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.instrument_gcov, - pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), - config.debug_info_for_profiling, - llvm_selfprofiler, - selfprofile_before_pass_callback, - selfprofile_after_pass_callback, - extra_passes.as_ptr().cast(), - extra_passes.len(), - llvm_plugins.as_ptr().cast(), - llvm_plugins.len(), - ); + let result = unsafe { + llvm::LLVMRustOptimize( + module.module_llvm.llmod(), + &*module.module_llvm.tm, + to_pass_builder_opt_level(opt_level), + opt_stage, + cgcx.opts.cg.linker_plugin_lto.enabled(), + config.no_prepopulate_passes, + config.verify_llvm_ir, + using_thin_buffers, + config.merge_functions, + unroll_loops, + config.vectorize_slp, + config.vectorize_loop, + config.no_builtins, + config.emit_lifetime_markers, + sanitizer_options.as_ref(), + pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_coverage, + instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.instrument_gcov, + pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), + config.debug_info_for_profiling, + llvm_selfprofiler, + selfprofile_before_pass_callback, + selfprofile_after_pass_callback, + extra_passes.as_ptr().cast(), + extra_passes.len(), + llvm_plugins.as_ptr().cast(), + llvm_plugins.len(), + ) + }; result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } @@ -617,7 +620,7 @@ pub(crate) unsafe fn optimize( if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); let out = path_to_c_string(&out); - llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); + unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) }; } if let Some(opt_level) = config.opt_level { @@ -627,7 +630,7 @@ pub(crate) unsafe fn optimize( _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ => llvm::OptStage::PreLinkNoLTO, }; - return llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage); + return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }; } Ok(()) } @@ -692,10 +695,12 @@ pub(crate) unsafe fn codegen( where F: FnOnce(&'ll mut PassManager<'ll>) -> R, { - let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) + unsafe { + let cpm = llvm::LLVMCreatePassManager(); + llvm::LLVMAddAnalysisPasses(tm, cpm); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); + f(cpm) + } } // Two things to note: @@ -757,7 +762,9 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + unsafe { + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + } } } @@ -793,7 +800,8 @@ pub(crate) unsafe fn codegen( cursor.position() as size_t } - let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback); + let result = + unsafe { llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback) }; if result == llvm::LLVMRustResult::Success { record_artifact_size(&cgcx.prof, "llvm_ir", &out); @@ -812,22 +820,24 @@ pub(crate) unsafe fn codegen( // binaries. So we must clone the module to produce the asm output // if we are also producing object code. let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj { - llvm::LLVMCloneModule(llmod) + unsafe { llvm::LLVMCloneModule(llmod) } } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &path, - None, - llvm::FileType::AssemblyFile, - &cgcx.prof, - ) - })?; + unsafe { + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file( + dcx, + tm, + cpm, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + &cgcx.prof, + ) + })?; + } } match config.emit_obj { @@ -851,18 +861,20 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &obj_out, - dwo_out, - llvm::FileType::ObjectFile, - &cgcx.prof, - ) - })?; + unsafe { + with_codegen(tm, llmod, config.no_builtins, |cpm| { + write_output_file( + dcx, + tm, + cpm, + llmod, + &obj_out, + dwo_out, + llvm::FileType::ObjectFile, + &cgcx.prof, + ) + })?; + } } EmitObj::Bitcode => { @@ -1013,44 +1025,46 @@ unsafe fn embed_bitcode( // reason (see issue #90326 for historical background). let is_aix = target_is_aix(cgcx); let is_apple = target_is_apple(cgcx); - if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") { - // We don't need custom section flags, create LLVM globals. - let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.module".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); - - let section = bitcode_section_name(cgcx); - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - - let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr().cast(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); - let section = if is_apple { - c"__LLVM,__cmdline" - } else if is_aix { - c".info" + unsafe { + if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") { + // We don't need custom section flags, create LLVM globals. + let llconst = common::bytes_in_context(llcx, bitcode); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + c"rustc.embedded.module".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); + + let section = bitcode_section_name(cgcx); + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); + + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); + let llglobal = llvm::LLVMAddGlobal( + llmod, + common::val_ty(llconst), + c"rustc.embedded.cmdline".as_ptr().cast(), + ); + llvm::LLVMSetInitializer(llglobal, llconst); + let section = if is_apple { + c"__LLVM,__cmdline" + } else if is_aix { + c".info" + } else { + c".llvmcmd" + }; + llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); + llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); } else { - c".llvmcmd" - }; - llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); - llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); - } else { - // We need custom section flags, so emit module-level inline assembly. - let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; - let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); - let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); - llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + // We need custom section flags, so emit module-level inline assembly. + let section_flags = if cgcx.is_pe_coff { "n" } else { "e" }; + let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes()); + llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); + } } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index a2314f4850c..164d1681a36 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -495,8 +495,14 @@ impl<'ll> CodegenCx<'ll, '_> { } // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. - if self.tcx.sess.target.is_like_wasm { + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext2( self.llcx, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 77beb9a6bb3..49677dcf12f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -120,7 +120,7 @@ pub unsafe fn create_module<'ll>( ) -> &'ll llvm::Module { let sess = tcx.sess; let mod_name = SmallCStr::new(mod_name); - let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) }; let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); @@ -153,11 +153,14 @@ pub unsafe fn create_module<'ll>( // Ensure the data-layout values hardcoded remain the defaults. { let tm = crate::back::write::create_informational_target_machine(tcx.sess); - llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); + unsafe { + llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); + } - let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod); - let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) - .expect("got a non-UTF8 data-layout from LLVM"); + let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) }; + let llvm_data_layout = + str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes()) + .expect("got a non-UTF8 data-layout from LLVM"); if target_data_layout != llvm_data_layout { tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { @@ -170,20 +173,28 @@ pub unsafe fn create_module<'ll>( } let data_layout = SmallCStr::new(&target_data_layout); - llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + unsafe { + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + } let llvm_target = SmallCStr::new(&sess.target.llvm_target); - llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + unsafe { + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + } let reloc_model = sess.relocation_model(); if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) { - llvm::LLVMRustSetModulePICLevel(llmod); + unsafe { + llvm::LLVMRustSetModulePICLevel(llmod); + } // PIE is potentially more effective than PIC, but can only be used in executables. // If all our outputs are executables, then we can relax PIC to PIE. if reloc_model == RelocModel::Pie || tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable) { - llvm::LLVMRustSetModulePIELevel(llmod); + unsafe { + llvm::LLVMRustSetModulePIELevel(llmod); + } } } @@ -192,95 +203,109 @@ pub unsafe fn create_module<'ll>( // longer jumps) if a larger code model is used with a smaller one. // // See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323. - llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); + unsafe { + llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model())); + } // If skipping the PLT is enabled, we need to add some module metadata // to ensure intrinsic calls don't use it. if !sess.needs_plt() { let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + unsafe { + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + } } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - canonical_jump_tables, - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + canonical_jump_tables, + 1, + ); + } } // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - enable_split_lto_unit, - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + enable_split_lto_unit, + 1, + ); + } } // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { let kcfi = c"kcfi".as_ptr().cast(); - llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + unsafe { + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + } } // Control Flow Guard is currently only supported by the MSVC linker on Windows. if sess.target.is_like_msvc { - match sess.opts.cg.control_flow_guard { - CFGuard::Disabled => {} - CFGuard::NoChecks => { - // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 1, - ) - } - CFGuard::Checks => { - // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"cfguard".as_ptr() as *const _, - 2, - ) + unsafe { + match sess.opts.cg.control_flow_guard { + CFGuard::Disabled => {} + CFGuard::NoChecks => { + // Set `cfguard=1` module flag to emit metadata only. + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"cfguard".as_ptr() as *const _, + 1, + ) + } + CFGuard::Checks => { + // Set `cfguard=2` module flag to emit metadata and checks. + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"cfguard".as_ptr() as *const _, + 2, + ) + } } } } if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"branch-target-enforcement".as_ptr().cast(), - bti.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address".as_ptr().cast(), - pac_ret.is_some().into(), - ); - let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-all".as_ptr().cast(), - pac_opts.leaf.into(), - ); - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Min, - c"sign-return-address-with-bkey".as_ptr().cast(), - u32::from(pac_opts.key == PAuthKey::B), - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"branch-target-enforcement".as_ptr().cast(), + bti.into(), + ); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address".as_ptr().cast(), + pac_ret.is_some().into(), + ); + let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address-all".as_ptr().cast(), + pac_opts.leaf.into(), + ); + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Min, + c"sign-return-address-with-bkey".as_ptr().cast(), + u32::from(pac_opts.key == PAuthKey::B), + ); + } } else { bug!( "branch-protection used on non-AArch64 target; \ @@ -291,39 +316,47 @@ pub unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-branch".as_ptr().cast(), - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"cf-protection-branch".as_ptr().cast(), + 1, + ); + } } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Override, - c"cf-protection-return".as_ptr().cast(), - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Override, + c"cf-protection-return".as_ptr().cast(), + 1, + ); + } } if sess.opts.unstable_opts.virtual_function_elimination { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"Virtual Function Elim".as_ptr().cast(), - 1, - ); + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"Virtual Function Elim".as_ptr().cast(), + 1, + ); + } } // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - llvm::LLVMRustAddModuleFlagU32( - llmod, - llvm::LLVMModFlagBehavior::Warning, - c"ehcontguard".as_ptr() as *const _, - 1, - ) + unsafe { + llvm::LLVMRustAddModuleFlagU32( + llmod, + llvm::LLVMModFlagBehavior::Warning, + c"ehcontguard".as_ptr() as *const _, + 1, + ) + } } // Insert `llvm.ident` metadata. @@ -333,16 +366,20 @@ pub unsafe fn create_module<'ll>( #[allow(clippy::option_env_unwrap)] let rustc_producer = format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION")); - let name_metadata = llvm::LLVMMDStringInContext( - llcx, - rustc_producer.as_ptr().cast(), - rustc_producer.as_bytes().len() as c_uint, - ); - llvm::LLVMAddNamedMetadataOperand( - llmod, - c"llvm.ident".as_ptr(), - llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), - ); + let name_metadata = unsafe { + llvm::LLVMMDStringInContext( + llcx, + rustc_producer.as_ptr().cast(), + rustc_producer.as_bytes().len() as c_uint, + ) + }; + unsafe { + llvm::LLVMAddNamedMetadataOperand( + llmod, + c"llvm.ident".as_ptr(), + llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), + ); + } // Emit RISC-V specific target-abi metadata // to workaround lld as the LTO plugin not @@ -351,13 +388,15 @@ pub unsafe fn create_module<'ll>( // If llvm_abiname is empty, emit nothing. let llvm_abiname = &sess.target.options.llvm_abiname; if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { - llvm::LLVMRustAddModuleFlagString( - llmod, - llvm::LLVMModFlagBehavior::Error, - c"target-abi".as_ptr(), - llvm_abiname.as_ptr().cast(), - llvm_abiname.len(), - ); + unsafe { + llvm::LLVMRustAddModuleFlagString( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"target-abi".as_ptr(), + llvm_abiname.as_ptr().cast(), + llvm_abiname.len(), + ); + } } // Add module flags specified via -Z llvm_module_flag @@ -375,7 +414,7 @@ pub unsafe fn create_module<'ll>( // We already checked this during option parsing _ => unreachable!(), }; - llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) + unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } } llmod diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ed0989a0ba4..a96993b9aba 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -216,7 +216,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: &ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<(), FatalError> { - back::write::optimize(cgcx, dcx, module, config) + unsafe { back::write::optimize(cgcx, dcx, module, config) } } fn optimize_fat( cgcx: &CodegenContext<Self>, @@ -230,7 +230,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { cgcx: &CodegenContext<Self>, thin: ThinModule<Self>, ) -> Result<ModuleCodegen<Self::Module>, FatalError> { - back::lto::optimize_thin_module(thin, cgcx) + unsafe { back::lto::optimize_thin_module(thin, cgcx) } } unsafe fn codegen( cgcx: &CodegenContext<Self>, @@ -238,7 +238,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { module: ModuleCodegen<Self::Module>, config: &ModuleConfig, ) -> Result<CompiledModule, FatalError> { - back::write::codegen(cgcx, dcx, module, config) + unsafe { back::write::codegen(cgcx, dcx, module, config) } } fn prepare_thin( module: ModuleCodegen<Self::Module>, diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index f9b28178ddb..73e1b08a3d7 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -40,7 +40,7 @@ impl<'ll> OptimizationDiagnostic<'ll> { let mut filename = None; let pass_name = super::build_string(|pass_name| { message = super::build_string(|message| { - filename = super::build_string(|filename| { + filename = super::build_string(|filename| unsafe { super::LLVMRustUnpackOptimizationDiagnostic( di, pass_name, @@ -91,7 +91,7 @@ impl SrcMgrDiagnostic { let mut ranges = [0; 8]; let mut num_ranges = ranges.len() / 2; let message = super::build_string(|message| { - buffer = super::build_string(|buffer| { + buffer = super::build_string(|buffer| unsafe { have_source = super::LLVMRustUnpackSMDiagnostic( diag, message, @@ -134,7 +134,9 @@ impl InlineAsmDiagnostic { let mut message = None; let mut level = super::DiagnosticLevel::Error; - super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + unsafe { + super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message); + } InlineAsmDiagnostic { level, @@ -146,7 +148,8 @@ impl InlineAsmDiagnostic { unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self { let mut cookie = 0; - let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)); + let smdiag = + unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { level: smdiag.level, cookie: cookie.into(), @@ -170,44 +173,46 @@ pub enum Diagnostic<'ll> { impl<'ll> Diagnostic<'ll> { pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self { use super::DiagnosticKind as Dk; - let kind = super::LLVMRustGetDiagInfoKind(di); - match kind { - Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), + unsafe { + let kind = super::LLVMRustGetDiagInfoKind(di); + match kind { + Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)), - Dk::OptimizationRemark => { - Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) - } - Dk::OptimizationRemarkOther => { - Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) - } - Dk::OptimizationRemarkMissed => { - Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) - } + Dk::OptimizationRemark => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di)) + } + Dk::OptimizationRemarkOther => { + Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di)) + } + Dk::OptimizationRemarkMissed => { + Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di)) + } - Dk::OptimizationRemarkAnalysis => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) - } + Dk::OptimizationRemarkAnalysis => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di)) + } - Dk::OptimizationRemarkAnalysisFPCommute => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) - } + Dk::OptimizationRemarkAnalysisFPCommute => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di)) + } - Dk::OptimizationRemarkAnalysisAliasing => { - Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) - } + Dk::OptimizationRemarkAnalysisAliasing => { + Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di)) + } - Dk::OptimizationFailure => { - Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) - } + Dk::OptimizationFailure => { + Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di)) + } - Dk::PGOProfile => PGO(di), - Dk::Linker => Linker(di), - Dk::Unsupported => Unsupported(di), + Dk::PGOProfile => PGO(di), + Dk::Linker => Linker(di), + Dk::Unsupported => Unsupported(di), - Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), + Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)), - _ => UnknownDiagnostic(di), + _ => UnknownDiagnostic(di), + } } } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index e0bf6110cdf..ae46200d3f5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2440,4 +2440,8 @@ extern "C" { callback: GetSymbolsCallback, error_callback: GetSymbolsErrorCallback, ) -> *mut c_void; + + pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool; + + pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool; } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 0e89e66be49..98dc8ac86d2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -49,12 +49,16 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); - llvm::LLVMRustInstallErrorHandlers(); + unsafe { + llvm::LLVMRustInstallErrorHandlers(); + } // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog // box for the purpose of launching a debugger. However, on CI this will // cause it to hang until it times out, which can take several hours. if std::env::var_os("CI").is_some() { - llvm::LLVMRustDisableSystemDialogsOnCrash(); + unsafe { + llvm::LLVMRustDisableSystemDialogsOnCrash(); + } } fn llvm_arg_to_arg_name(full_arg: &str) -> &str { @@ -124,12 +128,12 @@ unsafe fn configure_llvm(sess: &Session) { } if sess.opts.unstable_opts.llvm_time_trace { - llvm::LLVMRustTimeTraceProfilerInitialize(); + unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }; } rustc_llvm::initialize_available_targets(); - llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); + unsafe { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()) }; } pub fn time_trace_profiler_finish(file_name: &Path) { @@ -442,8 +446,8 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { - let out = &mut *(out as *mut &mut String); - let bytes = slice::from_raw_parts(string as *const u8, len); + let out = unsafe { &mut *(out as *mut &mut String) }; + let bytes = unsafe { slice::from_raw_parts(string as *const u8, len) }; write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); } unsafe { diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index a7df08421a3..282a186be99 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -108,8 +108,8 @@ impl CodegenCx<'_, '_> { llval: &llvm::Value, is_declaration: bool, ) -> bool { - let linkage = llvm::LLVMRustGetLinkage(llval); - let visibility = llvm::LLVMRustGetVisibility(llval); + let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) }; + let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) }; if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { return true; @@ -145,8 +145,8 @@ impl CodegenCx<'_, '_> { } // Thread-local variables generally don't support copy relocations. - let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) - .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True); + let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) } + .is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True); if is_thread_local_var { return false; } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3771fc6b0a2..f7b5b0f310b 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.2.0" +ar_archive_writer = "0.3.0" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90" diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c99118f5156..ae649cd77c4 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -6,8 +6,8 @@ use rustc_span::symbol::Symbol; use super::metadata::search_for_section; -pub use ar_archive_writer::get_native_object_symbols; use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember}; +pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER}; use object::read::archive::ArchiveFile; use object::read::macho::FatArch; use tempfile::Builder as TempFileBuilder; @@ -89,8 +89,7 @@ pub trait ArchiveBuilder { #[must_use = "must call build() to finish building the archive"] pub struct ArArchiveBuilder<'a> { sess: &'a Session, - get_object_symbols: - fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result<bool>, + object_reader: &'static ObjectReader, src_archives: Vec<(PathBuf, Mmap)>, // Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs @@ -105,14 +104,8 @@ enum ArchiveEntry { } impl<'a> ArArchiveBuilder<'a> { - pub fn new( - sess: &'a Session, - get_object_symbols: fn( - buf: &[u8], - f: &mut dyn FnMut(&[u8]) -> io::Result<()>, - ) -> io::Result<bool>, - ) -> ArArchiveBuilder<'a> { - ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] } + pub fn new(sess: &'a Session, object_reader: &'static ObjectReader) -> ArArchiveBuilder<'a> { + ArArchiveBuilder { sess, object_reader, src_archives: vec![], entries: vec![] } } } @@ -267,7 +260,7 @@ impl<'a> ArArchiveBuilder<'a> { entries.push(NewArchiveMember { buf: data, - get_symbols: self.get_object_symbols, + object_reader: self.object_reader, member_name: String::from_utf8(entry_name).unwrap(), mtime: 0, uid: 0, @@ -294,7 +287,13 @@ impl<'a> ArArchiveBuilder<'a> { let mut archive_tmpfile = File::create_new(&archive_tmpfile_path) .map_err(|err| io_error_context("couldn't create the temp file", err))?; - write_archive_to_stream(&mut archive_tmpfile, &entries, archive_kind, false)?; + write_archive_to_stream( + &mut archive_tmpfile, + &entries, + archive_kind, + false, + /* is_ec = */ self.sess.target.arch == "arm64ec", + )?; let any_entries = !entries.is_empty(); drop(entries); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1f627353d54..8e07d128dbd 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -750,7 +750,7 @@ fn link_natively( for print in &sess.opts.prints { if print.kind == PrintKind::LinkArgs { - let content = format!("{cmd:?}"); + let content = format!("{cmd:?}\n"); print.out.overwrite(&content, sess); } } diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index cb6244050df..5291cad148e 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -72,7 +72,7 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> { B::optimize_fat(cgcx, &mut module)?; Ok(module) } - LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin), + LtoModuleCodegen::Thin(thin) => unsafe { B::optimize_thin(cgcx, thin) }, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 822f5c2c44a..35e9a3b7dc2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -37,13 +37,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn eval_unevaluated_mir_constant_to_valtree( &self, constant: &mir::ConstOperand<'tcx>, - ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> { + ) -> Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled> { let uv = match self.monomorphize(constant.const_) { mir::Const::Unevaluated(uv, _) => uv.shrink(), mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style // simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)), + rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate @@ -70,6 +70,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = self .eval_unevaluated_mir_constant_to_valtree(constant) .ok() + .map(|x| x.ok()) .flatten() .map(|val| { let field_ty = ty.builtin_index().unwrap(); diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 4ae4816e33a..3a6dc81eff1 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -27,15 +27,15 @@ pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value}; // We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes. const VALTREE_MAX_NODES: usize = 100000; -pub(crate) enum ValTreeCreationError { +pub(crate) enum ValTreeCreationError<'tcx> { NodesOverflow, /// Values of this type, or this particular value, are not supported as valtrees. - NonSupportedType, + NonSupportedType(Ty<'tcx>), } -pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>; +pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>; -impl From<InterpErrorInfo<'_>> for ValTreeCreationError { - fn from(err: InterpErrorInfo<'_>) -> Self { +impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> { + fn from(err: InterpErrorInfo<'tcx>) -> Self { ty::tls::with(|tcx| { bug!( "Unexpected Undefined Behavior error during valtree construction: {}", diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 2e8ad445cf5..3bc01510730 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -120,13 +120,13 @@ fn const_to_valtree_inner<'tcx>( // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. if matches!(val.layout.abi, Abi::ScalarPair(..)) { - return Err(ValTreeCreationError::NonSupportedType); + return Err(ValTreeCreationError::NonSupportedType(ty)); } let val = val.to_scalar(); // We are in the CTFE machine, so ptr-to-int casts will fail. // This can only be `Ok` if `val` already is an integer. let Ok(val) = val.try_to_scalar_int() else { - return Err(ValTreeCreationError::NonSupportedType); + return Err(ValTreeCreationError::NonSupportedType(ty)); }; // It's just a ScalarInt! Ok(ty::ValTree::Leaf(val)) @@ -134,7 +134,7 @@ fn const_to_valtree_inner<'tcx>( // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to // agree with runtime equality tests. - ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType), + ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Ref(_, _, _) => { let derefd_place = ecx.deref_pointer(place)?; @@ -148,7 +148,7 @@ fn const_to_valtree_inner<'tcx>( // resolving their backing type, even if we can do that at const eval time. We may // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future, // but it is unclear if this is useful. - ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType), + ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Tuple(elem_tys) => { branches(ecx, place, elem_tys.len(), None, num_nodes) @@ -156,7 +156,7 @@ fn const_to_valtree_inner<'tcx>( ty::Adt(def, _) => { if def.is_union() { - return Err(ValTreeCreationError::NonSupportedType); + return Err(ValTreeCreationError::NonSupportedType(ty)); } else if def.variants().is_empty() { bug!("uninhabited types should have errored and never gotten converted to valtree") } @@ -180,7 +180,7 @@ fn const_to_valtree_inner<'tcx>( | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType), + | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)), } } @@ -251,7 +251,7 @@ pub(crate) fn eval_to_valtree<'tcx>( let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes); match valtree_result { - Ok(valtree) => Ok(Some(valtree)), + Ok(valtree) => Ok(Ok(valtree)), Err(err) => { let did = cid.instance.def_id(); let global_const_id = cid.display(tcx); @@ -262,7 +262,7 @@ pub(crate) fn eval_to_valtree<'tcx>( tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id }); Err(handled.into()) } - ValTreeCreationError::NonSupportedType => Ok(None), + ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)), } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 83b61ab1749..bd2a5812cfa 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -401,15 +401,46 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } (ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => { let val = self.read_immediate(src)?; - if data_a.principal() == data_b.principal() { - // A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables. - // (But currently mismatching vtables violate the validity invariant so UB is triggered anyway.) - return self.write_immediate(*val, dest); - } + // Take apart the old pointer, and find the dynamic type. let (old_data, old_vptr) = val.to_scalar_pair(); let old_data = old_data.to_pointer(self)?; let old_vptr = old_vptr.to_pointer(self)?; let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?; + + // Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces + // our destination trait. + if cfg!(debug_assertions) { + let vptr_entry_idx = + self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty)); + let vtable_entries = self.vtable_entries(data_a.principal(), ty); + if let Some(entry_idx) = vptr_entry_idx { + let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) = + vtable_entries.get(entry_idx) + else { + span_bug!( + self.cur_span(), + "invalid vtable entry index in {} -> {} upcast", + src_pointee_ty, + dest_pointee_ty + ); + }; + let erased_trait_ref = upcast_trait_ref + .map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r)); + assert!( + data_b + .principal() + .is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b)) + ); + } else { + // In this case codegen would keep using the old vtable. We don't want to do + // that as it has the wrong trait. The reason codegen can do this is that + // one vtable is a prefix of the other, so we double-check that. + let vtable_entries_b = self.vtable_entries(data_b.principal(), ty); + assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b); + }; + } + + // Get the destination trait vtable and return that. let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 6d3e5ea1031..9fddeec2973 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -2,11 +2,15 @@ use std::cell::Cell; use std::{fmt, mem}; use either::{Either, Left, Right}; +use rustc_infer::infer::at::ToTrace; +use rustc_infer::traits::ObligationCause; +use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, info, info_span, instrument, trace}; use rustc_errors::DiagCtxtHandle; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; +use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir; use rustc_middle::mir::interpret::{ CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo, @@ -640,6 +644,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + /// Check if the two things are equal in the current param_env, using an infctx to get proper + /// equality checks. + pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool + where + T: PartialEq + TypeFoldable<TyCtxt<'tcx>> + ToTrace<'tcx>, + { + // Fast path: compare directly. + if a == b { + return true; + } + // Slow path: spin up an inference context to check if these traits are sufficiently equal. + let infcx = self.tcx.infer_ctxt().build(); + let ocx = ObligationCtxt::new(&infcx); + let cause = ObligationCause::dummy_with_span(self.cur_span()); + // equate the two trait refs after normalization + let a = ocx.normalize(&cause, self.param_env, a); + let b = ocx.normalize(&cause, self.param_env, b); + if ocx.eq(&cause, self.param_env, a, b).is_ok() { + if ocx.select_all_or_error().is_empty() { + // All good. + return true; + } + } + return false; + } + /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a /// frame which is not `#[track_caller]`. This matches the `caller_location` intrinsic, /// and is primarily intended for the panic machinery. diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 25f6bd64055..56d3dc94104 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use either::Either; -use rustc_middle::ty::TyCtxt; use tracing::trace; use rustc_middle::{ @@ -867,7 +866,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; // Obtain the underlying trait we are working on, and the adjusted receiver argument. - let (dyn_trait, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) = + let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) = receiver_place.layout.ty.kind() { let recv = self.unpack_dyn_star(&receiver_place, data)?; @@ -898,20 +897,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { (receiver_trait.principal(), dyn_ty, receiver_place.ptr()) }; - // Now determine the actual method to call. We can do that in two different ways and - // compare them to ensure everything fits. - let vtable_entries = if let Some(dyn_trait) = dyn_trait { - let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty); - let trait_ref = self.tcx.erase_regions(trait_ref); - self.tcx.vtable_entries(trait_ref) - } else { - TyCtxt::COMMON_VTABLE_ENTRIES - }; + // Now determine the actual method to call. Usually we use the easy way of just + // looking up the method at index `idx`. + let vtable_entries = self.vtable_entries(trait_, dyn_ty); let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else { // FIXME(fee1-dead) these could be variants of the UB info enum instead of this throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method); }; trace!("Virtual call dispatches to {fn_inst:#?}"); + // We can also do the lookup based on `def_id` and `dyn_ty`, and check that that + // produces the same result. if cfg!(debug_assertions) { let tcx = *self.tcx; diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index bd2c6519421..fb50661b826 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,10 +1,7 @@ -use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt, VtblEntry}; use rustc_target::abi::{Align, Size}; -use rustc_trait_selection::traits::ObligationCtxt; use tracing::trace; use super::util::ensure_monomorphic_enough; @@ -47,6 +44,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok((layout.size, layout.align.abi)) } + pub(super) fn vtable_entries( + &self, + trait_: Option<ty::PolyExistentialTraitRef<'tcx>>, + dyn_ty: Ty<'tcx>, + ) -> &'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(trait_ref); + self.tcx.vtable_entries(trait_ref) + } else { + TyCtxt::COMMON_VTABLE_ENTRIES + } + } + /// Check that the given vtable trait is valid for a pointer/reference/place with the given /// expected trait type. pub(super) fn check_vtable_for_type( @@ -54,28 +65,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>, expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ) -> InterpResult<'tcx> { - // Fast path: if they are equal, it's all fine. - if expected_trait.principal() == vtable_trait { - return Ok(()); - } - if let (Some(expected_trait), Some(vtable_trait)) = - (expected_trait.principal(), vtable_trait) - { - // Slow path: spin up an inference context to check if these traits are sufficiently equal. - let infcx = self.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); - let cause = ObligationCause::dummy_with_span(self.cur_span()); - // equate the two trait refs after normalization - let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait); - let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait); - if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() { - if ocx.select_all_or_error().is_empty() { - // All good. - return Ok(()); - } - } + let eq = match (expected_trait.principal(), vtable_trait) { + (Some(a), Some(b)) => self.eq_in_param_env(a, b), + (None, None) => true, + _ => false, + }; + if !eq { + throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); } - throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait }); + Ok(()) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 7fea0617666..4da7e233889 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -34,7 +34,6 @@ use super::{ Pointer, Projectable, Scalar, ValueVisitor, }; -// for the validation errors use super::InterpError::UndefinedBehavior as Ub; use super::InterpError::Unsupported as Unsup; use super::UndefinedBehaviorInfo::*; diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index e5e733439ea..3794a6e043c 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -56,5 +56,5 @@ portable-atomic = "1.5.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon"] +rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "dep:rustc-rayon"] # tidy-alphabetical-end diff --git a/compiler/rustc_error_codes/src/error_codes/E0120.md b/compiler/rustc_error_codes/src/error_codes/E0120.md index dc7258d8731..aa701df5774 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0120.md +++ b/compiler/rustc_error_codes/src/error_codes/E0120.md @@ -1,7 +1,7 @@ -Drop was implemented on a trait, which is not allowed: only structs and -enums can implement Drop. +`Drop` was implemented on a trait object or reference, which is not allowed; +only structs, enums, and unions can implement Drop. -Erroneous code example: +Erroneous code examples: ```compile_fail,E0120 trait MyTrait {} @@ -11,8 +11,16 @@ impl Drop for MyTrait { } ``` -A workaround for this problem is to wrap the trait up in a struct, and implement -Drop on that: +```compile_fail,E0120 +struct Concrete {} + +impl Drop for &'_ mut Concrete { + fn drop(&mut self) {} +} +``` + +A workaround for traits is to create a wrapper struct with a generic type, +add a trait bound to the type, and implement `Drop` on the wrapper: ``` trait MyTrait {} @@ -24,13 +32,13 @@ impl <T: MyTrait> Drop for MyWrapper<T> { ``` -Alternatively, wrapping trait objects requires something: +Alternatively, the `Drop` wrapper can contain the trait object: ``` trait MyTrait {} -//or Box<MyTrait>, if you wanted an owned trait object -struct MyWrapper<'a> { foo: &'a MyTrait } +// or Box<dyn MyTrait>, if you wanted an owned trait object +struct MyWrapper<'a> { foo: &'a dyn MyTrait } impl <'a> Drop for MyWrapper<'a> { fn drop(&mut self) {} diff --git a/compiler/rustc_error_codes/src/error_codes/E0158.md b/compiler/rustc_error_codes/src/error_codes/E0158.md index 03b93d925c1..c31f1e13bee 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0158.md +++ b/compiler/rustc_error_codes/src/error_codes/E0158.md @@ -1,5 +1,4 @@ -An associated `const`, `const` parameter or `static` has been referenced -in a pattern. +A generic parameter or `static` has been referenced in a pattern. Erroneous code example: @@ -15,25 +14,25 @@ trait Bar { fn test<A: Bar>(arg: Foo) { match arg { - A::X => println!("A::X"), // error: E0158: associated consts cannot be - // referenced in patterns + A::X => println!("A::X"), // error: E0158: constant pattern depends + // on a generic parameter Foo::Two => println!("Two") } } ``` -Associated `const`s cannot be referenced in patterns because it is impossible +Generic parameters cannot be referenced in patterns because it is impossible for the compiler to prove exhaustiveness (that some pattern will always match). Take the above example, because Rust does type checking in the *generic* method, not the *monomorphized* specific instance. So because `Bar` could have -theoretically infinite implementations, there's no way to always be sure that +theoretically arbitrary implementations, there's no way to always be sure that `A::X` is `Foo::One`. So this code must be rejected. Even if code can be proven exhaustive by a programmer, the compiler cannot currently prove this. -The same holds true of `const` parameters and `static`s. +The same holds true of `static`s. -If you want to match against an associated `const`, `const` parameter or -`static` consider using a guard instead: +If you want to match against a `const` that depends on a generic parameter or a +`static`, consider using a guard instead: ``` trait Trait { diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md new file mode 100644 index 00000000000..da08cde3010 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -0,0 +1,39 @@ +Functions marked as `C-cmse-nonsecure-call` place restrictions on their +inputs and outputs. + +- inputs must fit in the 4 available 32-bit argument registers. Alignment +is relevant. +- outputs must either fit in 4 bytes, or be a foundational type of +size 8 (`i64`, `u64`, `f64`). +- no generics can be used in the signature + +For more information, +see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). + +Erroneous code example: + +```ignore (only fails on supported targets) +#![feature(abi_c_cmse_nonsecure_call)] + +#[no_mangle] +pub fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, +) -> u32 { + f(1, 2, 3, 4, 5) +} +``` + +Arguments' alignment is respected. In the example below, padding is inserted +so that the `u64` argument is passed in registers r2 and r3. There is then no +room left for the final `f32` argument + +```ignore (only fails on supported targets) +#![feature(abi_c_cmse_nonsecure_call)] + +#[no_mangle] +pub fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, +) -> u32 { + f(1, 2, 3.0) +} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d13d5e1bca2..2a7bc2501c0 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -536,6 +536,7 @@ E0794: 0794, E0795: 0795, E0796: 0796, E0797: 0797, +E0798: 0798, ); ) } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index dbbd948fd70..2964ac8cc58 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -119,6 +119,8 @@ impl MetaVarExpr { } } +/// Indicates what is placed in a `concat` parameter. For example, literals +/// (`${concat("foo", "bar")}`) or adhoc identifiers (`${concat(foo, bar)}`). #[derive(Debug, Decodable, Encodable, PartialEq)] pub(crate) enum MetaVarExprConcatElem { /// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 9b4dc13c703..7e2ea8de5fc 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -6,9 +6,10 @@ use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*}; use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR}; use crate::mbe::{self, KleeneOp, MetaVarExpr}; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::token::IdentIsRaw; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{IdentIsRaw, Lit, LitKind}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; +use rustc_ast::ExprKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult}; use rustc_parse::lexer::nfc_normalize; @@ -17,7 +18,7 @@ use rustc_session::parse::ParseSess; use rustc_session::parse::SymbolGallery; use rustc_span::hygiene::{LocalExpnId, Transparency}; use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent}; -use rustc_span::{with_metavar_spans, Span, SyntaxContext}; +use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -691,12 +692,12 @@ fn transcribe_metavar_expr<'a>( MetaVarExpr::Concat(ref elements) => { let mut concatenated = String::new(); for element in elements.into_iter() { - let string = match element { - MetaVarExprConcatElem::Ident(elem) => elem.to_string(), - MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(), - MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?, + let symbol = match element { + MetaVarExprConcatElem::Ident(elem) => elem.name, + MetaVarExprConcatElem::Literal(elem) => *elem, + MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?, }; - concatenated.push_str(&string); + concatenated.push_str(symbol.as_str()); } let symbol = nfc_normalize(&concatenated); let concatenated_span = visited_span(); @@ -750,32 +751,42 @@ fn transcribe_metavar_expr<'a>( Ok(()) } -/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree. -fn extract_ident<'a>( +/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal. +fn extract_var_symbol<'a>( dcx: DiagCtxtHandle<'a>, ident: Ident, interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, -) -> PResult<'a, String> { +) -> PResult<'a, Symbol> { if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { if let IdentIsRaw::Yes = is_raw { return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); } - return Ok(nt_ident.to_string()); + return Ok(nt_ident.name); } - if let ParseNtResult::Tt(TokenTree::Token( - Token { kind: TokenKind::Ident(token_ident, is_raw), .. }, - _, - )) = pnr - { - if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + + if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr { + if let TokenKind::Ident(symbol, is_raw) = kind { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + } + return Ok(*symbol); } - return Ok(token_ident.to_string()); + + if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind { + return Ok(*symbol); + } + } + + if let ParseNtResult::Nt(nt) = pnr + && let Nonterminal::NtLiteral(expr) = &**nt + && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind + { + return Ok(*symbol); } } - Err(dcx.struct_span_err( - ident.span, - "`${concat(..)}` currently only accepts identifiers or meta-variables as parameters", - )) + Err(dcx + .struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`") + .with_note("currently only string literals are supported") + .with_span(ident.span)) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3bd7b300758..bf773f2d487 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -228,13 +228,53 @@ impl<'hir> PathSegment<'hir> { } } +/// A constant that enters the type system, used for arguments to const generics (e.g. array lengths). +/// +/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed +/// to use any generic parameters, therefore we must represent `N` differently. Additionally +/// future designs for supporting generic parameters in const arguments will likely not use +/// an anon const based design. +/// +/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args +/// that are [just paths](ConstArgKind::Path) (currently just bare const params) +/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`). #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct ConstArg<'hir> { - pub value: &'hir AnonConst, + #[stable_hasher(ignore)] + pub hir_id: HirId, + pub kind: ConstArgKind<'hir>, /// Indicates whether this comes from a `~const` desugaring. pub is_desugared_from_effects: bool, } +impl<'hir> ConstArg<'hir> { + pub fn anon_const_hir_id(&self) -> Option<HirId> { + match self.kind { + ConstArgKind::Anon(ac) => Some(ac.hir_id), + _ => None, + } + } + + pub fn span(&self) -> Span { + match self.kind { + ConstArgKind::Path(path) => path.span(), + ConstArgKind::Anon(anon) => anon.span, + } + } +} + +/// See [`ConstArg`]. +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub enum ConstArgKind<'hir> { + /// **Note:** Currently this is only used for bare const params + /// (`N` where `fn foo<const N: usize>(...)`), + /// not paths to any const (`N` where `const N: usize = ...`). + /// + /// However, in the future, we'll be using it for all of those. + Path(QPath<'hir>), + Anon(&'hir AnonConst), +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct InferArg { pub hir_id: HirId, @@ -251,7 +291,7 @@ impl InferArg { pub enum GenericArg<'hir> { Lifetime(&'hir Lifetime), Type(&'hir Ty<'hir>), - Const(ConstArg<'hir>), + Const(&'hir ConstArg<'hir>), Infer(InferArg), } @@ -260,7 +300,7 @@ impl GenericArg<'_> { match self { GenericArg::Lifetime(l) => l.ident.span, GenericArg::Type(t) => t.span, - GenericArg::Const(c) => c.value.span, + GenericArg::Const(c) => c.span(), GenericArg::Infer(i) => i.span, } } @@ -269,7 +309,7 @@ impl GenericArg<'_> { match self { GenericArg::Lifetime(l) => l.hir_id, GenericArg::Type(t) => t.hir_id, - GenericArg::Const(c) => c.value.hir_id, + GenericArg::Const(c) => c.hir_id, GenericArg::Infer(i) => i.hir_id, } } @@ -524,7 +564,7 @@ pub enum GenericParamKind<'hir> { Const { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param - default: Option<&'hir AnonConst>, + default: Option<&'hir ConstArg<'hir>>, is_host_effect: bool, synthetic: bool, }, @@ -1598,13 +1638,13 @@ pub type Lit = Spanned<LitKind>; #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum ArrayLen<'hir> { Infer(InferArg), - Body(&'hir AnonConst), + Body(&'hir ConstArg<'hir>), } impl ArrayLen<'_> { pub fn hir_id(&self) -> HirId { match self { - ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => { + ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => { *hir_id } } @@ -2434,7 +2474,7 @@ impl<'hir> AssocItemConstraint<'hir> { } /// Obtain the const on the RHS of an assoc const equality constraint if applicable. - pub fn ct(self) -> Option<&'hir AnonConst> { + pub fn ct(self) -> Option<&'hir ConstArg<'hir>> { match self.kind { AssocItemConstraintKind::Equality { term: Term::Const(ct) } => Some(ct), _ => None, @@ -2445,7 +2485,7 @@ impl<'hir> AssocItemConstraint<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum Term<'hir> { Ty(&'hir Ty<'hir>), - Const(&'hir AnonConst), + Const(&'hir ConstArg<'hir>), } impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> { @@ -2454,8 +2494,8 @@ impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> { } } -impl<'hir> From<&'hir AnonConst> for Term<'hir> { - fn from(c: &'hir AnonConst) -> Self { +impl<'hir> From<&'hir ConstArg<'hir>> for Term<'hir> { + fn from(c: &'hir ConstArg<'hir>) -> Self { Term::Const(c) } } @@ -3689,6 +3729,7 @@ pub enum Node<'hir> { Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), ConstBlock(&'hir ConstBlock), + ConstArg(&'hir ConstArg<'hir>), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), @@ -3750,6 +3791,7 @@ impl<'hir> Node<'hir> { Node::Param(..) | Node::AnonConst(..) | Node::ConstBlock(..) + | Node::ConstArg(..) | Node::Expr(..) | Node::Stmt(..) | Node::Block(..) @@ -3966,7 +4008,7 @@ mod size_asserts { static_assert_size!(FnDecl<'_>, 40); static_assert_size!(ForeignItem<'_>, 72); static_assert_size!(ForeignItemKind<'_>, 40); - static_assert_size!(GenericArg<'_>, 24); + static_assert_size!(GenericArg<'_>, 16); static_assert_size!(GenericBound<'_>, 48); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9bb3245ae05..c202ee41e31 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -347,6 +347,9 @@ pub trait Visitor<'v>: Sized { fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result { walk_inline_const(self, c) } + fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result { + walk_const_arg(self, c) + } fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result { walk_expr(self, ex) } @@ -364,7 +367,7 @@ pub trait Visitor<'v>: Sized { fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result { walk_generic_param(self, p) } - fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) -> Self::Result { + fn visit_const_param_default(&mut self, _param: HirId, ct: &'v ConstArg<'v>) -> Self::Result { walk_const_param_default(self, ct) } fn visit_generics(&mut self, g: &'v Generics<'v>) -> Self::Result { @@ -708,7 +711,7 @@ pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v> match len { // FIXME: Use `visit_infer` here. ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id), - ArrayLen::Body(c) => visitor.visit_anon_const(c), + ArrayLen::Body(c) => visitor.visit_const_arg(c), } } @@ -725,6 +728,17 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>( visitor.visit_nested_body(constant.body) } +pub fn walk_const_arg<'v, V: Visitor<'v>>( + visitor: &mut V, + const_arg: &'v ConstArg<'v>, +) -> V::Result { + try_visit!(visitor.visit_id(const_arg.hir_id)); + match &const_arg.kind { + ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()), + ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), + } +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { try_visit!(visitor.visit_id(expression.hir_id)); match expression.kind { @@ -928,9 +942,9 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( pub fn walk_const_param_default<'v, V: Visitor<'v>>( visitor: &mut V, - ct: &'v AnonConst, + ct: &'v ConstArg<'v>, ) -> V::Result { - visitor.visit_anon_const(ct) + visitor.visit_const_arg(ct) } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result { @@ -1216,7 +1230,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>( match generic_arg { GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), GenericArg::Type(ty) => visitor.visit_ty(ty), - GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value), + GenericArg::Const(ct) => visitor.visit_const_arg(ct), GenericArg::Infer(inf) => visitor.visit_infer(inf), } } @@ -1278,7 +1292,7 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>( match constraint.kind { AssocItemConstraintKind::Equality { ref term } => match term { Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)), - Term::Const(ref c) => try_visit!(visitor.visit_anon_const(c)), + Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)), }, AssocItemConstraintKind::Bound { bounds } => { walk_list!(visitor, visit_param_bound, bounds) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 24c5377a3b1..f08a0f8c8fc 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -58,6 +58,23 @@ hir_analysis_cannot_capture_late_bound_ty = hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present .label = `for<...>` is here +hir_analysis_cmse_call_generic = + function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type + +hir_analysis_cmse_call_inputs_stack_spill = + arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + .label = {$plural -> + [false] this argument doesn't + *[true] these arguments don't + } fit in the available registers + .note = functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +hir_analysis_cmse_call_output_stack_spill = + return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + .label = this type doesn't fit in the available registers + .note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions @@ -382,6 +399,10 @@ hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is no hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias .label = `Self` is not a generic argument, but an alias to the type of the {$what} +hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is only used recursively + .label = {$param_def_kind} must be used non-recursively in the definition + .note = all type parameters must be used in a non-recursive way in order to constrain their variance + hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` @@ -515,6 +536,11 @@ hir_analysis_typeof_reserved_keyword_used = .suggestion = consider replacing `typeof(...)` with an actual type .label = reserved keyword +hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_name}` is not constrained by the impl trait, self type, or predicates + .label = unconstrained {$param_def_kind} + .const_param_note = expressions using a const parameter must map each value to a distinct output value + .const_param_note2 = proving the result of expressions other than the parameter are unique is not supported + hir_analysis_unconstrained_opaque_type = unconstrained opaque type .note = `{$name}` must be used in combination with a concrete type within the same {$what} @@ -549,6 +575,8 @@ hir_analysis_unused_generic_parameter = {$param_def_kind} `{$param_name}` is never used .label = unused {$param_def_kind} .const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead + .usage_spans = `{$param_name}` is named here, but is likely unused in the containing type + hir_analysis_unused_generic_parameter_adt_help = consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}` hir_analysis_unused_generic_parameter_adt_no_phantom_data_help = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index bf8ef18c04f..dbc265ad3ff 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1572,6 +1572,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD param_name, param_def_kind: tcx.def_descr(param.def_id), help: errors::UnusedGenericParameterHelp::TyAlias { param_name }, + usage_spans: vec![], const_param_help, }); diag.code(E0091); diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 17cb20df754..19a0476e630 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -1,5 +1,4 @@ use rustc_hir as hir; -use rustc_hir_pretty::qpath_to_string; use rustc_lint_defs::builtin::STATIC_MUT_REFS; use rustc_middle::ty::{Mutability, TyCtxt}; use rustc_span::Span; @@ -12,9 +11,17 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { let hir_id = expr.hir_id; if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind && matches!(borrow_kind, hir::BorrowKind::Ref) - && let Some(var) = path_if_static_mut(tcx, expr) + && path_if_static_mut(expr) { - handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id); + handle_static_mut_ref( + tcx, + span, + span.with_hi(expr.span.lo()), + span.shrink_to_hi(), + span.edition().at_least_rust_2024(), + m, + hir_id, + ); } } @@ -24,12 +31,13 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind && let hir::ByRef::Yes(rmutbl) = ba.0 && let Some(init) = loc.init - && let Some(var) = path_if_static_mut(tcx, init) + && path_if_static_mut(init) { handle_static_mut_ref( tcx, init.span, - var, + init.span.shrink_to_lo(), + init.span.shrink_to_hi(), loc.span.edition().at_least_rust_2024(), rmutbl, stmt.hir_id, @@ -37,38 +45,39 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { } } -fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { +fn path_if_static_mut(expr: &hir::Expr<'_>) -> bool { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = def_kind { - return Some(qpath_to_string(&tcx, &qpath)); + return true; } - None + false } fn handle_static_mut_ref( tcx: TyCtxt<'_>, span: Span, - var: String, + lo: Span, + hi: Span, e2024: bool, mutable: Mutability, hir_id: hir::HirId, ) { if e2024 { let (sugg, shared) = if mutable == Mutability::Mut { - (errors::StaticMutRefSugg::Mut { span, var }, "mutable") + (errors::MutRefSugg::Mut { lo, hi }, "mutable") } else { - (errors::StaticMutRefSugg::Shared { span, var }, "shared") + (errors::MutRefSugg::Shared { lo, hi }, "shared") }; tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); } else { let (sugg, shared) = if mutable == Mutability::Mut { - (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") + (errors::MutRefSugg::Mut { lo, hi }, "mutable") } else { - (errors::RefOfMutStaticSugg::Shared { span, var }, "shared") + (errors::MutRefSugg::Shared { lo, hi }, "shared") }; tcx.emit_node_span_lint( STATIC_MUT_REFS, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 6a36938dd1d..24aeb024461 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -82,7 +82,7 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_infer::infer::error_reporting::ObligationCauseExt as _; +use rustc_infer::error_reporting::infer::ObligationCauseExt as _; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; @@ -166,21 +166,42 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { return; } - // For the wasm32 target statics with `#[link_section]` are placed into custom - // sections of the final output file, but this isn't link custom sections of - // other executable formats. Namely we can only embed a list of bytes, - // nothing with provenance (pointers to anything else). If any provenance - // show up, reject it here. + // For the wasm32 target statics with `#[link_section]` other than `.init_array` + // are placed into custom sections of the final output file, but this isn't like + // custom sections of other executable formats. Namely we can only embed a list + // of bytes, nothing with provenance (pointers to anything else). If any + // provenance show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. + // + // The `.init_array` section is left to go through the normal custom section code path. + // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests + // in workarounds in user-code. + // + // * The linker fails to merge multiple items in a crate into the .init_array section. + // To work around this, a single array can be used placing multiple items in the array. + // #[link_section = ".init_array"] + // static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor]; + // * Even symbols marked used get gc'd from dependant crates unless at least one symbol + // in the crate is marked with an `#[export_name]` + // + // Once `.init_array` support in wasm-ld is complete, the user code workarounds should + // continue to work, but would no longer be necessary. + if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + if attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap() + { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.dcx().span_err(tcx.def_span(id), msg); + tcx.dcx().span_err(tcx.def_span(id), msg); + } } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b2ef07d65c5..71a7b0b1638 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -4,12 +4,12 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use crate::errors; use crate::fluent_generated as fluent; -use hir::intravisit::Visitor; +use hir::intravisit::{self, Visitor}; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; @@ -1799,7 +1799,7 @@ fn receiver_is_implemented<'tcx>( fn check_variances_for_type_defn<'tcx>( tcx: TyCtxt<'tcx>, - item: &hir::Item<'tcx>, + item: &'tcx hir::Item<'tcx>, hir_generics: &hir::Generics<'tcx>, ) { let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id); @@ -1886,21 +1886,21 @@ fn check_variances_for_type_defn<'tcx>( hir::ParamName::Error => {} _ => { let has_explicit_bounds = explicitly_bounded_params.contains(¶meter); - report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind); + report_bivariance(tcx, hir_param, has_explicit_bounds, item); } } } } -fn report_bivariance( - tcx: TyCtxt<'_>, - param: &rustc_hir::GenericParam<'_>, +fn report_bivariance<'tcx>( + tcx: TyCtxt<'tcx>, + param: &'tcx hir::GenericParam<'tcx>, has_explicit_bounds: bool, - item_kind: ItemKind<'_>, + item: &'tcx hir::Item<'tcx>, ) -> ErrorGuaranteed { let param_name = param.name.ident(); - let help = match item_kind { + let help = match item.kind { ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { if let Some(def_id) = tcx.lang_items().phantom_data() { errors::UnusedGenericParameterHelp::Adt { @@ -1915,6 +1915,41 @@ fn report_bivariance( item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"), }; + let mut usage_spans = vec![]; + intravisit::walk_item( + &mut CollectUsageSpans { spans: &mut usage_spans, param_def_id: param.def_id.to_def_id() }, + item, + ); + + if !usage_spans.is_empty() { + // First, check if the ADT/LTA is (probably) cyclical. We say probably here, since we're + // not actually looking into substitutions, just walking through fields / the "RHS". + // We don't recurse into the hidden types of opaques or anything else fancy. + let item_def_id = item.owner_id.to_def_id(); + let is_probably_cyclical = + IsProbablyCyclical { tcx, item_def_id, seen: Default::default() } + .visit_def(item_def_id) + .is_break(); + // If the ADT/LTA is cyclical, then if at least one usage of the type parameter or + // the `Self` alias is present in the, then it's probably a cyclical struct/ type + // alias, and we should call those parameter usages recursive rather than just saying + // they're unused... + // + // We currently report *all* of the parameter usages, since computing the exact + // subset is very involved, and the fact we're mentioning recursion at all is + // likely to guide the user in the right direction. + if is_probably_cyclical { + return tcx.dcx().emit_err(errors::RecursiveGenericParameter { + spans: usage_spans, + param_span: param.span, + param_name, + param_def_kind: tcx.def_descr(param.def_id.to_def_id()), + help, + note: (), + }); + } + } + let const_param_help = matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds) .then_some(()); @@ -1923,6 +1958,7 @@ fn report_bivariance( span: param.span, param_name, param_def_kind: tcx.def_descr(param.def_id.to_def_id()), + usage_spans, help, const_param_help, }); @@ -1930,6 +1966,86 @@ fn report_bivariance( diag.emit() } +/// Detects cases where an ADT/LTA is trivially cyclical -- we want to detect this so +/// we only mention that its parameters are used cyclically if the ADT/LTA is truly +/// cyclical. +/// +/// Notably, we don't consider substitutions here, so this may have false positives. +struct IsProbablyCyclical<'tcx> { + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + seen: FxHashSet<DefId>, +} + +impl<'tcx> IsProbablyCyclical<'tcx> { + fn visit_def(&mut self, def_id: DefId) -> ControlFlow<(), ()> { + match self.tcx.def_kind(def_id) { + DefKind::Struct | DefKind::Enum | DefKind::Union => { + self.tcx.adt_def(def_id).all_fields().try_for_each(|field| { + self.tcx.type_of(field.did).instantiate_identity().visit_with(self) + }) + } + DefKind::TyAlias if self.tcx.type_alias_is_lazy(def_id) => { + self.tcx.type_of(def_id).instantiate_identity().visit_with(self) + } + _ => ControlFlow::Continue(()), + } + } +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> { + type Result = ControlFlow<(), ()>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> { + let def_id = match ty.kind() { + ty::Adt(adt_def, _) => Some(adt_def.did()), + ty::Alias(ty::Weak, alias_ty) => Some(alias_ty.def_id), + _ => None, + }; + if let Some(def_id) = def_id { + if def_id == self.item_def_id { + return ControlFlow::Break(()); + } + if self.seen.insert(def_id) { + self.visit_def(def_id)?; + } + } + ty.super_visit_with(self) + } +} + +/// Collect usages of the `param_def_id` and `Res::SelfTyAlias` in the HIR. +/// +/// This is used to report places where the user has used parameters in a +/// non-variance-constraining way for better bivariance errors. +struct CollectUsageSpans<'a> { + spans: &'a mut Vec<Span>, + param_def_id: DefId, +} + +impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> { + type Result = (); + + fn visit_generics(&mut self, _g: &'tcx rustc_hir::Generics<'tcx>) -> Self::Result { + // Skip the generics. We only care about fields, not where clause/param bounds. + } + + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result { + if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind { + if let Res::Def(DefKind::TyParam, def_id) = qpath.res + && def_id == self.param_def_id + { + self.spans.push(t.span); + return; + } else if let Res::SelfTyAlias { .. } = qpath.res { + self.spans.push(t.span); + return; + } + } + intravisit::walk_ty(self, t); + } +} + impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e0aad299163..5e23d473274 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -304,7 +304,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { self.tcx.ensure().type_of(param.def_id); if let Some(default) = default { // need to store default and type of default - self.tcx.ensure().type_of(default.def_id); + if let hir::ConstArgKind::Anon(ac) = default.kind { + self.tcx.ensure().type_of(ac.def_id); + } self.tcx.ensure().const_param_default(param.def_id); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 22d465c8e62..690423421b9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -13,7 +13,7 @@ use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -102,6 +102,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { None } else if tcx.features().generic_const_exprs { let parent_node = tcx.parent_hir_node(hir_id); + debug!(?parent_node); if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node && constant.hir_id == hir_id { @@ -164,13 +165,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } else { let parent_node = tcx.parent_hir_node(hir_id); + let parent_node = match parent_node { + Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id), + _ => parent_node, + }; match parent_node { // HACK(eddyb) this provides the correct generics for repeat // expressions' count (i.e. `N` in `[x; N]`), and explicit // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. - Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. }) - if constant.hir_id() == hir_id => + Node::Expr(Expr { kind: ExprKind::Repeat(_, ArrayLen::Body(ct)), .. }) + if ct.anon_const_hir_id() == Some(hir_id) => { Some(parent_did) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b89d034fc2e..9e430c83e20 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -388,7 +388,7 @@ fn const_evaluatable_predicates_of( } } - fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) { + fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) { // Do not look into const param defaults, // these get checked when they are actually instantiated. // diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index cad7870a0a1..7930f54038d 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -954,7 +954,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { GenericParamKind::Const { ty, default, .. } => { self.visit_ty(ty); if let Some(default) = default { - self.visit_body(self.tcx.hir().body(default.body)); + self.visit_const_arg(default); } } } @@ -1594,7 +1594,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { i += 1; } GenericArg::Const(ct) => { - self.visit_anon_const(&ct.value); + self.visit_const_arg(ct); i += 1; } GenericArg::Infer(inf) => { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 974dd415f46..9affd654366 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -35,16 +35,32 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let parent_node_id = tcx.parent_hir_id(hir_id); let parent_node = tcx.hir_node(parent_node_id); - let (generics, arg_idx) = match parent_node { - // Easy case: arrays repeat expressions. - Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) - | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id() == hir_id => + match parent_node { + // Anon consts "inside" the type system. + Node::ConstArg(&ConstArg { + hir_id: arg_hir_id, + kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }), + .. + }) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span), + + // Anon consts outside the type system. + Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) + | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) + if asm.operands.iter().any(|(op, _op_sp)| match op { + hir::InlineAsmOperand::Const { anon_const } + | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, + _ => false, + }) => { - return tcx.types.usize; + tcx.typeck(def_id).node_type(hir_id) + } + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) } + // Sort of affects the type system, but only for the purpose of diagnostics + // so no need for ConstArg. Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => { - let ty = tcx.typeck(def_id).node_type(e.hir_id); + let ty = tcx.typeck(def_id).node_type(tcx.local_def_id_to_hir_id(def_id)); let ty = tcx.fold_regions(ty, |r, _| { if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r } }); @@ -56,24 +72,35 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg }); return ty; } - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id, - _ => false, - }) => + + _ => Ty::new_error_with_message( + tcx, + span, + format!("unexpected anon const parent in type_of(): {parent_node:?}"), + ), + } +} + +fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { + use hir::*; + use rustc_middle::ty::Ty; + + let parent_node_id = tcx.parent_hir_id(arg_hir_id); + let parent_node = tcx.hir_node(parent_node_id); + + let (generics, arg_idx) = match parent_node { + // Easy case: arrays repeat expressions. + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id() == arg_hir_id => { - return tcx.typeck(def_id).node_type(hir_id); - } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx); + return tcx.types.usize; } Node::GenericParam(&GenericParam { def_id: param_def_id, kind: GenericParamKind::Const { default: Some(ct), .. }, .. - }) if ct.hir_id == hir_id => { + }) if ct.hir_id == arg_hir_id => { return tcx .type_of(param_def_id) .no_bound_vars() @@ -104,7 +131,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`). let item_def_id = tcx .hir() - .parent_owner_iter(hir_id) + .parent_owner_iter(arg_hir_id) .find(|(_, node)| matches!(node, OwnerNode::Item(_))) .unwrap() .0 @@ -124,7 +151,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) }) .unwrap_or_else(|| { bug!("no arg matching AnonConst in segment"); @@ -145,7 +172,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)), .. }) => { - let body_owner = tcx.hir().enclosing_body_owner(hir_id); + let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); let tables = tcx.typeck(body_owner); // This may fail in case the method/path does not actually exist. // As there is no relevant param for `def_id`, we simply return @@ -163,10 +190,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) }) .unwrap_or_else(|| { - bug!("no arg matching AnonConst in segment"); + bug!("no arg matching ConstArg in segment"); }); (tcx.generics_of(type_dependent_def), idx) @@ -185,18 +212,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { | ExprKind::Struct(&QPath::Resolved(_, path), ..), .. }) => { - let body_owner = tcx.hir().enclosing_body_owner(hir_id); + let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id); let _tables = tcx.typeck(body_owner); &*path } Node::Pat(pat) => { - if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { + if let Some(path) = get_path_containing_arg_in_pat(pat, arg_hir_id) { path } else { return Ty::new_error_with_message( tcx, span, - format!("unable to find const parent for {hir_id} in pat {pat:?}"), + format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"), ); } } @@ -217,14 +244,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { args.args .iter() .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) + .position(|arg| arg.hir_id() == arg_hir_id) .map(|index| (index, seg)) .or_else(|| { args.constraints .iter() .copied() .filter_map(AssocItemConstraint::ct) - .position(|ct| ct.hir_id == hir_id) + .position(|ct| ct.hir_id == arg_hir_id) .map(|idx| (idx, seg)) }) }) else { @@ -249,7 +276,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { return Ty::new_error_with_message( tcx, span, - format!("unexpected const parent in type_of(): {parent_node:?}"), + format!("unexpected const arg parent in type_of(): {parent_node:?}"), ); } }; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 0ee87a13e9e..2eca64c27d0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1500,33 +1500,33 @@ pub struct StaticMutRef<'a> { #[label] pub span: Span, #[subdiagnostic] - pub sugg: StaticMutRefSugg, + pub sugg: MutRefSugg, pub shared: &'a str, } #[derive(Subdiagnostic)] -pub enum StaticMutRefSugg { - #[suggestion( +pub enum MutRefSugg { + #[multipart_suggestion( hir_analysis_suggestion, style = "verbose", - code = "addr_of!({var})", applicability = "maybe-incorrect" )] Shared { - #[primary_span] - span: Span, - var: String, + #[suggestion_part(code = "addr_of!(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, }, - #[suggestion( + #[multipart_suggestion( hir_analysis_suggestion_mut, style = "verbose", - code = "addr_of_mut!({var})", applicability = "maybe-incorrect" )] Mut { - #[primary_span] - span: Span, - var: String, + #[suggestion_part(code = "addr_of_mut!(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, }, } @@ -1539,36 +1539,10 @@ pub struct RefOfMutStatic<'a> { #[label] pub span: Span, #[subdiagnostic] - pub sugg: RefOfMutStaticSugg, + pub sugg: MutRefSugg, pub shared: &'a str, } -#[derive(Subdiagnostic)] -pub enum RefOfMutStaticSugg { - #[suggestion( - hir_analysis_suggestion, - style = "verbose", - code = "addr_of!({var})", - applicability = "maybe-incorrect" - )] - Shared { - #[primary_span] - span: Span, - var: String, - }, - #[suggestion( - hir_analysis_suggestion_mut, - style = "verbose", - code = "addr_of_mut!({var})", - applicability = "maybe-incorrect" - )] - Mut { - #[primary_span] - span: Span, - var: String, - }, -} - #[derive(Diagnostic)] #[diag(hir_analysis_not_supported_delegation)] pub struct NotSupportedDelegation<'a> { @@ -1597,12 +1571,29 @@ pub(crate) struct UnusedGenericParameter { pub span: Span, pub param_name: Ident, pub param_def_kind: &'static str, + #[label(hir_analysis_usage_spans)] + pub usage_spans: Vec<Span>, #[subdiagnostic] pub help: UnusedGenericParameterHelp, #[help(hir_analysis_const_param_help)] pub const_param_help: Option<()>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_recursive_generic_parameter)] +pub(crate) struct RecursiveGenericParameter { + #[primary_span] + pub spans: Vec<Span>, + #[label] + pub param_span: Span, + pub param_name: Ident, + pub param_def_kind: &'static str, + #[subdiagnostic] + pub help: UnusedGenericParameterHelp, + #[note] + pub note: (), +} + #[derive(Subdiagnostic)] pub(crate) enum UnusedGenericParameterHelp { #[help(hir_analysis_unused_generic_parameter_adt_help)] @@ -1614,6 +1605,20 @@ pub(crate) enum UnusedGenericParameterHelp { } #[derive(Diagnostic)] +#[diag(hir_analysis_unconstrained_generic_parameter)] +pub(crate) struct UnconstrainedGenericParameter { + #[primary_span] + #[label] + pub span: Span, + pub param_name: Symbol, + pub param_def_kind: &'static str, + #[note(hir_analysis_const_param_note)] + pub const_param_note: Option<()>, + #[note(hir_analysis_const_param_note2)] + pub const_param_note2: Option<()>, +} + +#[derive(Diagnostic)] pub enum UnnamedFieldsRepr<'a> { #[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)] MissingReprC { @@ -1682,3 +1687,30 @@ pub struct InvalidReceiverTy<'tcx> { #[note] #[help] pub struct EffectsWithoutNextSolver; + +#[derive(Diagnostic)] +#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)] +#[note] +pub struct CmseCallInputsStackSpill { + #[primary_span] + #[label] + pub span: Span, + pub plural: bool, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)] +#[note(hir_analysis_note1)] +#[note(hir_analysis_note2)] +pub struct CmseCallOutputStackSpill { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cmse_call_generic, code = E0798)] +pub struct CmseCallGeneric { + #[primary_span] + pub span: Span, +} 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 a1feef9e15b..6f9c481650b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -413,12 +413,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }); // Provide the resolved type of the associated constant to `type_of(AnonConst)`. - if let Some(anon_const) = constraint.ct() { - let ty = alias_term - .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); - let ty = - check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id); - tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); + if let Some(const_arg) = constraint.ct() { + if let hir::ConstArgKind::Anon(anon_const) = const_arg.kind { + let ty = alias_term + .map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args)); + let ty = check_assoc_const_binding_type( + self, + constraint.ident, + ty, + constraint.hir_id, + ); + tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty)); + } } alias_term @@ -435,7 +441,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::AssocItemConstraintKind::Equality { term } => { let term = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), - hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(), + hir::Term::Const(ct) => { + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into() + } }; // Find any late-bound regions declared in `ty` that are not diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs new file mode 100644 index 00000000000..e99717ce00f --- /dev/null +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -0,0 +1,156 @@ +use rustc_errors::DiagCtxtHandle; +use rustc_hir as hir; +use rustc_hir::HirId; +use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::{self, ParamEnv, TyCtxt}; +use rustc_span::Span; +use rustc_target::spec::abi; + +use crate::errors; + +/// Check conditions on inputs and outputs that the cmse ABIs impose: arguments and results MUST be +/// returned via registers (i.e. MUST NOT spill to the stack). LLVM will also validate these +/// conditions, but by checking them here rustc can emit nicer error messages. +pub fn validate_cmse_abi<'tcx>( + tcx: TyCtxt<'tcx>, + dcx: DiagCtxtHandle<'_>, + hir_id: HirId, + abi: abi::Abi, + fn_sig: ty::PolyFnSig<'tcx>, +) { + if let abi::Abi::CCmseNonSecureCall = abi { + let hir_node = tcx.hir_node(hir_id); + let hir::Node::Ty(hir::Ty { + span: bare_fn_span, + kind: hir::TyKind::BareFn(bare_fn_ty), + .. + }) = hir_node + else { + // might happen when this ABI is used incorrectly. That will be handled elsewhere + return; + }; + + match is_valid_cmse_inputs(tcx, fn_sig) { + Ok(Ok(())) => {} + Ok(Err(index)) => { + // fn(x: u32, u32, u32, u16, y: u16) -> u32, + // ^^^^^^ + let span = bare_fn_ty.param_names[index] + .span + .to(bare_fn_ty.decl.inputs[index].span) + .to(bare_fn_ty.decl.inputs.last().unwrap().span); + let plural = bare_fn_ty.param_names.len() - index != 1; + dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural }); + } + Err(layout_err) => { + if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) { + dcx.emit_err(err); + } + } + } + + match is_valid_cmse_output(tcx, fn_sig) { + Ok(true) => {} + Ok(false) => { + let span = bare_fn_ty.decl.output.span(); + dcx.emit_err(errors::CmseCallOutputStackSpill { span }); + } + Err(layout_err) => { + if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) { + dcx.emit_err(err); + } + } + }; + } +} + +/// Returns whether the inputs will fit into the available registers +fn is_valid_cmse_inputs<'tcx>( + tcx: TyCtxt<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, +) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> { + let mut span = None; + let mut accum = 0u64; + + for (index, arg_def) in fn_sig.inputs().iter().enumerate() { + let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?; + + let align = layout.layout.align().abi.bytes(); + let size = layout.layout.size().bytes(); + + accum += size; + accum = accum.next_multiple_of(Ord::max(4, align)); + + // i.e. exceeds 4 32-bit registers + if accum > 16 { + span = span.or(Some(index)); + } + } + + match span { + None => Ok(Ok(())), + Some(span) => Ok(Err(span)), + } +} + +/// Returns whether the output will fit into the available registers +fn is_valid_cmse_output<'tcx>( + tcx: TyCtxt<'tcx>, + fn_sig: ty::PolyFnSig<'tcx>, +) -> Result<bool, &'tcx LayoutError<'tcx>> { + let mut ret_ty = fn_sig.output().skip_binder(); + let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?; + let size = layout.layout.size().bytes(); + + if size <= 4 { + return Ok(true); + } else if size > 8 { + return Ok(false); + } + + // next we need to peel any repr(transparent) layers off + 'outer: loop { + let ty::Adt(adt_def, args) = ret_ty.kind() else { + break; + }; + + if !adt_def.repr().transparent() { + break; + } + + // the first field with non-trivial size and alignment must be the data + for variant_def in adt_def.variants() { + for field_def in variant_def.fields.iter() { + let ty = field_def.ty(tcx, args); + let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?; + + if !layout.layout.is_1zst() { + ret_ty = ty; + continue 'outer; + } + } + } + } + + Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64) +} + +fn cmse_layout_err<'tcx>( + layout_err: &'tcx LayoutError<'tcx>, + span: Span, +) -> Option<crate::errors::CmseCallGeneric> { + use LayoutError::*; + + match layout_err { + Unknown(ty) => { + if ty.is_impl_trait() { + None // prevent double reporting of this error + } else { + Some(errors::CmseCallGeneric { span }) + } + } + SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => { + None // not our job to report these + } + } +} 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 5e595488ea7..8ff6ced8b39 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -340,7 +340,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { { let span = match term { hir::Term::Ty(ty) => ty.span, - hir::Term::Const(ct) => tcx.def_span(ct.def_id), + hir::Term::Const(ct) => ct.span(), }; (span, Some(ident.span), assoc_item.kind, assoc_kind) } else { @@ -1257,14 +1257,12 @@ pub fn prohibit_assoc_item_constraint( }; // Now emit the suggestion - if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) { - e.span_suggestion_verbose( - removal_span, - format!("consider removing this associated item {}", constraint.kind.descr()), - suggestion, - Applicability::MaybeIncorrect, - ); - } + e.span_suggestion_verbose( + removal_span, + format!("consider removing this associated item {}", constraint.kind.descr()), + "", + Applicability::MaybeIncorrect, + ); }; // Suggest replacing the associated item binding with a generic argument. @@ -1296,8 +1294,7 @@ pub fn prohibit_assoc_item_constraint( hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) }, GenericParamDefKind::Const { .. }, ) => { - let span = tcx.hir().span(c.hir_id); - suggest_direct_use(&mut err, span); + suggest_direct_use(&mut err, c.span()); } (hir::AssocItemConstraintKind::Bound { bounds }, _) => { // Suggest `impl<T: Bound> Trait<T> for Foo` when finding @@ -1340,11 +1337,13 @@ pub fn prohibit_assoc_item_constraint( format!("<{lifetimes}{type_with_constraints}>"), ) }; - let suggestions = - vec![param_decl, (constraint.span, format!("{}", matching_param.name))]; + let suggestions = vec![ + param_decl, + (constraint.span.with_lo(constraint.ident.span.hi()), String::new()), + ]; err.multipart_suggestion_verbose( - format!("declare the type parameter right after the `impl` keyword"), + "declare the type parameter right after the `impl` keyword", suggestions, Applicability::MaybeIncorrect, ); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index b1c77db9f37..abe2cff321f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -113,8 +113,12 @@ fn generic_arg_mismatch_err( } } (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => { - let body = tcx.hir().body(cnst.value.body); - if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind + // FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too, + // this should match against that instead of ::Anon + if let hir::ConstArgKind::Anon(anon) = cnst.kind + && let body = tcx.hir().body(anon.body) + && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = + body.value.kind { if let Res::Def(DefKind::Fn { .. }, id) = path.res { err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a665306f2c6..d6eb1a66902 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -14,6 +14,7 @@ //! trait references and bounds. mod bounds; +mod cmse; pub mod errors; pub mod generics; mod lint; @@ -471,11 +472,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { handle_ty_args(has_default, &inf.to_ty()) } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - let did = ct.value.def_id; - tcx.feed_anon_const_type(did, tcx.type_of(param.def_id)); - ty::Const::from_anon_const(tcx, did).into() + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id)) + .into() } - (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { + (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( @@ -912,7 +912,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let term: ty::Term<'_> = match term { hir::Term::Ty(ty) => self.lower_ty(ty).into(), hir::Term::Const(ct) => { - ty::Const::from_anon_const(tcx, ct.def_id).into() + ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No) + .into() } }; // FIXME(#97583): This isn't syntactically well-formed! @@ -1087,7 +1088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(suggested_name) = find_best_match_for_name( + if let Some(variant_name) = find_best_match_for_name( &adt_def .variants() .iter() @@ -1095,12 +1096,66 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect::<Vec<Symbol>>(), assoc_ident.name, None, - ) { - err.span_suggestion( - assoc_ident.span, + ) && let Some(variant) = + adt_def.variants().iter().find(|s| s.name == variant_name) + { + let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())]; + if let hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Semi(ref expr), + .. + }) + | hir::Node::Expr(ref expr) = tcx.parent_hir_node(hir_ref_id) + && let hir::ExprKind::Struct(..) = expr.kind + { + match variant.ctor { + None => { + // struct + suggestion = vec![( + assoc_ident.span.with_hi(expr.span.hi()), + if variant.fields.is_empty() { + format!("{variant_name} {{}}") + } else { + format!( + "{variant_name} {{ {} }}", + variant + .fields + .iter() + .map(|f| format!("{}: /* value */", f.name)) + .collect::<Vec<_>>() + .join(", ") + ) + }, + )]; + } + Some((hir::def::CtorKind::Fn, def_id)) => { + // tuple + let fn_sig = tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + suggestion = vec![( + assoc_ident.span.with_hi(expr.span.hi()), + format!( + "{variant_name}({})", + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::<Vec<_>>() + .join(", ") + ), + )]; + } + Some((hir::def::CtorKind::Const, _)) => { + // unit + suggestion = vec![( + assoc_ident.span.with_hi(expr.span.hi()), + variant_name.to_string(), + )]; + } + } + } + err.multipart_suggestion_verbose( "there is a variant with a similar name", - suggested_name, - Applicability::MaybeIncorrect, + suggestion, + Applicability::HasPlaceholders, ); } else { err.span_label( @@ -2140,7 +2195,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let length = match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { - ty::Const::from_anon_const(tcx, constant.def_id) + ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No) } }; @@ -2324,6 +2379,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); + // reject function types that violate cmse ABI requirements + cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty); + // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not well-formed. // diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 5cc1ec71757..f0fcbd5528f 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -8,15 +8,15 @@ //! specialization errors. These things can (and probably should) be //! fixed, but for the moment it's easier to do these checks early. -use crate::constrained_generic_params as cgp; +use crate::{constrained_generic_params as cgp, errors::UnconstrainedGenericParameter}; use min_specialization::check_min_specialization; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{codes::*, struct_span_code_err}; +use rustc_errors::codes::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::ErrorGuaranteed; mod min_specialization; @@ -117,43 +117,34 @@ fn enforce_impl_params_are_constrained( let mut res = Ok(()); for param in &impl_generics.own_params { - match param.kind { + let err = match param.kind { // Disallow ANY unconstrained type parameters. ty::GenericParamDefKind::Type { .. } => { let param_ty = ty::ParamTy::for_def(param); - if !input_parameters.contains(&cgp::Parameter::from(param_ty)) { - res = Err(report_unused_parameter( - tcx, - tcx.def_span(param.def_id), - "type", - param_ty.name, - )); - } + !input_parameters.contains(&cgp::Parameter::from(param_ty)) } ty::GenericParamDefKind::Lifetime => { let param_lt = cgp::Parameter::from(param.to_early_bound_region_data()); - if lifetimes_in_associated_types.contains(¶m_lt) && // (*) + lifetimes_in_associated_types.contains(¶m_lt) && // (*) !input_parameters.contains(¶m_lt) - { - res = Err(report_unused_parameter( - tcx, - tcx.def_span(param.def_id), - "lifetime", - param.name, - )); - } } ty::GenericParamDefKind::Const { .. } => { let param_ct = ty::ParamConst::for_def(param); - if !input_parameters.contains(&cgp::Parameter::from(param_ct)) { - res = Err(report_unused_parameter( - tcx, - tcx.def_span(param.def_id), - "const", - param_ct.name, - )); - } + !input_parameters.contains(&cgp::Parameter::from(param_ct)) } + }; + if err { + let const_param_note = + matches!(param.kind, ty::GenericParamDefKind::Const { .. }).then_some(()); + let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter { + span: tcx.def_span(param.def_id), + param_name: param.name, + param_def_kind: tcx.def_descr(param.def_id), + const_param_note, + const_param_note2: const_param_note, + }); + diag.code(E0207); + res = Err(diag.emit()); } } res @@ -177,30 +168,3 @@ fn enforce_impl_params_are_constrained( // associated types. I believe this is sound, because lifetimes // used elsewhere are not projected back out. } - -fn report_unused_parameter( - tcx: TyCtxt<'_>, - span: Span, - kind: &str, - name: Symbol, -) -> ErrorGuaranteed { - let mut err = struct_span_code_err!( - tcx.dcx(), - span, - E0207, - "the {} parameter `{}` is not constrained by the \ - impl trait, self type, or predicates", - kind, - name - ); - err.span_label(span, format!("unconstrained {kind} parameter")); - if kind == "const" { - err.note( - "expressions using a const parameter must map each value to a distinct output value", - ); - err.note( - "proving the result of expressions other than the parameter are unique is not supported", - ); - } - err.emit() -} diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5105d60ae18..db5eba0d9eb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -12,8 +12,9 @@ use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; use rustc_hir::{ - BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, - LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier, + BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, + HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, + TraitBoundModifier, }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -87,6 +88,7 @@ impl<'a> State<'a> { Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), Node::ConstBlock(a) => self.print_inline_const(a), + Node::ConstArg(a) => self.print_const_arg(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), Node::Stmt(a) => self.print_stmt(a), @@ -983,7 +985,7 @@ impl<'a> State<'a> { fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) { match len { hir::ArrayLen::Infer(..) => self.word("_"), - hir::ArrayLen::Body(ct) => self.print_anon_const(ct), + hir::ArrayLen::Body(ct) => self.print_const_arg(ct), } } @@ -991,6 +993,13 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(constant.body)) } + fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { + match &const_arg.kind { + ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), + ConstArgKind::Anon(anon) => self.print_anon_const(anon), + } + } + fn print_call_post(&mut self, args: &[hir::Expr<'_>]) { self.popen(); self.commasep_exprs(Inconsistent, args); @@ -1679,7 +1688,7 @@ impl<'a> State<'a> { GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt), GenericArg::Lifetime(_) => {} GenericArg::Type(ty) => s.print_type(ty), - GenericArg::Const(ct) => s.print_anon_const(&ct.value), + GenericArg::Const(ct) => s.print_const_arg(ct), GenericArg::Infer(_inf) => s.word("_"), } }); @@ -1720,7 +1729,7 @@ impl<'a> State<'a> { self.word_space("="); match term { Term::Ty(ty) => self.print_type(ty), - Term::Const(ref c) => self.print_anon_const(c), + Term::Const(ref c) => self.print_const_arg(c), } } hir::AssocItemConstraintKind::Bound { bounds } => { @@ -2155,7 +2164,7 @@ impl<'a> State<'a> { if let Some(default) = default { self.space(); self.word_space("="); - self.print_anon_const(default); + self.print_const_arg(default); } } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 035a3429ed7..d708269f1f5 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -519,7 +519,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_error(tcx, e) } Res::Def(DefKind::Variant, _) => { - let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, E0533, "value"); + let e = report_unexpected_variant_res( + tcx, + res, + Some(expr), + qpath, + expr.span, + E0533, + "value", + ); Ty::new_error(tcx, e) } _ => { @@ -1439,9 +1447,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; if let hir::TyKind::Array(_, length) = ty.peel_refs().kind - && let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length + && let hir::ArrayLen::Body(ct) = length { - let span = self.tcx.hir().span(hir_id); + let span = ct.span(); self.dcx().try_steal_modify_and_emit_err( span, StashKey::UnderscoreForArrayLengths, @@ -2210,8 +2218,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap(); - match variant.ctor_kind() { - Some(CtorKind::Fn) => match ty.kind() { + match variant.ctor { + Some((CtorKind::Fn, def_id)) => match ty.kind() { ty::Adt(adt, ..) if adt.is_enum() => { err.span_label( variant_ident_span, @@ -2222,28 +2230,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); err.span_label(field.ident.span, "field does not exist"); + let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + let fields = format!( + "({})", + inputs.iter().map(|i| format!("/* {i} */")).collect::<Vec<_>>().join(", ") + ); + let (replace_span, sugg) = match expr.kind { + hir::ExprKind::Struct(qpath, ..) => { + (qpath.span().shrink_to_hi().with_hi(expr.span.hi()), fields) + } + _ => { + (expr.span, format!("{ty}::{variant}{fields}", variant = variant.name)) + } + }; err.span_suggestion_verbose( - expr.span, + replace_span, format!( "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax", adt = ty, variant = variant.name, ), - format!( - "{adt}::{variant}(/* fields */)", - adt = ty, - variant = variant.name, - ), + sugg, Applicability::HasPlaceholders, ); } _ => { err.span_label(variant_ident_span, format!("`{ty}` defined here")); err.span_label(field.ident.span, "field does not exist"); + let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + let fields = format!( + "({})", + inputs.iter().map(|i| format!("/* {i} */")).collect::<Vec<_>>().join(", ") + ); err.span_suggestion_verbose( expr.span, format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",), - format!("{ty}(/* fields */)"), + format!("{ty}{fields}"), Applicability::HasPlaceholders, ); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index ea9567f4e3d..cc2c1a302f5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -19,7 +19,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -457,22 +457,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> { match length { hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), - hir::ArrayLen::Body(anon_const) => { - let span = self.tcx.def_span(anon_const.def_id); - let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); + hir::ArrayLen::Body(const_arg) => { + let span = const_arg.span(); + let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No); self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); self.normalize(span, c) } } } - pub fn lower_const_arg(&self, hir_ct: &hir::AnonConst, param_def_id: DefId) -> ty::Const<'tcx> { - let did = hir_ct.def_id; - self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id)); - let ct = ty::Const::from_anon_const(self.tcx, did); + pub fn lower_const_arg( + &self, + const_arg: &'tcx hir::ConstArg<'tcx>, + param_def_id: DefId, + ) -> ty::Const<'tcx> { + let ct = + ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id)); self.register_wf_obligation( ct.into(), - self.tcx.hir().span(hir_ct.hir_id), + self.tcx.hir().span(const_arg.hir_id), ObligationCauseCode::WellFormed(None), ); ct @@ -1298,7 +1301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fcx.lower_ty(ty).raw.into() } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - self.fcx.lower_const_arg(&ct.value, param.def_id).into() + self.fcx.lower_const_arg(ct, param.def_id).into() } (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { self.fcx.ty_infer(Some(param), inf.span).into() @@ -1519,7 +1522,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let e = self.tainted_by_errors().unwrap_or_else(|| { self.err_ctxt() - .emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true) + .emit_inference_failure_err( + self.body_id, + sp, + ty.into(), + TypeAnnotationNeeded::E0282, + true, + ) .emit() }); let err = Ty::new_error(self.tcx, e); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9fbb01216bb..2b4025ca808 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -29,7 +29,7 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; -use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; +use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -1105,7 +1105,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "".to_string() }; - labels.push((provided_span, format!("unexpected argument{provided_ty_name}"))); + let idx = if provided_arg_tys.len() == 1 { + "".to_string() + } else { + format!(" #{}", arg_idx.as_usize() + 1) + }; + labels.push(( + provided_span, + format!("unexpected argument{idx}{provided_ty_name}"), + )); let mut span = provided_span; if span.can_be_used_for_suggestions() && error_span.can_be_used_for_suggestions() @@ -1186,7 +1194,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { "".to_string() }; - labels.push((span, format!("an argument{rendered} is missing"))); + labels.push(( + span, + format!( + "argument #{}{rendered} is missing", + expected_idx.as_usize() + 1 + ), + )); + suggestion_text = match suggestion_text { SuggestionText::None => SuggestionText::Provide(false), SuggestionText::Provide(_) => SuggestionText::Provide(true), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index b5796fbd48a..3fe87c03e74 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,9 +15,9 @@ use hir::def_id::CRATE_DEF_ID; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; +use rustc_infer::error_reporting::infer::sub_relations::SubRelations; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer; -use rustc_infer::infer::error_reporting::sub_relations::SubRelations; -use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index bdbdcee6446..2c793664509 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -53,7 +53,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::LoweredTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; +use rustc_errors::{codes::*, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -346,6 +346,7 @@ impl<'tcx> EnclosingBreakables<'tcx> { fn report_unexpected_variant_res( tcx: TyCtxt<'_>, res: Res, + expr: Option<&hir::Expr<'_>>, qpath: &hir::QPath<'_>, span: Span, err_code: ErrCode, @@ -356,7 +357,7 @@ fn report_unexpected_variant_res( _ => res.descr(), }; let path_str = rustc_hir_pretty::qpath_to_string(&tcx, qpath); - let err = tcx + let mut err = tcx .dcx() .struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`")) .with_code(err_code); @@ -366,6 +367,61 @@ fn report_unexpected_variant_res( err.with_span_label(span, "`fn` calls are not allowed in patterns") .with_help(format!("for more information, visit {patterns_url}")) } + Res::Def(DefKind::Variant, _) if let Some(expr) = expr => { + err.span_label(span, format!("not a {expected}")); + let variant = tcx.expect_variant_res(res); + let sugg = if variant.fields.is_empty() { + " {}".to_string() + } else { + format!( + " {{ {} }}", + variant + .fields + .iter() + .map(|f| format!("{}: /* value */", f.name)) + .collect::<Vec<_>>() + .join(", ") + ) + }; + let descr = "you might have meant to create a new value of the struct"; + let mut suggestion = vec![]; + match tcx.parent_hir_node(expr.hir_id) { + hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Call(..), + span: call_span, + .. + }) => { + suggestion.push((span.shrink_to_hi().with_hi(call_span.hi()), sugg)); + } + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(..), hir_id, .. }) => { + suggestion.push((expr.span.shrink_to_lo(), "(".to_string())); + if let hir::Node::Expr(drop_temps) = tcx.parent_hir_node(*hir_id) + && let hir::ExprKind::DropTemps(_) = drop_temps.kind + && let hir::Node::Expr(parent) = tcx.parent_hir_node(drop_temps.hir_id) + && let hir::ExprKind::If(condition, block, None) = parent.kind + && condition.hir_id == drop_temps.hir_id + && let hir::ExprKind::Block(block, _) = block.kind + && block.stmts.is_empty() + && let Some(expr) = block.expr + && let hir::ExprKind::Path(..) = expr.kind + { + // Special case: you can incorrectly write an equality condition: + // if foo == Struct { field } { /* if body */ } + // which should have been written + // if foo == (Struct { field }) { /* if body */ } + suggestion.push((block.span.shrink_to_hi(), ")".to_string())); + } else { + suggestion.push((span.shrink_to_hi().with_hi(expr.span.hi()), sugg)); + } + } + _ => { + suggestion.push((span.shrink_to_hi(), sugg)); + } + } + + err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect); + err + } _ => err.with_span_label(span, format!("not a {expected}")), } .emit() diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e574fde14fb..e70431a68ff 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -400,7 +400,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.lower_ty(ty).raw.into() } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { - self.cfcx.lower_const_arg(&ct.value, param.def_id).into() + self.cfcx.lower_const_arg(ct, param.def_id).into() } (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => { self.cfcx.ty_infer(Some(param), inf.span).into() diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index dc1b888374c..daf4ef5cdb3 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -182,8 +182,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> { - let pick = - self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; + let scope = if let Some(only_method) = segment.res.opt_def_id() { + ProbeScope::Single(only_method) + } else { + ProbeScope::TraitsInScope + }; + + let pick = self.lookup_probe(segment.ident, self_ty, call_expr, scope)?; self.lint_edition_dependent_dot_call( self_ty, segment, span, call_expr, self_expr, &pick, args, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6a7af5510e0..e817685e41c 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,7 +12,7 @@ use rustc_hir::HirId; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; @@ -20,6 +20,7 @@ use rustc_middle::middle::stability; use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; +use rustc_middle::ty::AssocItemContainer; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::Upcast; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; @@ -216,6 +217,9 @@ pub enum Mode { #[derive(PartialEq, Eq, Copy, Clone, Debug)] pub enum ProbeScope { + // Single candidate coming from pre-resolved delegation method. + Single(DefId), + // Assemble candidates coming only from traits in scope. TraitsInScope, @@ -441,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.body_id, span, ty.into(), - E0282, + TypeAnnotationNeeded::E0282, !raw_ptr_call, ); if raw_ptr_call { @@ -480,12 +484,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_suggestion, ); - probe_cx.assemble_inherent_candidates(); match scope { ProbeScope::TraitsInScope => { - probe_cx.assemble_extension_candidates_for_traits_in_scope() + probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_extension_candidates_for_traits_in_scope(); + } + ProbeScope::AllTraits => { + probe_cx.assemble_inherent_candidates(); + probe_cx.assemble_extension_candidates_for_all_traits(); + } + 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::TraitContainer); + + let trait_def_id = self.tcx.parent(def_id); + let trait_span = self.tcx.def_span(trait_def_id); + + let trait_args = self.fresh_args_for_item(trait_span, trait_def_id); + let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args); + + probe_cx.push_candidate( + Candidate { + item, + kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)), + import_ids: smallvec![], + }, + false, + ); } - ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(), }; op(probe_cx) }) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 425289ce3c5..1cc7cf67ee3 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1596,16 +1596,127 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that had unsatisfied trait bounds if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() { let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT"); - if let Some(suggestion) = edit_distance::find_best_match_for_name( + if let Some(var_name) = edit_distance::find_best_match_for_name( &adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(), item_name.name, None, - ) { - err.span_suggestion( - span, + ) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == var_name) + { + let mut suggestion = vec![(span, var_name.to_string())]; + if let SelfSource::QPath(ty) = source + && let hir::Node::Expr(ref path_expr) = self.tcx.parent_hir_node(ty.hir_id) + && let hir::ExprKind::Path(_) = path_expr.kind + && let hir::Node::Stmt(hir::Stmt { + kind: hir::StmtKind::Semi(ref parent), .. + }) + | hir::Node::Expr(ref parent) = self.tcx.parent_hir_node(path_expr.hir_id) + { + let replacement_span = + if let hir::ExprKind::Call(..) | hir::ExprKind::Struct(..) = parent.kind { + // We want to replace the parts that need to go, like `()` and `{}`. + span.with_hi(parent.span.hi()) + } else { + span + }; + match (variant.ctor, parent.kind) { + (None, hir::ExprKind::Struct(..)) => { + // We want a struct and we have a struct. We won't suggest changing + // the fields (at least for now). + suggestion = vec![(span, var_name.to_string())]; + } + (None, _) => { + // struct + suggestion = vec![( + replacement_span, + if variant.fields.is_empty() { + format!("{var_name} {{}}") + } else { + format!( + "{var_name} {{ {} }}", + variant + .fields + .iter() + .map(|f| format!("{}: /* value */", f.name)) + .collect::<Vec<_>>() + .join(", ") + ) + }, + )]; + } + (Some((hir::def::CtorKind::Const, _)), _) => { + // unit, remove the `()`. + suggestion = vec![(replacement_span, var_name.to_string())]; + } + ( + Some((hir::def::CtorKind::Fn, def_id)), + hir::ExprKind::Call(rcvr, args), + ) => { + let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + // FIXME: reuse the logic for "change args" suggestion to account for types + // involved and detect things like substitution. + match (inputs, args) { + (inputs, []) => { + // Add arguments. + suggestion.push(( + rcvr.span.shrink_to_hi().with_hi(parent.span.hi()), + format!( + "({})", + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::<Vec<String>>() + .join(", ") + ), + )); + } + (_, [arg]) if inputs.len() != args.len() => { + // Replace arguments. + suggestion.push(( + arg.span, + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::<Vec<String>>() + .join(", "), + )); + } + (_, [arg_start, .., arg_end]) if inputs.len() != args.len() => { + // Replace arguments. + suggestion.push(( + arg_start.span.to(arg_end.span), + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::<Vec<String>>() + .join(", "), + )); + } + // Argument count is the same, keep as is. + _ => {} + } + } + (Some((hir::def::CtorKind::Fn, def_id)), _) => { + let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity(); + let inputs = fn_sig.inputs().skip_binder(); + suggestion = vec![( + replacement_span, + format!( + "{var_name}({})", + inputs + .iter() + .map(|i| format!("/* {i} */")) + .collect::<Vec<String>>() + .join(", ") + ), + )]; + } + } + } + err.multipart_suggestion_verbose( "there is a variant with a similar name", suggestion, - Applicability::MaybeIncorrect, + Applicability::HasPlaceholders, ); } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 6d1e9ff1f95..8afc6a48dfc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1023,7 +1023,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => { let expected = "unit struct, unit variant or constant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected); + let e = + report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected); return Ty::new_error(tcx, e); } Res::SelfCtor(def_id) => { @@ -1036,6 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let e = report_unexpected_variant_res( tcx, res, + None, qpath, pat.span, E0533, @@ -1189,7 +1191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let report_unexpected_res = |res: Res| { let expected = "tuple struct or tuple variant"; - let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0164, expected); + let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected); on_error(e); e }; diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e800c1a97d9..611854ce2af 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -783,7 +783,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { self.fcx.tcx.hir().body_owner_def_id(self.body.id()), self.span.to_span(self.fcx.tcx), p.into(), - E0282, + TypeAnnotationNeeded::E0282, false, ) .emit() diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index 3a4c813b5d4..92ea3f278dc 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -15,5 +15,9 @@ smallvec = "1.8.1" [features] # tidy-alphabetical-start default = ["nightly"] -nightly = ["rustc_serialize", "rustc_macros", "rustc_index_macros/nightly"] +nightly = [ + "dep:rustc_serialize", + "dep:rustc_macros", + "rustc_index_macros/nightly", +] # tidy-alphabetical-end diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index b866c8b8433..346ce945bf9 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::borrow::{Borrow, BorrowMut}; @@ -322,14 +322,14 @@ impl<I: Idx, T, const N: usize> From<[T; N]> for IndexVec<I, T> { } } -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> { fn encode(&self, s: &mut S) { Encodable::encode(&self.raw, s); } } -#[cfg(feature = "rustc_serialize")] +#[cfg(feature = "nightly")] impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> { fn decode(d: &mut D) -> Self { IndexVec::from_raw(Vec::<T>::decode(d)) diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 7a5e7159920..c279195a7e9 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -225,6 +225,8 @@ infer_outlives_content = lifetime of reference outlives lifetime of borrowed con infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` +infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... infer_prlf_defined_without_sub = the lifetime defined here... infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) @@ -387,6 +389,9 @@ infer_type_annotations_needed = {$source_kind -> .label = type must be known at this point infer_types_declared_different = these two types are declared with different lifetimes... + +infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + infer_where_copy_predicates = copy the `where` clause predicates from the trait infer_where_remove = remove the `where` clause diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/infer/mod.rs index bb1285ee813..9998fbca056 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/mod.rs @@ -45,17 +45,11 @@ //! ported to this system, and which relies on string concatenation at the //! time of error detection. -use super::{InferCtxt, TypeTrace, ValuePairs}; - -use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; -use crate::infer; -use crate::infer::ExpectedFound; -use crate::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - PredicateObligation, -}; +use std::borrow::Cow; +use std::ops::{ControlFlow, Deref}; +use std::path::PathBuf; +use std::{cmp, fmt, iter}; -use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart, @@ -68,6 +62,7 @@ use rustc_hir::{self as hir}; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::{ @@ -76,18 +71,21 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; -use std::borrow::Cow; -use std::ops::{ControlFlow, Deref}; -use std::path::PathBuf; -use std::{cmp, fmt, iter}; + +use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; +use crate::infer; +use crate::infer::relate::{self, RelateResult, TypeRelation}; +use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; +use crate::traits::{ + IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, + PredicateObligation, +}; mod note_and_explain; mod suggest; -pub(crate) mod need_type_info; -pub mod sub_relations; -pub use need_type_info::TypeAnnotationNeeded; pub mod region; +pub mod sub_relations; pub mod nice_region_error; @@ -1242,7 +1240,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(values) => { let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { - ValuePairs::Terms(infer::ExpectedFound { expected, found }) => { + ValuePairs::Terms(ExpectedFound { expected, found }) => { match (expected.unpack(), found.unpack()) { (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { let is_simple_err = expected.is_simple_text(self.tcx) @@ -1254,7 +1252,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ( is_simple_err, - Mismatch::Variable(infer::ExpectedFound { expected, found }), + Mismatch::Variable(ExpectedFound { expected, found }), ) } (ty::TermKind::Const(_), ty::TermKind::Const(_)) => { @@ -1263,13 +1261,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (false, Mismatch::Fixed("type")), } } - ValuePairs::PolySigs(infer::ExpectedFound { expected, found }) => { + ValuePairs::PolySigs(ExpectedFound { expected, found }) => { OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) .report(diag); (false, Mismatch::Fixed("signature")) } ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")), - ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => { + ValuePairs::Aliases(ExpectedFound { expected, .. }) => { (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), @@ -1303,9 +1301,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let Some((sp, msg)) = secondary_span { if swap_secondary_and_primary { - let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound { - expected, - .. + let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound { + expected, .. })) = values { Cow::from(format!("expected this to be `{expected}`")) @@ -1765,9 +1762,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if let Some(tykind) = tykind && let hir::TyKind::Array(_, length) = tykind - && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let hir::ArrayLen::Body(ct) = length { - let span = self.tcx.hir().span(*hir_id); + let span = ct.span(); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { span, length: sz.found }) } else { None @@ -1933,14 +1930,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.0.tcx } - fn tag(&self) -> &'static str { - "SameTypeModuloInfer" - } - fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>( &mut self, _variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs index cbeec591960..74dcde03639 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs @@ -1,21 +1,20 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where both the regions are anonymous. +use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type; +use crate::error_reporting::infer::nice_region_error::util::AnonymousParamInfo; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::AddLifetimeParamsSuggestion; use crate::errors::LifetimeMismatch; use crate::errors::LifetimeMismatchLabels; -use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; -use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::SubregionOrigin; -use crate::infer::TyCtxt; use rustc_errors::Subdiagnostic; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::LocalDefId; use rustc_hir::Ty; -use rustc_middle::ty::Region; +use rustc_middle::ty::{Region, TyCtxt}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs index b91b755d683..b91b755d683 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs index 7996b4bf65b..550cc455e01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs @@ -1,12 +1,12 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; use crate::errors::{ DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; use rustc_data_structures::fx::FxIndexSet; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs index cffdfa88752..ced4c384f02 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs @@ -1,6 +1,6 @@ -use crate::infer::error_reporting::TypeErrCtxt; -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::lexical_region_resolve::RegionResolutionError::*; +use crate::error_reporting::infer::TypeErrCtxt; +use crate::infer::RegionResolutionError; +use crate::infer::RegionResolutionError::*; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index 85624c9ca73..d1802d2f5ee 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs @@ -1,11 +1,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::{ - errors::ExplicitLifetimeRequired, - infer::error_reporting::nice_region_error::find_anon_type::find_anon_type, -}; +use crate::error_reporting::infer::nice_region_error::find_anon_type::find_anon_type; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; +use crate::errors::ExplicitLifetimeRequired; use rustc_errors::Diag; use rustc_middle::ty; use rustc_span::symbol::kw; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 80b7e3b4fa5..476ac3f1720 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -1,9 +1,9 @@ +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes, TraitPlaceholderMismatch, TyOrSig, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index a3f306802de..e9f17a3e3e2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs @@ -1,9 +1,6 @@ -use crate::{ - errors::PlaceholderRelationLfNotSatisfied, - infer::{ - error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin, - }, -}; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; +use crate::errors::PlaceholderRelationLfNotSatisfied; +use crate::infer::{RegionResolutionError, SubregionOrigin}; use rustc_data_structures::intern::Interned; use rustc_errors::Diag; use rustc_middle::ty::{self, RePlaceholder, Region}; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 9973646aecd..ce157ff3dc8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -1,11 +1,11 @@ //! Error Reporting for static impl Traits. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, ReqIntroducedLocations, }; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxIndexSet; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index 7f3e23716f9..c58c7e13551 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -1,8 +1,8 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::error_reporting::infer::nice_region_error::NiceRegionError; use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; +use crate::infer::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs index 83145e4f7b2..30fa98c5526 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs @@ -1,13 +1,13 @@ //! Helper functions corresponding to lifetime errors due to //! anonymous regions. -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; +use crate::error_reporting::infer::nice_region_error::NiceRegionError; + /// Information about the anonymous region we are searching for. #[derive(Debug)] pub struct AnonymousParamInfo<'tcx> { diff --git a/compiler/rustc_infer/src/error_reporting/infer/note.rs b/compiler/rustc_infer/src/error_reporting/infer/note.rs new file mode 100644 index 00000000000..aeb3049c2ae --- /dev/null +++ b/compiler/rustc_infer/src/error_reporting/infer/note.rs @@ -0,0 +1,421 @@ +use crate::error_reporting::infer::{note_and_explain_region, TypeErrCtxt}; +use crate::errors::{ + note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, + RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, +}; +use crate::fluent_generated as fluent; +use crate::infer::{self, SubregionOrigin}; +use rustc_errors::{Diag, Subdiagnostic}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; +use rustc_span::symbol::kw; + +use super::ObligationCauseAsDiagArg; + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { + match *origin { + infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + span: trace.cause.span, + requirement: ObligationCauseAsDiagArg(trace.cause.clone()), + expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)), + } + .add_to_diag(err), + infer::Reborrow(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) + } + infer::RelateObjectBound(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } + .add_to_diag(err); + } + infer::ReferenceOutlivesReferent(ty, span) => { + RegionOriginNote::WithName { + span, + msg: fluent::infer_reference_outlives_referent, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diag(err); + } + infer::RelateParamBound(span, ty, opt_span) => { + RegionOriginNote::WithName { + span, + msg: fluent::infer_relate_param_bound, + name: &self.ty_to_string(ty), + continues: opt_span.is_some(), + } + .add_to_diag(err); + if let Some(span) = opt_span { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } + .add_to_diag(err); + } + } + infer::RelateRegionParamBound(span) => { + RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } + .add_to_diag(err); + } + infer::CompareImplItemObligation { span, .. } => { + RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } + .add_to_diag(err); + } + infer::CheckAssociatedTypeBounds { ref parent, .. } => { + self.note_region_origin(err, parent); + } + infer::AscribeUserTypeProvePredicate(span) => { + RegionOriginNote::Plain { + span, + msg: fluent::infer_ascribe_user_type_prove_predicate, + } + .add_to_diag(err); + } + } + } + + pub(super) fn report_concrete_failure( + &self, + generic_param_scope: LocalDefId, + origin: SubregionOrigin<'tcx>, + sub: Region<'tcx>, + sup: Region<'tcx>, + ) -> Diag<'a> { + let mut err = match origin { + infer::Subtype(box trace) => { + let terr = TypeError::RegionsDoesNotOutlive(sup, sub); + let mut err = self.report_and_explain_type_error(trace, terr); + match (*sub, *sup) { + (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} + (ty::RePlaceholder(_), _) => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "", + sup, + " doesn't meet the lifetime requirements", + None, + ); + } + (_, ty::RePlaceholder(_)) => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "the required lifetime does not necessarily outlive ", + sub, + "", + None, + ); + } + _ => { + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "", + sup, + "...", + None, + ); + note_and_explain_region( + self.tcx, + &mut err, + generic_param_scope, + "...does not necessarily outlive ", + sub, + "", + None, + ); + } + } + err + } + infer::Reborrow(span) => { + let reference_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::RefValidFor, + note_and_explain::SuffixKind::Continues, + ); + let content_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::ContentValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(OutlivesContent { + span, + notes: reference_valid.into_iter().chain(content_valid).collect(), + }) + } + infer::RelateObjectBound(span) => { + let object_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::TypeObjValidFor, + note_and_explain::SuffixKind::Empty, + ); + let pointer_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::SourcePointerValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(OutlivesBound { + span, + notes: object_valid.into_iter().chain(pointer_valid).collect(), + }) + } + infer::RelateParamBound(span, ty, opt_span) => { + let prefix = match *sub { + ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, + _ => note_and_explain::PrefixKind::TypeOutlive, + }; + let suffix = if opt_span.is_some() { + note_and_explain::SuffixKind::ReqByBinding + } else { + note_and_explain::SuffixKind::Empty + }; + let note = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + opt_span, + prefix, + suffix, + ); + self.dcx().create_err(FulfillReqLifetime { + span, + ty: self.resolve_vars_if_possible(ty), + note, + }) + } + infer::RelateRegionParamBound(span) => { + let param_instantiated = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::LfParamInstantiatedWith, + note_and_explain::SuffixKind::Empty, + ); + let param_must_outlive = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::LfParamMustOutlive, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(LfBoundNotSatisfied { + span, + notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), + }) + } + infer::ReferenceOutlivesReferent(ty, span) => { + let pointer_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::PointerValidFor, + note_and_explain::SuffixKind::Empty, + ); + let data_valid = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::DataValidFor, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(RefLongerThanData { + span, + ty: self.resolve_vars_if_possible(ty), + notes: pointer_valid.into_iter().chain(data_valid).collect(), + }) + } + infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { + let mut err = self.infcx.report_extra_impl_obligation( + span, + impl_item_def_id, + trait_item_def_id, + &format!("`{sup}: {sub}`"), + ); + // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause + if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) + && generics.where_clause_span.contains(span) + { + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); + } + err + } + infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { + let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); + + // Don't mention the item name if it's an RPITIT, since that'll just confuse + // folks. + if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) { + let trait_item_span = self.tcx.def_span(trait_item_def_id); + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label( + trait_item_span, + format!("definition of `{item_name}` from trait"), + ); + } + + self.suggest_copy_trait_method_bounds( + trait_item_def_id, + impl_item_def_id, + &mut err, + ); + err + } + infer::AscribeUserTypeProvePredicate(span) => { + let instantiated = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sup, + None, + note_and_explain::PrefixKind::LfInstantiatedWith, + note_and_explain::SuffixKind::Empty, + ); + let must_outlive = note_and_explain::RegionExplanation::new( + self.tcx, + generic_param_scope, + sub, + None, + note_and_explain::PrefixKind::LfMustOutlive, + note_and_explain::SuffixKind::Empty, + ); + self.dcx().create_err(LfBoundNotSatisfied { + span, + notes: instantiated.into_iter().chain(must_outlive).collect(), + }) + } + }; + if sub.is_error() || sup.is_error() { + err.downgrade_to_delayed_bug(); + } + err + } + + pub fn suggest_copy_trait_method_bounds( + &self, + trait_item_def_id: DefId, + impl_item_def_id: LocalDefId, + err: &mut Diag<'_>, + ) { + // FIXME(compiler-errors): Right now this is only being used for region + // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, + // 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 { + return; + }; + let trait_args = trait_ref + .instantiate_identity() + // Replace the explicit self type with `Self` for better suggestion rendering + .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) + .args; + let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) + .rebase_onto(self.tcx, impl_def_id, trait_args); + + let Ok(trait_predicates) = + self.tcx + .explicit_predicates_of(trait_item_def_id) + .instantiate_own(self.tcx, trait_item_args) + .map(|(pred, _)| { + if pred.is_suggestable(self.tcx, false) { + Ok(pred.to_string()) + } else { + Err(()) + } + }) + .collect::<Result<Vec<_>, ()>>() + else { + return; + }; + + let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { + return; + }; + + let suggestion = if trait_predicates.is_empty() { + WhereClauseSuggestions::Remove { span: generics.where_clause_span } + } else { + let space = if generics.where_clause_span.is_empty() { " " } else { "" }; + WhereClauseSuggestions::CopyPredicates { + span: generics.where_clause_span, + space, + trait_predicates: trait_predicates.join(", "), + } + }; + err.subdiagnostic(suggestion); + } + + pub(super) fn report_placeholder_failure( + &self, + generic_param_scope: LocalDefId, + placeholder_origin: SubregionOrigin<'tcx>, + sub: Region<'tcx>, + sup: Region<'tcx>, + ) -> Diag<'a> { + // I can't think how to do better than this right now. -nikomatsakis + debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); + match placeholder_origin { + infer::Subtype(box ref trace) + if matches!( + &trace.cause.code().peel_derives(), + ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) + ) => + { + // Hack to get around the borrow checker because trace.cause has an `Rc`. + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = + &trace.cause.code().peel_derives() + && !span.is_dummy() + { + let span = *span; + self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup) + .with_span_note(span, "the lifetime requirement is introduced here") + } else { + unreachable!( + "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." + ) + } + } + infer::Subtype(box trace) => { + let terr = TypeError::RegionsPlaceholderMismatch; + return self.report_and_explain_type_error(trace, terr); + } + _ => { + return self.report_concrete_failure( + generic_param_scope, + placeholder_origin, + sub, + sup, + ); + } + } + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs index d5e7de897d0..d5e7de897d0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/region.rs b/compiler/rustc_infer/src/error_reporting/infer/region.rs index 191cb23184d..5d41bb5d271 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/region.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/region.rs @@ -18,12 +18,12 @@ use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; use super::{nice_region_error, ObligationCauseAsDiagArg}; +use crate::error_reporting::infer::{ObligationCauseExt as _, TypeErrCtxt}; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, }; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::{ObligationCauseExt as _, TypeErrCtxt}; use crate::infer::region_constraints::GenericKind; use crate::infer::{self, InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin}; @@ -1269,9 +1269,13 @@ fn suggest_precise_capturing<'tcx>( captured_lifetime: ty::Region<'tcx>, diag: &mut Diag<'_>, ) { - let hir::OpaqueTy { bounds, .. } = + let hir::OpaqueTy { bounds, origin, .. } = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else { + return; + }; + let new_lifetime = Symbol::intern(&captured_lifetime.to_string()); if let Some((args, span)) = bounds.iter().find_map(|bound| match bound { @@ -1306,6 +1310,7 @@ fn suggest_precise_capturing<'tcx>( let variances = tcx.variances_of(opaque_def_id); let mut generics = tcx.generics_of(opaque_def_id); + let mut synthetics = vec![]; loop { for param in &generics.own_params { if variances[param.index as usize] == ty::Bivariant { @@ -1317,9 +1322,7 @@ fn suggest_precise_capturing<'tcx>( captured_lifetimes.insert(param.name); } ty::GenericParamDefKind::Type { synthetic: true, .. } => { - // FIXME: We can't provide a good suggestion for - // `use<...>` if we have an APIT. Bail for now. - return; + synthetics.push((tcx.def_span(param.def_id), param.name)); } ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { @@ -1340,17 +1343,86 @@ fn suggest_precise_capturing<'tcx>( return; } - let concatenated_bounds = captured_lifetimes - .into_iter() - .chain(captured_non_lifetimes) - .map(|sym| sym.to_string()) - .collect::<Vec<_>>() - .join(", "); - - diag.subdiagnostic(errors::AddPreciseCapturing::New { - span: tcx.def_span(opaque_def_id).shrink_to_hi(), - new_lifetime, - concatenated_bounds, - }); + if synthetics.is_empty() { + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::<Vec<_>>() + .join(", "); + + diag.subdiagnostic(errors::AddPreciseCapturing::New { + span: tcx.def_span(opaque_def_id).shrink_to_hi(), + new_lifetime, + concatenated_bounds, + }); + } else { + let mut next_fresh_param = || { + ["T", "U", "V", "W", "X", "Y", "A", "B", "C"] + .into_iter() + .map(Symbol::intern) + .chain((0..).map(|i| Symbol::intern(&format!("T{i}")))) + .find(|s| captured_non_lifetimes.insert(*s)) + .unwrap() + }; + + let mut new_params = String::new(); + let mut suggs = vec![]; + let mut apit_spans = vec![]; + + for (i, (span, name)) in synthetics.into_iter().enumerate() { + apit_spans.push(span); + + let fresh_param = next_fresh_param(); + + // Suggest renaming. + suggs.push((span, fresh_param.to_string())); + + // Super jank. Turn `impl Trait` into `T: Trait`. + // + // This currently involves stripping the `impl` from the name of + // the parameter, since APITs are always named after how they are + // rendered in the AST. This sucks! But to recreate the bound list + // from the APIT itself would be miserable, so we're stuck with + // this for now! + if i > 0 { + new_params += ", "; + } + let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start(); + new_params += fresh_param.as_str(); + new_params += ": "; + new_params += name_as_bounds; + } + + let Some(generics) = tcx.hir().get_generics(fn_def_id) else { + // This shouldn't happen, but don't ICE. + return; + }; + + // Add generics or concatenate to the end of the list. + suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() { + (params_span, format!(", {new_params}")) + } else { + (generics.span, format!("<{new_params}>")) + }); + + let concatenated_bounds = captured_lifetimes + .into_iter() + .chain(captured_non_lifetimes) + .map(|sym| sym.to_string()) + .collect::<Vec<_>>() + .join(", "); + + suggs.push(( + tcx.def_span(opaque_def_id).shrink_to_hi(), + format!(" + use<{concatenated_bounds}>"), + )); + + diag.subdiagnostic(errors::AddPreciseCapturingAndParams { + suggs, + new_lifetime, + apit_spans, + }); + } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs b/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs index ef26a8ff7b8..ef26a8ff7b8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/sub_relations.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/error_reporting/infer/suggest.rs index 13b145296a7..4d11ab9fac6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/error_reporting/infer/suggest.rs @@ -1,4 +1,4 @@ -use crate::infer::error_reporting::hir::Path; +use crate::error_reporting::infer::hir::Path; use core::ops::ControlFlow; use hir::def::CtorKind; use hir::intravisit::{walk_expr, walk_stmt, Visitor}; diff --git a/compiler/rustc_infer/src/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/mod.rs new file mode 100644 index 00000000000..132485ec661 --- /dev/null +++ b/compiler/rustc_infer/src/error_reporting/mod.rs @@ -0,0 +1 @@ +pub mod infer; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ce1b0f86d03..2ce712e0bff 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -15,11 +15,10 @@ use rustc_span::symbol::kw; use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; +use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; +use crate::error_reporting::infer::ObligationCauseAsDiagArg; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::{ - need_type_info::UnderspecifiedArgKind, nice_region_error::placeholder_error::Highlighted, - ObligationCauseAsDiagArg, -}; +use crate::infer::need_type_info::UnderspecifiedArgKind; use std::path::PathBuf; @@ -1610,3 +1609,25 @@ pub enum AddPreciseCapturing { post: &'static str, }, } + +pub struct AddPreciseCapturingAndParams { + pub suggs: Vec<(Span, String)>, + pub new_lifetime: Symbol, + pub apit_spans: Vec<Span>, +} + +impl Subdiagnostic for AddPreciseCapturingAndParams { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.arg("new_lifetime", self.new_lifetime); + diag.multipart_suggestion_verbose( + fluent::infer_precise_capturing_new_but_apit, + self.suggs, + Applicability::MaybeIncorrect, + ); + diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params); + } +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 4fbeb0ec102..d71b7f3c264 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,5 +1,5 @@ +use crate::error_reporting::infer::nice_region_error::find_anon_type; use crate::fluent_generated as fluent; -use crate::infer::error_reporting::nice_region_error::find_anon_type; use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic}; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index a0be545d46f..c9073d8c23e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,9 +11,9 @@ pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; +use crate::error_reporting::infer::TypeErrCtxt; use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; -use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; use lexical_region_resolve::LexicalRegionResolutions; use opaque_types::OpaqueTypeStorage; @@ -54,7 +54,6 @@ use type_variable::TypeVariableOrigin; pub mod at; pub mod canonical; mod context; -pub mod error_reporting; pub mod free_regions; mod freshen; mod lexical_region_resolve; @@ -66,6 +65,8 @@ pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; +// FIXME(error_reporting): Where should we put this? +pub mod need_type_info; #[must_use] #[derive(Debug)] @@ -1426,17 +1427,17 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, ) -> Result<ty::Const<'tcx>, ErrorHandled> { match self.const_eval_resolve(param_env, unevaluated, span) { - Ok(Some(val)) => Ok(ty::Const::new_value( + Ok(Ok(val)) => Ok(ty::Const::new_value( self.tcx, val, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), )), - Ok(None) => { + Ok(Err(bad_ty)) => { let tcx = self.tcx; let def_id = unevaluated.def; span_bug!( tcx.def_span(def_id), - "unable to construct a constant value for the unevaluated constant {:?}", + "unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible", unevaluated ); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/need_type_info.rs index 084aebc296f..4f3dcd9043f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/need_type_info.rs @@ -1,8 +1,8 @@ +use crate::error_reporting::infer::TypeErrCtxt; use crate::errors::{ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, SourceKindMultiSuggestion, SourceKindSubdiag, }; -use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::InferCtxt; use rustc_errors::{codes::*, Diag, IntoDiagArg}; use rustc_hir as hir; 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 978b92fd898..c63eeaf812c 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -110,7 +110,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern /// is already bound to a different value. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn bind( &mut self, br: ty::BoundRegion, @@ -133,11 +133,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> { - fn tag(&self) -> &'static str { - "MatchAgainstHigherRankedOutlives" - } - - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -154,13 +150,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> if variance != ty::Bivariant { self.relate(a, b) } else { Ok(a) } } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn regions( &mut self, pattern: ty::Region<'tcx>, value: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("self.pattern_depth = {:?}", self.pattern_depth); if let ty::RegionKind::ReBound(depth, br) = pattern.kind() && depth == self.pattern_depth { @@ -172,7 +167,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> } } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn tys(&mut self, pattern: Ty<'tcx>, value: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { // FIXME(non_lifetime_binders): What to do here? if matches!(pattern.kind(), ty::Error(_) | ty::Bound(..)) { @@ -185,13 +180,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> } } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn consts( &mut self, pattern: ty::Const<'tcx>, value: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), pattern, value); if pattern == value { Ok(pattern) } else { @@ -199,6 +193,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> } } + #[instrument(skip(self), level = "trace")] fn binders<T>( &mut self, pattern: ty::Binder<'tcx, T>, diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index c93b89756f9..1dc03de4c8b 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -79,6 +79,7 @@ impl<'tcx> InferCtxt<'tcx> { where R: PredicateEmittingRelation<InferCtxt<'tcx>>, { + debug!("super_combine_tys::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!b.has_escaping_bound_vars()); @@ -174,9 +175,10 @@ impl<'tcx> InferCtxt<'tcx> { where R: PredicateEmittingRelation<InferCtxt<'tcx>>, { - debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); + debug!("super_combine_consts::<{}>({:?}, {:?})", std::any::type_name::<R>(), a, b); debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!b.has_escaping_bound_vars()); + if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index fe3b8d60fb9..30cfbcae6b2 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -372,7 +372,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { - Ok(alias) => Ok(alias.to_ty(self.tcx())), + Ok(alias) => Ok(alias.to_ty(self.cx())), Err(e) => { if is_nested_alias { return Err(e); @@ -397,14 +397,10 @@ impl<'tcx> Generalizer<'_, 'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } - fn tag(&self) -> &'static str { - "Generalizer" - } - fn relate_item_args( &mut self, item_def_id: DefId, @@ -417,7 +413,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { // (e.g., #41849). relate::relate_args_invariantly(self, a_arg, b_arg) } else { - let tcx = self.tcx(); + let tcx = self.cx(); let opt_variances = tcx.variances_of(item_def_id); relate::relate_args_with_variances( self, @@ -525,7 +521,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); - Ok(Ty::new_var(self.tcx(), new_var_id)) + Ok(Ty::new_var(self.cx(), new_var_id)) } } } @@ -654,7 +650,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { { variable_table.union(vid, new_var_id); } - Ok(ty::Const::new_var(self.tcx(), new_var_id)) + Ok(ty::Const::new_var(self.cx(), new_var_id)) } } } @@ -672,7 +668,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { args, args, )?; - Ok(ty::Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst { def, args })) + Ok(ty::Const::new_unevaluated(self.cx(), ty::UnevaluatedConst { def, args })) } ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 5bb8a113e17..4f2cf2c43e7 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -23,11 +23,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> { - fn tag(&self) -> &'static str { - "Glb" - } - - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -47,27 +43,28 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> { } } + #[instrument(skip(self), level = "trace")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { lattice::super_lattice_tys(self, a, b) } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( - self.tcx(), + self.cx(), origin, a, b, )) } + #[instrument(skip(self), level = "trace")] fn consts( &mut self, a: ty::Const<'tcx>, diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 46e7466141a..d1d87071562 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -56,8 +56,6 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>( where L: LatticeDir<'a, 'tcx>, { - debug!("{}", this.tag()); - if a == b { return Ok(a); } diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 94c1464817f..2eb20f311cf 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -23,11 +23,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> { - fn tag(&self) -> &'static str { - "Lub" - } - - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.tcx() } @@ -51,23 +47,23 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> { lattice::super_lattice_tys(self, a, b) } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( - self.tcx(), + self.cx(), origin, a, b, )) } + #[instrument(skip(self), level = "trace")] fn consts( &mut self, a: ty::Const<'tcx>, diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index e206f530519..3fe35354286 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -28,11 +28,7 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { - fn tag(&self) -> &'static str { - "TypeRelating" - } - - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.fields.infcx.tcx } @@ -48,7 +44,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { // (e.g., #41849). relate_args_invariantly(self, a_arg, b_arg) } else { - let tcx = self.tcx(); + let tcx = self.cx(); let opt_variances = tcx.variances_of(item_def_id); relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) } @@ -71,7 +67,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { r } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { if a == b { return Ok(a); @@ -88,7 +84,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { // can't make progress on `A <: B` if both A and B are // type variables, so record an obligation. self.fields.goals.push(Goal::new( - self.tcx(), + self.cx(), self.fields.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: true, @@ -101,7 +97,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { // can't make progress on `B <: A` if both A and B are // type variables, so record an obligation. self.fields.goals.push(Goal::new( - self.tcx(), + self.cx(), self.fields.param_env, ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: false, @@ -134,7 +130,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { (&ty::Error(e), _) | (_, &ty::Error(e)) => { infcx.set_tainted_by_errors(e); - return Ok(Ty::new_error(self.tcx(), e)); + return Ok(Ty::new_error(self.cx(), e)); } ( @@ -166,12 +162,12 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { Ok(a) } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); match self.ambient_variance { @@ -209,6 +205,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { Ok(a) } + #[instrument(skip(self), level = "trace")] fn consts( &mut self, a: ty::Const<'tcx>, diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index b65ac859667..02ebf933f53 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -34,6 +34,7 @@ #[macro_use] extern crate tracing; +pub mod error_reporting; mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 4b3b0728f38..b5abf145d6b 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -53,6 +53,11 @@ tracing = "0.1" [features] # tidy-alphabetical-start -llvm = ['rustc_codegen_llvm'] -rustc_use_parallel_compiler = ['rustc-rayon', 'rustc-rayon-core', 'rustc_query_impl/rustc_use_parallel_compiler', 'rustc_errors/rustc_use_parallel_compiler'] +llvm = ['dep:rustc_codegen_llvm'] +rustc_use_parallel_compiler = [ + 'dep:rustc-rayon', + 'dep:rustc-rayon-core', + 'rustc_query_impl/rustc_use_parallel_compiler', + 'rustc_errors/rustc_use_parallel_compiler' +] # tidy-alphabetical-end diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index de04d882f51..7d7b97e2eb1 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -403,8 +403,9 @@ lint_inner_macro_attribute_unstable = inner macro attributes are unstable 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` - .note = an LLVM bug makes these labels ambiguous with a binary literal number - .note = see <https://bugs.llvm.org/show_bug.cgi?id=36144> for more information + .help = start numbering with `2` instead + .note1 = an LLVM bug makes these labels ambiguous with a binary literal number on x86 + .note2 = see <https://github.com/llvm/llvm-project/issues/99547> for more information lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly .help = only local labels of the form `<number>:` should be used in inline asm @@ -556,6 +557,9 @@ lint_non_fmt_panic_unused = } .add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally +lint_non_glob_import_type_ir_inherent = non-glob import of `rustc_type_ir::inherent` + .suggestion = try using a glob import instead + lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may come from an old version of the `{$crate_name}` crate, try updating your dependency with `cargo update -p {$crate_name}` lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 485c214ac9d..9ebada0fff3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -66,6 +66,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; use rustc_target::abi::Abi; +use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; @@ -2739,8 +2740,9 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail - /// # #![feature(asm_experimental_arch)] + /// ```rust,ignore (fails on non-x86_64) + /// #![cfg(target_arch = "x86_64")] + /// /// use std::arch::asm; /// /// fn main() { @@ -2750,19 +2752,32 @@ declare_lint! { /// } /// ``` /// - /// {{produces}} + /// This will produce: + /// + /// ```text + /// error: avoid using labels containing only the digits `0` and `1` in inline assembly + /// --> <source>:7:15 + /// | + /// 7 | asm!("0: jmp 0b"); + /// | ^ use a different label that doesn't start with `0` or `1` + /// | + /// = help: start numbering with `2` instead + /// = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + /// = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information + /// = note: `#[deny(binary_asm_labels)]` on by default + /// ``` /// /// ### Explanation /// - /// A [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary - /// literal instead of a reference to the previous local label `0`. Note that even though the - /// bug is marked as fixed, it only fixes a specific usage of intel syntax within standalone - /// files, not inline assembly. To work around this bug, don't use labels that could be - /// confused with a binary literal. + /// An [LLVM bug] causes this code to fail to compile because it interprets the `0b` as a binary + /// literal instead of a reference to the previous local label `0`. To work around this bug, + /// don't use labels that could be confused with a binary literal. + /// + /// This behavior is platform-specific to x86 and x86-64. /// /// See the explanation in [Rust By Example] for more details. /// - /// [LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144 + /// [LLVM bug]: https://github.com/llvm/llvm-project/issues/99547 /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels pub BINARY_ASM_LABELS, Deny, @@ -2908,16 +2923,22 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { InvalidAsmLabel::FormatArg { missing_precise_span }, ); } - AsmLabelKind::Binary => { - // the binary asm issue only occurs when using intel syntax - if !options.contains(InlineAsmOptions::ATT_SYNTAX) { - cx.emit_span_lint( - BINARY_ASM_LABELS, - span, - InvalidAsmLabel::Binary { missing_precise_span, span }, - ) - } + // the binary asm issue only occurs when using intel syntax on x86 targets + AsmLabelKind::Binary + if !options.contains(InlineAsmOptions::ATT_SYNTAX) + && matches!( + cx.tcx.sess.asm_arch, + Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None + ) => + { + cx.emit_span_lint( + BINARY_ASM_LABELS, + span, + InvalidAsmLabel::Binary { missing_precise_span, span }, + ) } + // No lint on anything other than x86 + AsmLabelKind::Binary => (), }; } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 772cc2ff8b9..e15eb90f827 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,7 +3,8 @@ use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, - QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, + NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, + TykindKind, UntranslatableDiag, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; @@ -264,6 +265,49 @@ fn gen_args(segment: &PathSegment<'_>) -> String { } declare_tool_lint! { + /// The `non_glob_import_of_type_ir_inherent_item` lint detects + /// non-glob imports of module `rustc_type_ir::inherent`. + pub rustc::NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, + Allow, + "non-glob import of `rustc_type_ir::inherent`", + report_in_external_macro: true +} + +declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT]); + +impl<'tcx> LateLintPass<'tcx> for TypeIr { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return }; + + let is_mod_inherent = |def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id); + let (lo, hi, snippet) = match path.segments { + [.., penultimate, segment] + if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) => + { + (segment.ident.span, item.ident.span, "*") + } + [.., segment] + if path.res.iter().flat_map(Res::opt_def_id).any(is_mod_inherent) + && let rustc_hir::UseKind::Single = kind => + { + let (lo, snippet) = + match cx.tcx.sess.source_map().span_to_snippet(path.span).as_deref() { + Ok("self") => (path.span, "*"), + _ => (segment.ident.span.shrink_to_hi(), "::*"), + }; + (lo, if segment.ident == item.ident { lo } else { item.ident.span }, snippet) + } + _ => return, + }; + cx.emit_span_lint( + NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, + path.span, + NonGlobImportTypeIrInherent { suggestion: lo.eq_ctxt(hi).then(|| lo.to(hi)), snippet }, + ); + } +} + +declare_tool_lint! { /// The `lint_pass_impl_without_macro` detects manual implementations of a lint /// pass, without using [`declare_lint_pass`] or [`impl_lint_pass`]. pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 8be8996e4c8..290f91045c4 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -120,7 +120,6 @@ use types::*; use unit_bindings::*; use unused::*; -/// Useful for other parts of the compiler / Clippy. pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, FindLintError, LintStore}; pub use context::{EarlyContext, LateContext, LintContext}; @@ -573,6 +572,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); store.register_late_mod_pass(|_| Box::new(TyTyKind)); + store.register_lints(&TypeIr::get_lints()); + store.register_late_mod_pass(|_| Box::new(TypeIr)); store.register_lints(&Diagnostics::get_lints()); store.register_late_mod_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::get_lints()); @@ -596,6 +597,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(PASS_BY_VALUE), LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO), LintId::of(USAGE_OF_QUALIFIED_TY), + LintId::of(NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT), LintId::of(EXISTING_DOC_KEYWORD), LintId::of(BAD_OPT_ACCESS), LintId::of(SPAN_USE_EQ_CTXT), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 308bb73f4ce..6c5f366727f 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -927,6 +927,14 @@ pub struct TyQualified { } #[derive(LintDiagnostic)] +#[diag(lint_non_glob_import_type_ir_inherent)] +pub struct NonGlobImportTypeIrInherent { + #[suggestion(code = "{snippet}", applicability = "maybe-incorrect")] + pub suggestion: Option<Span>, + pub snippet: &'static str, +} + +#[derive(LintDiagnostic)] #[diag(lint_lintpass_by_hand)] #[help] pub struct LintPassByHand; @@ -2066,7 +2074,9 @@ pub enum InvalidAsmLabel { missing_precise_span: bool, }, #[diag(lint_invalid_asm_label_binary)] - #[note] + #[help] + #[note(lint_note1)] + #[note(lint_note2)] Binary { #[note(lint_invalid_asm_label_no_span)] missing_precise_span: bool, diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index c1f5cd45dc8..fa23f120468 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -78,7 +78,7 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { .tcx .sess .source_map() - .span_to_snippet(c.value.span) + .span_to_snippet(c.span()) .unwrap_or_else(|_| "_".into()), GenericArg::Infer(_) => String::from("_"), }) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index aa7844f4012..04764b71b10 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1203,16 +1203,16 @@ declare_lint! { /// This was historically allowed, but is not the intended behavior /// according to the visibility rules. This is a [future-incompatible] /// lint to transition this to a hard error in the future. See [issue - /// #34537] for more details. + /// #127909] for more details. /// - /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [issue #127909]: https://github.com/rust-lang/rust/issues/127909 /// [future-incompatible]: ../index.md#future-incompatible-lints pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, Deny, "detect public re-exports of private extern crates", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #127909 <https://github.com/rust-lang/rust/issues/127909>", }; } diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index a9d1362a338..ccf1a5429e2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -4,12 +4,16 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // Derived from: -// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h -// * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp +// * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/include/llvm/Object/ArchiveWriter.h +// * https://github.com/llvm/llvm-project/blob/ef6d1ec07c693352c4a60dd58db08d2d8558f6ea/llvm/lib/Object/ArchiveWriter.cpp +#include "LLVMWrapper.h" #include "SuppressLLVMWarnings.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ObjectFile.h" #include <llvm/Support/raw_ostream.h> @@ -34,6 +38,27 @@ static bool isArchiveSymbol(const object::BasicSymbolRef &S) { typedef void *(*LLVMRustGetSymbolsCallback)(void *, const char *); typedef void *(*LLVMRustGetSymbolsErrorCallback)(const char *); +// This function is copied from ArchiveWriter.cpp. +static Expected<std::unique_ptr<SymbolicFile>> +getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { + const file_magic Type = identify_magic(Buf.getBuffer()); + // Don't attempt to read non-symbolic file types. + if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) + return nullptr; + if (Type == file_magic::bitcode) { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + Buf, file_magic::bitcode, &Context); + if (!ObjOrErr) + return ObjOrErr.takeError(); + return std::move(*ObjOrErr); + } else { + auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); + if (!ObjOrErr) + return ObjOrErr.takeError(); + return std::move(*ObjOrErr); + } +} + // Note: This is implemented in C++ instead of using the C api from Rust as // IRObjectFile doesn't implement getSymbolName, only printSymbolName, which is // inaccessible from the C api. @@ -49,36 +74,16 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; - std::unique_ptr<object::SymbolicFile> Obj; - - const file_magic Type = identify_magic(Buf->getBuffer()); - if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) { - return 0; - } - - if (Type == file_magic::bitcode) { - auto ObjOrErr = object::SymbolicFile::createSymbolicFile( - Buf->getMemBufferRef(), file_magic::bitcode, &Context); - if (!ObjOrErr) { - Error E = ObjOrErr.takeError(); - SmallString<0> ErrorBuf; - auto Error = raw_svector_ostream(ErrorBuf); - Error << E << '\0'; - return ErrorCallback(Error.str().data()); - } - Obj = std::move(*ObjOrErr); - } else { - auto ObjOrErr = - object::SymbolicFile::createSymbolicFile(Buf->getMemBufferRef()); - if (!ObjOrErr) { - Error E = ObjOrErr.takeError(); - SmallString<0> ErrorBuf; - auto Error = raw_svector_ostream(ErrorBuf); - Error << E << '\0'; - return ErrorCallback(Error.str().data()); - } - Obj = std::move(*ObjOrErr); + Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + Error E = ObjOrErr.takeError(); + SmallString<0> ErrorBuf; + auto Error = raw_svector_ostream(ErrorBuf); + Error << E << '\0'; + return ErrorCallback(Error.str().data()); } + std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); for (const object::BasicSymbolRef &S : Obj->symbols()) { if (!isArchiveSymbol(S)) @@ -97,3 +102,72 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, } return 0; } + +// Encoding true and false as invalid pointer values +#define TRUE_PTR (void *)1 +#define FALSE_PTR (void *)0 + +extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer( + StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); + SmallString<0> SymNameBuf; + auto SymName = raw_svector_ostream(SymNameBuf); + + // Code starting from this line is copied from s64BitSymbolicFile in + // ArchiveWriter.cpp. + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + return false; + } + std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); + + return Obj != nullptr ? Obj->is64Bit() : false; +} + +extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer( + StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); + SmallString<0> SymNameBuf; + auto SymName = raw_svector_ostream(SymNameBuf); + + // In the scenario when LLVMContext is populated SymbolicFile will contain a + // reference to it, thus SymbolicFile should be destroyed first. + LLVMContext Context; + Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = + getSymbolicFile(Buf->getMemBufferRef(), Context); + if (!ObjOrErr) { + return false; + } + std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr); + + if (Obj == nullptr) { + return false; + } + + // Code starting from this line is copied from isECObject in + // ArchiveWriter.cpp with an extra #if to work with LLVM 17. + if (Obj->isCOFF()) + return cast<llvm::object::COFFObjectFile>(&*Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + +#if LLVM_VERSION_GE(18, 0) + if (Obj->isCOFFImportFile()) + return cast<llvm::object::COFFImportFile>(&*Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; +#endif + + if (Obj->isIR()) { + Expected<std::string> TripleStr = + getBitcodeTargetTriple(Obj->getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; + } + + return false; +} diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index e5366c9b518..1365afbce1c 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -33,7 +33,7 @@ pub unsafe extern "C" fn LLVMRustStringWriteImpl( ptr: *const c_char, size: size_t, ) { - let slice = slice::from_raw_parts(ptr as *const u8, size); + let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) }; sr.bytes.borrow_mut().extend_from_slice(slice); } diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index d41ceb29816..627f4088d5f 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -45,7 +45,7 @@ pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStre quote! { type Lifted = #lifted; - fn lift_to_tcx(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { + fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { Some(match self { #body }) } }, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 3dc592980fd..290ebde8712 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -40,5 +40,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon-core"] +rustc_use_parallel_compiler = ["dep:rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 2f3a6ee601b..ad59bfa9047 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -912,6 +912,7 @@ impl<'hir> Map<'hir> { Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, Node::ConstBlock(constant) => self.body(constant.body).value.span, + Node::ConstArg(const_arg) => const_arg.span(), Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, @@ -962,7 +963,8 @@ impl<'hir> Map<'hir> { /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when /// called with the HirId for the `{ ... }` anon const pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> { - match self.tcx.parent_hir_node(anon_const) { + let const_arg = self.tcx.parent_hir_id(anon_const); + match self.tcx.parent_hir_node(const_arg) { Node::GenericParam(GenericParam { def_id: param_id, kind: GenericParamKind::Const { .. }, @@ -1182,6 +1184,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { } Node::AnonConst(_) => node_str("const"), Node::ConstBlock(_) => node_str("const"), + Node::ConstArg(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), Node::Stmt(_) => node_str("stmt"), diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index fcea1ea81a7..d385be007d3 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -59,7 +59,7 @@ macro_rules! TrivialLiftImpls { $( impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty { type Lifted = Self; - fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> { + fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> { Some(self) } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 6a8498abaf9..9df19565ab3 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -90,9 +90,11 @@ TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; -/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. -/// This is needed in `thir::pattern::lower_inline_const`. -pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>; +/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed +/// because the value containts something of type `ty` that is not valtree-compatible. +/// The caller can then show an appropriate error; the query does not have the +/// necssary context to give good user-facing errors for this case. +pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 301c9911b44..d9fa5b02f7f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -157,9 +157,10 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> { type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()]; } -impl EraseType for Result<Option<ty::ValTree<'_>>, mir::interpret::ErrorHandled> { - type Result = - [u8; size_of::<Result<Option<ty::ValTree<'static>>, mir::interpret::ErrorHandled>>()]; +impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> { + type Result = [u8; size_of::< + Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>, + >()]; } impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index c97af68c29e..b80d00719ee 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -783,16 +783,13 @@ pub enum PatKind<'tcx> { }, /// One of the following: - /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus - /// exhaustiveness checking will detect if you use the same string twice in different - /// patterns. + /// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern + /// and thus exhaustiveness checking will detect if you use the same string/slice twice in + /// different patterns. /// * integer, bool, char or float (represented as a valtree), which will be handled by /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. - /// * Opaque constants (represented as `mir::ConstValue`), that must not be matched - /// structurally. So anything that does not derive `PartialEq` and `Eq`. - /// - /// These are always compared with the matched place using (the semantics of) `PartialEq`. + /// * `String`, if `string_deref_patterns` is enabled. Constant { value: mir::Const<'tcx>, }, diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 32d01d07c17..5cf1247f0c8 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,11 +1,12 @@ use crate::middle::resolve_bound_vars as rbv; use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar}; use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use either::Either; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, HirId}; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; @@ -182,16 +183,55 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { } } +/// In some cases, [`hir::ConstArg`]s that are being used in the type system +/// through const generics need to have their type "fed" to them +/// using the query system. +/// +/// Use this enum with [`Const::from_const_arg`] to instruct it with the +/// desired behavior. +#[derive(Debug, Clone, Copy)] +pub enum FeedConstTy { + /// Feed the type. + /// + /// The `DefId` belongs to the const param that we are supplying + /// this (anon) const arg to. + Param(DefId), + /// Don't feed the type. + No, +} + impl<'tcx> Const<'tcx> { + /// Convert a [`hir::ConstArg`] to a [`ty::Const`](Self). + #[instrument(skip(tcx), level = "debug")] + pub fn from_const_arg( + tcx: TyCtxt<'tcx>, + const_arg: &'tcx hir::ConstArg<'tcx>, + feed: FeedConstTy, + ) -> Self { + if let FeedConstTy::Param(param_def_id) = feed + && let hir::ConstArgKind::Anon(anon) = &const_arg.kind + { + tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); + } + + match const_arg.kind { + hir::ConstArgKind::Path(qpath) => { + // FIXME(min_generic_const_args): for now only params are lowered to ConstArgKind::Path + Self::from_param(tcx, qpath, const_arg.hir_id) + } + hir::ConstArgKind::Anon(anon) => Self::from_anon_const(tcx, anon.def_id), + } + } + /// Literals and const generic parameters are eagerly converted to a constant, everything else /// becomes `Unevaluated`. #[instrument(skip(tcx), level = "debug")] pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { let body_id = match tcx.hir_node_by_def_id(def) { hir::Node::AnonConst(ac) => ac.body, - _ => span_bug!( + node => span_bug!( tcx.def_span(def.to_def_id()), - "from_anon_const can only process anonymous constants" + "from_anon_const can only process anonymous constants, not {node:?}" ), }; @@ -200,7 +240,7 @@ impl<'tcx> Const<'tcx> { let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic"); - match Self::try_from_lit_or_param(tcx, ty, expr) { + match Self::try_from_lit(tcx, ty, expr) { Some(v) => v, None => ty::Const::new_unevaluated( tcx, @@ -212,12 +252,36 @@ impl<'tcx> Const<'tcx> { } } + /// Lower a const param to a [`Const`]. + /// + /// IMPORTANT: `qpath` must be a const param, otherwise this will panic + fn from_param(tcx: TyCtxt<'tcx>, qpath: hir::QPath<'tcx>, hir_id: HirId) -> Self { + let hir::QPath::Resolved(_, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }) = + qpath + else { + span_bug!(qpath.span(), "non-param {qpath:?} passed to Const::from_param") + }; + + match tcx.named_bound_var(hir_id) { + Some(rbv::ResolvedArg::EarlyBound(_)) => { + // Find the name and index of the const parameter by indexing the generics of + // the parent item and construct a `ParamConst`. + let item_def_id = tcx.parent(def_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + let name = tcx.item_name(def_id); + ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) + } + Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) + } + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), + arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), + } + } + #[instrument(skip(tcx), level = "debug")] - fn try_from_lit_or_param( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - expr: &'tcx hir::Expr<'tcx>, - ) -> Option<Self> { + fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) -> Option<Self> { // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments // currently have to be wrapped in curly brackets, so it's necessary to special-case. let expr = match &expr.kind { @@ -250,34 +314,15 @@ impl<'tcx> Const<'tcx> { } } - // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` - // does not provide the parents generics to anonymous constants. We still allow generic const - // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to - // ever try to instantiate the generic parameters in their bodies. - match expr.kind { - hir::ExprKind::Path(hir::QPath::Resolved( - _, - &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, - )) => { - match tcx.named_bound_var(expr.hir_id) { - Some(rbv::ResolvedArg::EarlyBound(_)) => { - // Find the name and index of the const parameter by indexing the generics of - // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); - Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name))) - } - Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - Some(ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))) - } - Some(rbv::ResolvedArg::Error(guar)) => Some(ty::Const::new_error(tcx, guar)), - arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), - } - } - _ => None, + if let hir::ExprKind::Path(hir::QPath::Resolved( + _, + &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, + )) = expr.kind + { + span_bug!(expr.span, "try_from_lit: received const param which shouldn't be possible") } + + None } #[inline] @@ -312,14 +357,16 @@ impl<'tcx> Const<'tcx> { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } - /// Returns the evaluated constant + /// Returns the evaluated constant as a valtree; + /// if that fails due to a valtree-incompatible type, indicate which type that is + /// by returning `Err(Left(bad_type))`. #[inline] - pub fn eval( + pub fn eval_valtree( self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, span: Span, - ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> { + ) -> Result<(Ty<'tcx>, ValTree<'tcx>), Either<Ty<'tcx>, ErrorHandled>> { assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); match self.kind() { ConstKind::Unevaluated(unevaluated) => { @@ -328,27 +375,47 @@ impl<'tcx> Const<'tcx> { let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - let Some(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)? - else { - // This can happen when we run on ill-typed code. - let e = tcx.dcx().span_delayed_bug( - span, - "`ty::Const::eval` called on a non-valtree-compatible type", - ); - return Err(e.into()); - }; - Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) + match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span) { + Ok(Ok(c)) => { + Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) + } + Ok(Err(bad_ty)) => Err(Either::Left(bad_ty)), + Err(err) => Err(Either::Right(err.into())), + } } ConstKind::Value(ty, val) => Ok((ty, val)), - ConstKind::Error(g) => Err(g.into()), + ConstKind::Error(g) => Err(Either::Right(g.into())), ConstKind::Param(_) | ConstKind::Infer(_) | ConstKind::Bound(_, _) | ConstKind::Placeholder(_) - | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span)), + | ConstKind::Expr(_) => Err(Either::Right(ErrorHandled::TooGeneric(span))), } } + /// Returns the evaluated constant + #[inline] + pub fn eval( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + span: Span, + ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> { + self.eval_valtree(tcx, param_env, span).map_err(|err| { + match err { + Either::Right(err) => err, + Either::Left(_bad_ty) => { + // This can happen when we run on ill-typed code. + let e = tcx.dcx().span_delayed_bug( + span, + "`ty::Const::eval` called on a non-valtree-compatible type", + ); + e.into() + } + } + }) + } + /// Normalizes the constant to a value or an error if possible. #[inline] pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { @@ -460,15 +527,15 @@ pub fn const_param_default<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { - let default_def_id = match tcx.hir_node_by_def_id(def_id) { + let default_ct = match tcx.hir_node_by_def_id(def_id) { hir::Node::GenericParam(hir::GenericParam { - kind: hir::GenericParamKind::Const { default: Some(ac), .. }, + kind: hir::GenericParamKind::Const { default: Some(ct), .. }, .. - }) => ac.def_id, + }) => ct, _ => span_bug!( tcx.def_span(def_id), "`const_param_default` expected a generic parameter with a constant" ), }; - ty::EarlyBinder::bind(Const::from_anon_const(tcx, default_def_id)) + ty::EarlyBinder::bind(Const::from_const_arg(tcx, default_ct, FeedConstTy::No)) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 25070e6b042..fd41668ae44 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1484,7 +1484,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> { - value.lift_to_tcx(self) + value.lift_to_interner(self) } /// Creates a type context. To use the context call `fn enter` which @@ -2087,7 +2087,7 @@ macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for $ty { type Lifted = $lifted; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { // Assert that the set has the right type. // Given an argument that has an interned type, the return type has the type of // the corresponding interner set. This won't actually return anything, we're @@ -2122,7 +2122,7 @@ macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { // Assert that the set has the right type. if false { let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; @@ -2160,7 +2160,7 @@ macro_rules! nop_slice_lift { ($ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for &'a [$ty] { type Lifted = &'tcx [$lifted]; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { if self.is_empty() { return Some(&[]); } diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index 5e256dc8d26..7b5ccae3568 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -67,7 +67,7 @@ fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () { #[inline] unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> { - &*(context as *const ImplicitCtxt<'a, 'tcx>) + unsafe { &*(context as *const ImplicitCtxt<'a, 'tcx>) } } /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`. diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 4bf22337991..f479b18c7c4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -271,6 +271,19 @@ pub fn suggest_constraining_type_params<'a>( } } + // in the scenario like impl has stricter requirements than trait, + // we should not suggest restrict bound on the impl, here we double check + // the whether the param already has the constraint by checking `def_id` + let bound_trait_defs: Vec<DefId> = generics + .bounds_for_param(param.def_id) + .flat_map(|bound| { + bound.bounds.iter().flat_map(|b| b.trait_ref().and_then(|t| t.trait_def_id())) + }) + .collect(); + + constraints + .retain(|(_, def_id)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def))); + if constraints.is_empty() { continue; } @@ -332,6 +345,7 @@ pub fn suggest_constraining_type_params<'a>( // -- // | // replace with: `T: Bar +` + if let Some((span, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) { suggest_restrict(span, true, open_paren_sp); continue; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 5ac3168196a..10919623de7 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -308,7 +308,7 @@ impl<'tcx> GenericArg<'tcx> { impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> { type Lifted = GenericArg<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { match self.unpack() { GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()), GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9a4562e9cfc..bd073cd891f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -86,7 +86,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, FeedConstTy, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index df080b2887b..57cd2dc73c4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1214,11 +1214,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() && alias_ty.def_id == def_id + && let generics = self.tcx().generics_of(fn_def_id) + // FIXME(return_type_notation): We only support lifetime params for now. + && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime)) { - let num_args = self.tcx().generics_of(fn_def_id).count(); + let num_args = generics.count(); write!(self, " {{ ")?; self.print_def_path(fn_def_id, &args[..num_args])?; - write!(self, "() }}")?; + write!(self, "(..) }}")?; } Ok(()) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index ebf0d7ed737..61c03922ac0 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -69,7 +69,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> { if inc_a != inc_b { todo!() } - Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) + Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) } } } @@ -81,7 +81,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate< a: Self, b: Self, ) -> RelateResult<'tcx, Self> { - let tcx = relation.tcx(); + let tcx = relation.cx(); // FIXME: this is wasteful, but want to do a perf run to see how slow it is. // We need to perform this deduplication as we sometimes generate duplicate projections diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index a9dca47ab43..7cdc0e32953 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -257,7 +257,6 @@ TrivialTypeTraversalImpls! { crate::ty::adjustment::PointerCoercion, ::rustc_span::Span, ::rustc_span::symbol::Ident, - ::rustc_errors::ErrorGuaranteed, ty::BoundVar, ty::ValTree<'tcx>, } @@ -284,7 +283,7 @@ TrivialTypeTraversalAndLiftImpls! { impl<'tcx, T: Lift<TyCtxt<'tcx>>> Lift<TyCtxt<'tcx>> for Option<T> { type Lifted = Option<T::Lifted>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { Some(match self { Some(x) => Some(tcx.lift(x)?), None => None, @@ -294,7 +293,7 @@ impl<'tcx, T: Lift<TyCtxt<'tcx>>> Lift<TyCtxt<'tcx>> for Option<T> { impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for Term<'a> { type Lifted = ty::Term<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { match self.unpack() { TermKind::Ty(ty) => tcx.lift(ty).map(Into::into), TermKind::Const(c) => tcx.lift(c).map(Into::into), @@ -443,13 +442,14 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> { pat.visit_with(visitor) } + ty::Error(guar) => guar.visit_with(visitor), + ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) - | ty::Error(_) | ty::Infer(_) | ty::Bound(..) | ty::Placeholder(..) @@ -602,6 +602,21 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { } } +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for rustc_span::ErrorGuaranteed { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + visitor.visit_error(*self) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for rustc_span::ErrorGuaranteed { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + _folder: &mut F, + ) -> Result<Self, F::Error> { + Ok(self) + } +} + impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, @@ -617,12 +632,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst { } } -impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { - fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - self.args.visit_with(visitor) - } -} - impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for TyAndLayout<'tcx, Ty<'tcx>> { fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { visitor.visit_ty(self.ty) diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 24e3e623ff2..a6dec66449e 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -607,7 +607,9 @@ impl<'a, V> ::std::ops::Index<HirId> for LocalTableInContext<'a, V> { type Output = V; fn index(&self, key: HirId) -> &V { - self.get(key).expect("LocalTableInContext: key not found") + self.get(key).unwrap_or_else(|| { + bug!("LocalTableInContext({:?}): key {:?} not found", self.hir_owner, key) + }) } } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 5d828d0093f..529e9cc2711 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start +either = "1.5.0" itertools = "0.12" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 0c277811fda..281f3ef6ef3 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -4,8 +4,6 @@ mir_build_already_borrowed = cannot borrow value as mutable because it is also b mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable -mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns - mir_build_bindings_with_variant_name = pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}` .suggestion = to match on the variant, qualify the path diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 5ccbd7c59cf..c608e5c63d8 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -71,11 +71,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); let si = (*scope, source_info); - unpack!( - block = this.in_scope(si, LintLevel::Inherited, |this| { + block = this + .in_scope(si, LintLevel::Inherited, |this| { this.stmt_expr(block, *expr, Some(*scope)) }) - ); + .into_block(); } StmtKind::Let { remainder_scope, @@ -166,14 +166,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let dummy_place = this.temp(this.tcx.types.never, else_block_span); let failure_entry = this.cfg.start_new_block(); let failure_block; - unpack!( - failure_block = this.ast_block( + failure_block = this + .ast_block( dummy_place, failure_entry, *else_block, this.source_info(else_block_span), ) - ); + .into_block(); this.cfg.terminate( failure_block, this.source_info(else_block_span), @@ -267,8 +267,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let initializer_span = this.thir[init].span; let scope = (*init_scope, source_info); - unpack!( - block = this.in_scope(scope, *lint_level, |this| { + block = this + .in_scope(scope, *lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -279,10 +279,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.expr_into_pattern(block, &pattern, init) // irrefutable pattern }) - ) + .into_block(); } else { let scope = (*init_scope, source_info); - unpack!(this.in_scope(scope, *lint_level, |this| { + let _: BlockAnd<()> = this.in_scope(scope, *lint_level, |this| { this.declare_bindings( visibility_scope, remainder_span, @@ -291,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, ); block.unit() - })); + }); debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_primary_bindings( @@ -333,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.block_context .push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span }); - unpack!(block = this.expr_into_dest(destination, block, expr_id)); + block = this.expr_into_dest(destination, block, expr_id).into_block(); let popped = this.block_context.pop(); assert!(popped.is_some_and(|bf| bf.is_tail_expr())); @@ -355,7 +355,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Finally, we pop all the let scopes before exiting out from the scope of block // itself. for scope in let_scope_stack.into_iter().rev() { - unpack!(block = this.pop_scope((*scope, source_info), block)); + block = this.pop_scope((*scope, source_info), block).into_block(); } // Restore the original source scope. this.source_scope = outer_source_scope; diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c5ee6db5999..40cfe563acc 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -185,13 +185,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: - unpack!( - block = this.expr_into_dest( - this.tcx.mk_place_deref(Place::from(result)), - block, - value, - ) - ); + block = this + .expr_into_dest(this.tcx.mk_place_deref(Place::from(result)), block, value) + .into_block(); block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { @@ -486,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: expr_span, user_ty: None, diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 607c7c3259c..82673582e79 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -112,7 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.expr_into_dest(temp_place, block, expr_id)); + block = this.expr_into_dest(temp_place, block, expr_id).into_block(); if let Some(temp_lifetime) = temp_lifetime { this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 942c69b5c0a..9cd958a21da 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -82,13 +82,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Lower the condition, and have it branch into `then` and `else` blocks. let (then_block, else_block) = this.in_if_then_scope(condition_scope, then_span, |this| { - let then_blk = unpack!(this.then_else_break( - block, - cond, - Some(condition_scope), // Temp scope - source_info, - DeclareLetBindings::Yes, // Declare `let` bindings normally - )); + let then_blk = this + .then_else_break( + block, + cond, + Some(condition_scope), // Temp scope + source_info, + DeclareLetBindings::Yes, // Declare `let` bindings normally + ) + .into_block(); // Lower the `then` arm into its block. this.expr_into_dest(destination, then_blk, then) @@ -105,7 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // If there is an `else` arm, lower it into `else_blk`. if let Some(else_expr) = else_opt { - unpack!(else_blk = this.expr_into_dest(destination, else_blk, else_expr)); + else_blk = this.expr_into_dest(destination, else_blk, else_expr).into_block(); } else { // There is no `else` arm, so we know both arms have type `()`. // Generate the implicit `else {}` by assigning unit. @@ -187,7 +189,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { const_: Const::from_bool(this.tcx, constant), }, ); - let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs)); + let mut rhs_block = + this.expr_into_dest(destination, continuation, rhs).into_block(); // Instrument the lowered RHS's value for condition coverage. // (Does nothing if condition coverage is not enabled.) this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block); @@ -230,7 +233,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // introduce a unit temporary as the destination for the loop body. let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. - let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body)); + let body_block_end = this.expr_into_dest(tmp, body_block, body).into_block(); this.cfg.goto(body_block_end, source_info, loop_block); // Loops are only exited by `break` expressions. @@ -462,7 +465,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { targets.push(target); let tmp = this.get_unit_temp(); - let target = unpack!(this.ast_block(tmp, target, block, source_info)); + let target = + this.ast_block(tmp, target, block, source_info).into_block(); this.cfg.terminate( target, source_info, @@ -502,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // These cases don't actually need a destination ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - unpack!(block = this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); this.cfg.push_assign_unit(block, source_info, destination, this.tcx); block.unit() } @@ -511,7 +515,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Break { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => { - unpack!(block = this.stmt_expr(block, expr_id, None)); + block = this.stmt_expr(block, expr_id, None).into_block(); // No assign, as these have type `!`. block.unit() } diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 88b76c46c90..8e13edb4c89 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -44,7 +44,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if lhs_expr.ty.needs_drop(this.tcx, this.param_env) { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); - unpack!(block = this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs)); + block = + this.build_drop_and_replace(block, lhs_expr.span, lhs, rhs).into_block(); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs new file mode 100644 index 00000000000..95fec154918 --- /dev/null +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -0,0 +1,258 @@ +use rustc_middle::mir::*; +use rustc_middle::thir::{self, *}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; + +use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::build::matches::{FlatPat, MatchPairTree, TestCase}; +use crate::build::Builder; + +impl<'a, 'tcx> Builder<'a, 'tcx> { + /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in + /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or + /// [`PatKind::Leaf`]. + /// + /// Used internally by [`MatchPairTree::for_pattern`]. + fn field_match_pairs<'pat>( + &mut self, + place: PlaceBuilder<'tcx>, + subpatterns: &'pat [FieldPat<'tcx>], + ) -> Vec<MatchPairTree<'pat, 'tcx>> { + subpatterns + .iter() + .map(|fieldpat| { + let place = + place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); + MatchPairTree::for_pattern(place, &fieldpat.pattern, self) + }) + .collect() + } + + /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an + /// array pattern or slice pattern, and adds those trees to `match_pairs`. + /// + /// Used internally by [`MatchPairTree::for_pattern`]. + fn prefix_slice_suffix<'pat>( + &mut self, + match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>, + place: &PlaceBuilder<'tcx>, + prefix: &'pat [Box<Pat<'tcx>>], + opt_slice: &'pat Option<Box<Pat<'tcx>>>, + suffix: &'pat [Box<Pat<'tcx>>], + ) { + let tcx = self.tcx; + let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { + match place_resolved.ty(&self.local_decls, tcx).ty.kind() { + ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), + _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), + } + } else { + ((prefix.len() + suffix.len()).try_into().unwrap(), false) + }; + + match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + let elem = + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) + })); + + if let Some(subslice_pat) = opt_slice { + let suffix_len = suffix.len() as u64; + let subslice = place.clone_project(PlaceElem::Subslice { + from: prefix.len() as u64, + to: if exact_size { min_length - suffix_len } else { suffix_len }, + from_end: !exact_size, + }); + match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self)); + } + + match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { + let end_offset = (idx + 1) as u64; + let elem = ProjectionElem::ConstantIndex { + offset: if exact_size { min_length - end_offset } else { end_offset }, + min_length, + from_end: !exact_size, + }; + let place = place.clone_project(elem); + MatchPairTree::for_pattern(place, subpattern, self) + })); + } +} + +impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { + /// Recursively builds a match pair tree for the given pattern and its + /// subpatterns. + pub(in crate::build) fn for_pattern( + mut place_builder: PlaceBuilder<'tcx>, + pattern: &'pat Pat<'tcx>, + cx: &mut Builder<'_, 'tcx>, + ) -> MatchPairTree<'pat, 'tcx> { + // Force the place type to the pattern's type. + // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? + if let Some(resolved) = place_builder.resolve_upvar(cx) { + place_builder = resolved; + } + + // Only add the OpaqueCast projection if the given place is an opaque type and the + // expected type from the pattern is not. + let may_need_cast = match place_builder.base() { + PlaceBase::Local(local) => { + let ty = + Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; + ty != pattern.ty && ty.has_opaque_types() + } + _ => true, + }; + if may_need_cast { + place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); + } + + let place = place_builder.try_to_place(cx); + let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; + let mut subpairs = Vec::new(); + let test_case = match pattern.kind { + PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + + PatKind::Or { ref pats } => TestCase::Or { + pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), + }, + + PatKind::Range(ref range) => { + if range.is_full_range(cx.tcx) == Some(true) { + default_irrefutable() + } else { + TestCase::Range(range) + } + } + + PatKind::Constant { value } => TestCase::Constant { value }, + + PatKind::AscribeUserType { + ascription: thir::Ascription { ref annotation, variance }, + ref subpattern, + .. + } => { + // Apply the type ascription to the value at `match_pair.place` + let ascription = place.map(|source| super::Ascription { + annotation: annotation.clone(), + source, + variance, + }); + + subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Binding { mode, var, ref subpattern, .. } => { + let binding = place.map(|source| super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + + if let Some(subpattern) = subpattern.as_ref() { + // this is the `x @ P` case; have to keep matching against `P` now + subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); + } + TestCase::Irrefutable { ascription: None, binding } + } + + PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + let ascription = place.map(|source| { + let span = pattern.span; + let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + cx.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), + ty: cx.infcx.next_ty_var(span), + }, + ) + .args; + let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + super::Ascription { annotation, source, variance: ty::Contravariant } + }); + + subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); + TestCase::Irrefutable { ascription, binding: None } + } + + PatKind::Array { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + default_irrefutable() + } + PatKind::Slice { ref prefix, ref slice, ref suffix } => { + cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + + if prefix.is_empty() && slice.is_some() && suffix.is_empty() { + default_irrefutable() + } else { + TestCase::Slice { + len: prefix.len() + suffix.len(), + variable_length: slice.is_some(), + } + } + } + + PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { + let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` + subpairs = cx.field_match_pairs(downcast_place, subpatterns); + + let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { + i == variant_index || { + (cx.tcx.features().exhaustive_patterns + || cx.tcx.features().min_exhaustive_patterns) + && !v + .inhabited_predicate(cx.tcx, adt_def) + .instantiate(cx.tcx, args) + .apply_ignore_module(cx.tcx, cx.param_env) + } + }) && (adt_def.did().is_local() + || !adt_def.is_variant_list_non_exhaustive()); + if irrefutable { + default_irrefutable() + } else { + TestCase::Variant { adt_def, variant_index } + } + } + + PatKind::Leaf { ref subpatterns } => { + subpairs = cx.field_match_pairs(place_builder, subpatterns); + default_irrefutable() + } + + PatKind::Deref { ref subpattern } => { + subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx)); + default_irrefutable() + } + + PatKind::DerefPattern { ref subpattern, mutability } => { + // Create a new temporary for each deref pattern. + // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? + let temp = cx.temp( + Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), + pattern.span, + ); + subpairs.push(MatchPairTree::for_pattern( + PlaceBuilder::from(temp).deref(), + subpattern, + cx, + )); + TestCase::Deref { temp, mutability } + } + + PatKind::Never => TestCase::Never, + }; + + MatchPairTree { place, test_case, subpairs, pattern } + } +} diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 841ef2719c9..b531a392efa 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -24,6 +24,7 @@ use tracing::{debug, instrument}; use util::visit_bindings; // helper functions, broken out by category: +mod match_pair; mod simplify; mod test; mod util; @@ -121,8 +122,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::LogicalOp { op: op @ LogicalOp::And, lhs, rhs } => { this.visit_coverage_branch_operation(op, expr_span); - let lhs_then_block = unpack!(this.then_else_break_inner(block, lhs, args)); - let rhs_then_block = unpack!(this.then_else_break_inner(lhs_then_block, rhs, args)); + let lhs_then_block = this.then_else_break_inner(block, lhs, args).into_block(); + let rhs_then_block = + this.then_else_break_inner(lhs_then_block, rhs, args).into_block(); rhs_then_block.unit() } ExprKind::LogicalOp { op: op @ LogicalOp::Or, lhs, rhs } => { @@ -139,14 +141,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ) }); - let rhs_success_block = unpack!(this.then_else_break_inner( - failure_block, - rhs, - ThenElseArgs { - declare_let_bindings: DeclareLetBindings::LetNotPermitted, - ..args - }, - )); + let rhs_success_block = this + .then_else_break_inner( + failure_block, + rhs, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, + ) + .into_block(); // Make the LHS and RHS success arms converge to a common block. // (We can't just make LHS goto RHS, because `rhs_success_block` @@ -451,7 +455,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>, ) -> BlockAnd<()> { - let arm_end_blocks: Vec<_> = arm_candidates + let arm_end_blocks: Vec<BasicBlock> = arm_candidates .into_iter() .map(|(arm, candidate)| { debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); @@ -502,6 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.expr_into_dest(destination, arm_block, arm.body) }) + .into_block() }) .collect(); @@ -512,10 +517,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)), ); for arm_block in arm_end_blocks { - let block = &self.cfg.basic_blocks[arm_block.0]; + let block = &self.cfg.basic_blocks[arm_block]; let last_location = block.statements.last().map(|s| s.source_info); - self.cfg.goto(unpack!(arm_block), last_location.unwrap_or(end_brace), end_block); + self.cfg.goto(arm_block, last_location.unwrap_or(end_brace), end_block); } self.source_scope = outer_source_info.scope; @@ -621,7 +626,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { OutsideGuard, ScheduleDrops::Yes, ); - unpack!(block = self.expr_into_dest(place, block, initializer_id)); + block = self.expr_into_dest(place, block, initializer_id).into_block(); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); @@ -660,7 +665,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { OutsideGuard, ScheduleDrops::Yes, ); - unpack!(block = self.expr_into_dest(place, block, initializer_id)); + block = self.expr_into_dest(place, block, initializer_id).into_block(); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -1027,15 +1032,15 @@ impl<'tcx> PatternExtraData<'tcx> { #[derive(Debug, Clone)] struct FlatPat<'pat, 'tcx> { /// To match the pattern, all of these must be satisfied... - // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: all the match pairs are recursively simplified. // Invariant: or-patterns must be sorted to the end. - match_pairs: Vec<MatchPair<'pat, 'tcx>>, + match_pairs: Vec<MatchPairTree<'pat, 'tcx>>, extra_data: PatternExtraData<'tcx>, } impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { - /// Creates a `FlatPat` containing a simplified [`MatchPair`] list/forest + /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest /// for the given pattern. fn new( place: PlaceBuilder<'tcx>, @@ -1043,7 +1048,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { cx: &mut Builder<'_, 'tcx>, ) -> Self { // First, recursively build a tree of match pairs for the given pattern. - let mut match_pairs = vec![MatchPair::new(place, pattern, cx)]; + let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)]; let mut extra_data = PatternExtraData { span: pattern.span, bindings: Vec::new(), @@ -1060,9 +1065,9 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { #[derive(Debug)] struct Candidate<'pat, 'tcx> { /// For the candidate to match, all of these must be satisfied... - // Invariant: all the `MatchPair`s are recursively simplified. + // Invariant: all the match pairs are recursively simplified. // Invariant: or-patterns must be sorted at the end. - match_pairs: Vec<MatchPair<'pat, 'tcx>>, + match_pairs: Vec<MatchPairTree<'pat, 'tcx>>, /// ...and if this is non-empty, one of these subcandidates also has to match... // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate @@ -1121,7 +1126,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { /// Returns whether the first match pair of this candidate is an or-pattern. fn starts_with_or_pattern(&self) -> bool { - matches!(&*self.match_pairs, [MatchPair { test_case: TestCase::Or { .. }, .. }, ..]) + matches!(&*self.match_pairs, [MatchPairTree { test_case: TestCase::Or { .. }, .. }, ..]) } /// Visit the leaf candidates (those with no subcandidates) contained in @@ -1195,17 +1200,27 @@ impl<'pat, 'tcx> TestCase<'pat, 'tcx> { } } +/// Node in a tree of "match pairs", where each pair consists of a place to be +/// tested, and a test to perform on that place. +/// +/// Each node also has a list of subpairs (possibly empty) that must also match, +/// and a reference to the THIR pattern it represents. #[derive(Debug, Clone)] -pub(crate) struct MatchPair<'pat, 'tcx> { +pub(crate) struct MatchPairTree<'pat, 'tcx> { /// This place... - // This can be `None` if it referred to a non-captured place in a closure. - // Invariant: place.is_none() => test_case is Irrefutable - // In other words this must be `Some(_)` after simplification. + /// + /// --- + /// This can be `None` if it referred to a non-captured place in a closure. + /// + /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. + /// Therefore this must be `Some(_)` after simplification. place: Option<Place<'tcx>>, /// ... must pass this test... - // Invariant: after creation and simplification in `Candidate::new()`, this must not be - // `Irrefutable`. + /// + /// --- + /// Invariant: after creation and simplification in [`FlatPat::new`], + /// this must not be [`TestCase::Irrefutable`]. test_case: TestCase<'pat, 'tcx>, /// ... and these subpairs must match. @@ -1536,10 +1551,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { start_block: BasicBlock, candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>], ) -> BlockAnd<&'b mut [&'c mut Candidate<'pat, 'tcx>]> { - // We can't expand or-patterns freely. The rule is: if the candidate has an - // or-pattern as its only remaining match pair, we can expand it freely. If it has - // other match pairs, we can expand it but we can't process more candidates after - // it. + // We can't expand or-patterns freely. The rule is: + // - If a candidate doesn't start with an or-pattern, we include it in + // the expansion list as-is (i.e. it "expands" to itself). + // - If a candidate has an or-pattern as its only remaining match pair, + // we can expand it. + // - If it starts with an or-pattern but also has other match pairs, + // we can expand it, but we can't process more candidates after it. // // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it @@ -1556,17 +1574,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // } // ``` // - // We therefore split the `candidates` slice in two, expand or-patterns in the first half, + // We therefore split the `candidates` slice in two, expand or-patterns in the first part, // and process the rest separately. - let mut expand_until = 0; - for (i, candidate) in candidates.iter().enumerate() { - expand_until = i + 1; - if candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() { - // The candidate has an or-pattern as well as more match pairs: we must - // split the candidates list here. - break; - } - } + let expand_until = candidates + .iter() + .position(|candidate| { + // If a candidate starts with an or-pattern and has more match pairs, + // we can expand it, but we must stop expanding _after_ it. + candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern() + }) + .map(|pos| pos + 1) // Stop _after_ the found candidate + .unwrap_or(candidates.len()); // Otherwise, include all candidates let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until); // Expand one level of or-patterns for each candidate in `candidates_to_expand`. @@ -1581,6 +1599,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expanded_candidates.push(subcandidate); } } else { + // A candidate that doesn't start with an or-pattern has nothing to + // expand, so it is included in the post-expansion list as-is. expanded_candidates.push(candidate); } } @@ -1609,7 +1629,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn create_or_subcandidates<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, - match_pair: MatchPair<'pat, 'tcx>, + match_pair: MatchPairTree<'pat, 'tcx>, ) { let TestCase::Or { pats } = match_pair.test_case else { bug!() }; debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats); @@ -1793,8 +1813,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// [`Range`]: TestKind::Range fn pick_test(&mut self, candidates: &[&mut Candidate<'_, 'tcx>]) -> (Place<'tcx>, Test<'tcx>) { // Extract the match-pair from the highest priority candidate - let match_pair = &candidates.first().unwrap().match_pairs[0]; - let test = self.test(match_pair); + let match_pair = &candidates[0].match_pairs[0]; + let test = self.pick_test_for_match_pair(match_pair); // Unwrap is ok after simplification. let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 543301c71a0..20310f60821 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -12,7 +12,7 @@ //! sort of test: for example, testing which variant an enum is, or //! testing a value against a constant. -use crate::build::matches::{MatchPair, PatternExtraData, TestCase}; +use crate::build::matches::{MatchPairTree, PatternExtraData, TestCase}; use crate::build::Builder; use tracing::{debug, instrument}; @@ -24,7 +24,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn simplify_match_pairs<'pat>( &mut self, - match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>, + match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>, extra_data: &mut PatternExtraData<'tcx>, ) { // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index d29874a5ad4..8a02ea1a06d 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -5,7 +5,7 @@ // identify what tests are needed, perform the tests, and then filter // the candidates based on the result. -use crate::build::matches::{Candidate, MatchPair, Test, TestBranch, TestCase, TestKind}; +use crate::build::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; @@ -26,7 +26,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// /// It is a bug to call this with a not-fully-simplified pattern. - pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { + pub(super) fn pick_test_for_match_pair<'pat>( + &mut self, + match_pair: &MatchPairTree<'pat, 'tcx>, + ) -> Test<'tcx> { let kind = match match_pair.test_case { TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def }, @@ -144,7 +147,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && tcx.is_lang_item(def.did(), LangItem::String) { if !tcx.features().string_deref_patterns { - bug!( + span_bug!( + test.span, "matching on `String` went through without enabling string_deref_patterns" ); } @@ -432,40 +436,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - match *ty.kind() { - ty::Ref(_, deref_ty, _) => ty = deref_ty, - _ => { - // non_scalar_compare called on non-reference type - let temp = self.temp(ty, source_info.span); - self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect)); - let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty); - let ref_temp = self.temp(ref_ty, source_info.span); - - self.cfg.push_assign( - block, - source_info, - ref_temp, - Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp), - ); - expect = Operand::Move(ref_temp); - - let ref_temp = self.temp(ref_ty, source_info.span); - self.cfg.push_assign( - block, - source_info, - ref_temp, - Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val), - ); - val = ref_temp; + // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping + // reference: we can only compare two `&T`, and then compare_ty will be `T`. + // Make sure that we do *not* call any user-defined code here. + // The only types that can end up here are string and byte literals, + // which have their comparison defined in `core`. + // (Interestingly this means that exhaustiveness analysis relies, for soundness, + // on the `PartialEq` impls for `str` and `[u8]` to b correct!) + let compare_ty = match *ty.kind() { + ty::Ref(_, deref_ty, _) + if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 => + { + deref_ty } - } + _ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty), + }; let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); let method = trait_method( self.tcx, eq_def_id, sym::eq, - self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [ty, ty]), + self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]), ); let bool_ty = self.tcx.types.bool; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 3bec154e1df..8fe8069b345 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,78 +1,15 @@ use std::marker::PhantomData; -use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; +use crate::build::expr::as_place::PlaceBase; +use crate::build::matches::{Binding, Candidate, FlatPat, MatchPairTree, TestCase}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; impl<'a, 'tcx> Builder<'a, 'tcx> { - pub(crate) fn field_match_pairs<'pat>( - &mut self, - place: PlaceBuilder<'tcx>, - subpatterns: &'pat [FieldPat<'tcx>], - ) -> Vec<MatchPair<'pat, 'tcx>> { - subpatterns - .iter() - .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPair::new(place, &fieldpat.pattern, self) - }) - .collect() - } - - pub(crate) fn prefix_slice_suffix<'pat>( - &mut self, - match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>, - place: &PlaceBuilder<'tcx>, - prefix: &'pat [Box<Pat<'tcx>>], - opt_slice: &'pat Option<Box<Pat<'tcx>>>, - suffix: &'pat [Box<Pat<'tcx>>], - ) { - let tcx = self.tcx; - let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) { - match place_resolved.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_target_usize(tcx, self.param_env), true), - _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), - } - } else { - ((prefix.len() + suffix.len()).try_into().unwrap(), false) - }; - - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPair::new(place.clone_project(elem), subpattern, self) - })); - - if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u64; - let subslice = place.clone_project(PlaceElem::Subslice { - from: prefix.len() as u64, - to: if exact_size { min_length - suffix_len } else { suffix_len }, - from_end: !exact_size, - }); - match_pairs.push(MatchPair::new(subslice, subslice_pat, self)); - } - - match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u64; - let elem = ProjectionElem::ConstantIndex { - offset: if exact_size { min_length - end_offset } else { end_offset }, - min_length, - from_end: !exact_size, - }; - let place = place.clone_project(elem); - MatchPair::new(place, subpattern, self) - })); - } - /// Creates a false edge to `imaginary_target` and a real edge to /// real_target. If `imaginary_target` is none, or is the same as the real /// target, a Goto is generated instead to simplify the generated MIR. @@ -96,181 +33,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { - /// Recursively builds a `MatchPair` tree for the given pattern and its - /// subpatterns. - pub(in crate::build) fn new( - mut place_builder: PlaceBuilder<'tcx>, - pattern: &'pat Pat<'tcx>, - cx: &mut Builder<'_, 'tcx>, - ) -> MatchPair<'pat, 'tcx> { - // Force the place type to the pattern's type. - // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? - if let Some(resolved) = place_builder.resolve_upvar(cx) { - place_builder = resolved; - } - - // Only add the OpaqueCast projection if the given place is an opaque type and the - // expected type from the pattern is not. - let may_need_cast = match place_builder.base() { - PlaceBase::Local(local) => { - let ty = - Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty; - ty != pattern.ty && ty.has_opaque_types() - } - _ => true, - }; - if may_need_cast { - place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); - } - - let place = place_builder.try_to_place(cx); - let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; - let mut subpairs = Vec::new(); - let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => default_irrefutable(), - - PatKind::Or { ref pats } => TestCase::Or { - pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }, - - PatKind::Range(ref range) => { - if range.is_full_range(cx.tcx) == Some(true) { - default_irrefutable() - } else { - TestCase::Range(range) - } - } - - PatKind::Constant { value } => TestCase::Constant { value }, - - PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, - ref subpattern, - .. - } => { - // Apply the type ascription to the value at `match_pair.place` - let ascription = place.map(|source| super::Ascription { - annotation: annotation.clone(), - source, - variance, - }); - - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Binding { mode, var, ref subpattern, .. } => { - let binding = place.map(|source| super::Binding { - span: pattern.span, - source, - var_id: var, - binding_mode: mode, - }); - - if let Some(subpattern) = subpattern.as_ref() { - // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPair::new(place_builder, subpattern, cx)); - } - TestCase::Irrefutable { ascription: None, binding } - } - - PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { - // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.map(|source| { - let span = pattern.span; - let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); - let args = ty::InlineConstArgs::new( - cx.tcx, - ty::InlineConstArgsParts { - parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx.infcx.next_ty_var(span), - }, - ) - .args; - let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), - ty::UserArgs { args, user_self_ty: None }, - )); - let annotation = ty::CanonicalUserTypeAnnotation { - inferred_ty: pattern.ty, - span, - user_ty: Box::new(user_ty), - }; - super::Ascription { annotation, source, variance: ty::Contravariant } - }); - - subpairs.push(MatchPair::new(place_builder, pattern, cx)); - TestCase::Irrefutable { ascription, binding: None } - } - - PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - default_irrefutable() - } - PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - - if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - default_irrefutable() - } else { - TestCase::Slice { - len: prefix.len() + suffix.len(), - variable_length: slice.is_some(), - } - } - } - - PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { - let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - subpairs = cx.field_match_pairs(downcast_place, subpatterns); - - let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { - i == variant_index || { - (cx.tcx.features().exhaustive_patterns - || cx.tcx.features().min_exhaustive_patterns) - && !v - .inhabited_predicate(cx.tcx, adt_def) - .instantiate(cx.tcx, args) - .apply_ignore_module(cx.tcx, cx.param_env) - } - }) && (adt_def.did().is_local() - || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - default_irrefutable() - } else { - TestCase::Variant { adt_def, variant_index } - } - } - - PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place_builder, subpatterns); - default_irrefutable() - } - - PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPair::new(place_builder.deref(), subpattern, cx)); - default_irrefutable() - } - - PatKind::DerefPattern { ref subpattern, mutability } => { - // Create a new temporary for each deref pattern. - // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls? - let temp = cx.temp( - Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), - pattern.span, - ); - subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); - TestCase::Deref { temp, mutability } - } - - PatKind::Never => TestCase::Never, - }; - - MatchPair { place, test_case, subpairs, pattern } - } -} - /// Determine the set of places that have to be stable across match guards. /// /// Returns a list of places that need a fake borrow along with a local to store it. @@ -390,7 +152,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } } - fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { if let TestCase::Or { pats, .. } = &match_pair.test_case { for flat_pat in pats.iter() { self.visit_flat_pat(flat_pat) @@ -498,7 +260,7 @@ where } } - fn visit_match_pair(&mut self, match_pair: &MatchPair<'_, 'tcx>) { + fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) { if let TestCase::Or { pats, .. } = &match_pair.test_case { // All the or-alternatives should bind the same locals, so we only visit the first one. self.visit_flat_pat(&pats[0]) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0f9746cb719..2793a7d8736 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -403,6 +403,15 @@ enum NeedsTemporary { #[must_use = "if you don't use one of these results, you're leaving a dangling edge"] struct BlockAnd<T>(BasicBlock, T); +impl BlockAnd<()> { + /// Unpacks `BlockAnd<()>` into a [`BasicBlock`]. + #[must_use] + fn into_block(self) -> BasicBlock { + let Self(block, ()) = self; + block + } +} + trait BlockAndExtension { fn and<T>(self, v: T) -> BlockAnd<T>; fn unit(self) -> BlockAnd<()>; @@ -426,11 +435,6 @@ macro_rules! unpack { $x = b; v }}; - - ($c:expr) => {{ - let BlockAnd(b, ()) = $c; - b - }}; } /////////////////////////////////////////////////////////////////////////// @@ -516,21 +520,22 @@ fn construct_fn<'tcx>( region::Scope { id: body.id().hir_id.local_id, data: region::ScopeData::Arguments }; let source_info = builder.source_info(span); let call_site_s = (call_site_scope, source_info); - unpack!(builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { + let _: BlockAnd<()> = builder.in_scope(call_site_s, LintLevel::Inherited, |builder| { let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span_with_body.shrink_to_hi(); - let return_block = - unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { + let return_block = builder + .in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body(START_BLOCK, arguments, arg_scope, expr) })) - })); + }) + .into_block(); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); builder.build_drop_trees(); return_block.unit() - })); + }); let mut body = builder.finish(); @@ -579,7 +584,7 @@ fn construct_const<'a, 'tcx>( Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None); let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, expr)); + block = builder.expr_into_dest(Place::return_place(), block, expr).into_block(); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -961,7 +966,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some((Some(&place), span)), ); let place_builder = PlaceBuilder::from(local); - unpack!(block = self.place_into_pattern(block, pat, place_builder, false)); + block = self.place_into_pattern(block, pat, place_builder, false).into_block(); } } self.source_scope = original_source_scope; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 948301e2ece..b630c74a202 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -510,12 +510,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target = self.cfg.start_new_block(); let source_info = self.source_info(span); self.cfg.terminate( - unpack!(normal_block), + normal_block.into_block(), source_info, TerminatorKind::Goto { target }, ); self.cfg.terminate( - unpack!(exit_block), + exit_block.into_block(), source_info, TerminatorKind::Goto { target }, ); @@ -552,14 +552,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = IfThenScope { region_scope, else_drops: DropTree::new() }; let previous_scope = mem::replace(&mut self.scopes.if_then_scope, Some(scope)); - let then_block = unpack!(f(self)); + let then_block = f(self).into_block(); let if_then_scope = mem::replace(&mut self.scopes.if_then_scope, previous_scope).unwrap(); assert!(if_then_scope.region_scope == region_scope); - let else_block = self - .build_exit_tree(if_then_scope.else_drops, region_scope, span, None) - .map_or_else(|| self.cfg.start_new_block(), |else_block_and| unpack!(else_block_and)); + let else_block = + self.build_exit_tree(if_then_scope.else_drops, region_scope, span, None).map_or_else( + || self.cfg.start_new_block(), + |else_block_and| else_block_and.into_block(), + ); (then_block, else_block) } @@ -585,7 +587,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.push_scope(region_scope); let mut block; let rv = unpack!(block = f(self)); - unpack!(block = self.pop_scope(region_scope, block)); + block = self.pop_scope(region_scope, block).into_block(); self.source_scope = source_scope; debug!(?block); block.and(rv) @@ -657,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(destination), Some(value)) => { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.expr_into_dest(destination, block, value)); + block = self.expr_into_dest(destination, block, value).into_block(); self.block_context.pop(); } (Some(destination), None) => { @@ -838,7 +840,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX }; let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes"); - unpack!(build_scope_drops( + build_scope_drops( &mut self.cfg, &mut self.scopes.unwind_drops, scope, @@ -846,7 +848,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unwind_to, is_coroutine && needs_cleanup, self.arg_count, - )) + ) + .into_block() } /// Possibly creates a new source scope if `current_root` and `parent_root` diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7c73d8a6d47..f6f443b64a6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -567,13 +567,6 @@ pub(crate) struct StaticInPattern { } #[derive(Diagnostic)] -#[diag(mir_build_assoc_const_in_pattern, code = E0158)] -pub(crate) struct AssocConstInPattern { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] #[diag(mir_build_const_param_in_pattern, code = E0158)] pub(crate) struct ConstParamInPattern { #[primary_span] @@ -597,7 +590,7 @@ pub(crate) struct UnreachablePattern { } #[derive(Diagnostic)] -#[diag(mir_build_const_pattern_depends_on_generic_parameter)] +#[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)] pub(crate) struct ConstPatternDependsOnGenericParameter { #[primary_span] pub(crate) span: Span, 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 5745dc0969c..0d54f332585 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 @@ -1,42 +1,45 @@ +use either::Either; use rustc_apfloat::Float; use rustc_hir as hir; use rustc_index::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_middle::mir; -use rustc_middle::span_bug; +use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir::{FieldPat, Pat, PatKind}; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt, ValTree}; -use rustc_span::{ErrorGuaranteed, Span}; +use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause}; +use rustc_trait_selection::traits::ObligationCause; use tracing::{debug, instrument, trace}; -use std::cell::Cell; - use super::PatCtxt; use crate::errors::{ - InvalidPattern, NaNPattern, PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, - UnsizedPattern, + ConstPatternDependsOnGenericParameter, CouldNotEvalConstPattern, InvalidPattern, NaNPattern, + PointerPattern, TypeNotPartialEq, TypeNotStructural, UnionPattern, UnsizedPattern, }; impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - /// Converts an evaluated constant to a pattern (if possible). + /// Converts a constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). /// - /// `cv` must be a valtree or a `mir::ConstValue`. + /// Only type system constants are supported, as we are using valtrees + /// as an intermediate step. Unfortunately those don't carry a type + /// so we have to carry one ourselves. #[instrument(level = "debug", skip(self), ret)] pub(super) fn const_to_pat( &self, - cv: mir::Const<'tcx>, + c: ty::Const<'tcx>, + ty: Ty<'tcx>, id: hir::HirId, span: Span, ) -> Box<Pat<'tcx>> { let infcx = self.tcx.infer_ctxt().build(); let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv) + convert.to_pat(c, ty) } } @@ -45,23 +48,12 @@ struct ConstToPat<'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, - // This tracks if we emitted some hard error for a given const value, so that - // we will not subsequently issue an irrelevant lint for the same const - // value. - saw_const_match_error: Cell<Option<ErrorGuaranteed>>, - // inference context used for checking `T: Structural` bounds. infcx: InferCtxt<'tcx>, treat_byte_string_as_slice: bool, } -/// This error type signals that we encountered a non-struct-eq situation. -/// We will fall back to calling `PartialEq::eq` on such patterns, -/// and exhaustiveness checking will consider them as matching nothing. -#[derive(Debug)] -struct FallbackToOpaqueConst; - impl<'tcx> ConstToPat<'tcx> { fn new( pat_ctxt: &PatCtxt<'_, 'tcx>, @@ -75,7 +67,6 @@ impl<'tcx> ConstToPat<'tcx> { span, infcx, param_env: pat_ctxt.param_env, - saw_const_match_error: Cell::new(None), treat_byte_string_as_slice: pat_ctxt .typeck_results .treat_byte_string_as_slice @@ -91,116 +82,55 @@ impl<'tcx> ConstToPat<'tcx> { ty.is_structural_eq_shallow(self.infcx.tcx) } - fn to_pat(&mut self, cv: mir::Const<'tcx>) -> Box<Pat<'tcx>> { + fn to_pat(&mut self, c: ty::Const<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { trace!(self.treat_byte_string_as_slice); - // This method is just a wrapper handling a validity check; the heavy lifting is - // performed by the recursive `recur` method, which is not meant to be - // invoked except by this method. - // - // once indirect_structural_match is a full fledged error, this - // level of indirection can be eliminated + let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind }); - let have_valtree = - matches!(cv, mir::Const::Ty(_, c) if matches!(c.kind(), ty::ConstKind::Value(_, _))); - let inlined_const_as_pat = match cv { - mir::Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Param(_) - | ty::ConstKind::Infer(_) - | ty::ConstKind::Bound(_, _) - | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Error(_) - | ty::ConstKind::Expr(_) => { - span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind()) - } - ty::ConstKind::Value(ty, valtree) => { - self.recur(valtree, ty).unwrap_or_else(|_: FallbackToOpaqueConst| { - Box::new(Pat { - span: self.span, - ty: cv.ty(), - kind: PatKind::Constant { value: cv }, - }) - }) - } - }, - mir::Const::Unevaluated(_, _) => { - span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}") + // Get a valtree. If that fails, this const is definitely not valid for use as a pattern. + let valtree = match c.eval_valtree(self.tcx(), self.param_env, self.span) { + Ok((_, valtree)) => valtree, + Err(Either::Right(e)) => { + let err = match e { + ErrorHandled::Reported(..) => { + // Let's tell the use where this failing const occurs. + self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span }) + } + ErrorHandled::TooGeneric(_) => self + .tcx() + .dcx() + .emit_err(ConstPatternDependsOnGenericParameter { span: self.span }), + }; + return pat_from_kind(PatKind::Error(err)); + } + Err(Either::Left(bad_ty)) => { + // The pattern cannot be turned into a valtree. + let e = match bad_ty.kind() { + ty::Adt(def, ..) => { + assert!(def.is_union()); + self.tcx().dcx().emit_err(UnionPattern { span: self.span }) + } + ty::FnPtr(..) | ty::RawPtr(..) => { + self.tcx().dcx().emit_err(PointerPattern { span: self.span }) + } + _ => self + .tcx() + .dcx() + .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }), + }; + return pat_from_kind(PatKind::Error(e)); } - mir::Const::Val(_, _) => Box::new(Pat { - span: self.span, - ty: cv.ty(), - kind: PatKind::Constant { value: cv }, - }), }; - if self.saw_const_match_error.get().is_none() { - // If we were able to successfully convert the const to some pat (possibly with some - // lints, but no errors), double-check that all types in the const implement - // `PartialEq`. Even if we have a valtree, we may have found something - // in there with non-structural-equality, meaning we match using `PartialEq` - // and we hence have to check if that impl exists. - // This is all messy but not worth cleaning up: at some point we'll emit - // a hard error when we don't have a valtree or when we find something in - // the valtree that is not structural; then this can all be made a lot simpler. - - let structural = traits::search_for_structural_match_violation(self.tcx(), cv.ty()); - debug!( - "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", - cv.ty(), - structural - ); - - if let Some(non_sm_ty) = structural { - if !self.type_has_partial_eq_impl(cv.ty()) { - // This is reachable and important even if we have a valtree: there might be - // non-structural things in a valtree, in which case we fall back to `PartialEq` - // comparison, in which case we better make sure the trait is implemented for - // each inner type (and not just for the surrounding type). - let e = if let ty::Adt(def, ..) = non_sm_ty.kind() { - if def.is_union() { - let err = UnionPattern { span: self.span }; - self.tcx().dcx().emit_err(err) - } else { - // fatal avoids ICE from resolution of nonexistent method (rare case). - self.tcx() - .dcx() - .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty }) - } - } else { - let err = InvalidPattern { span: self.span, non_sm_ty }; - self.tcx().dcx().emit_err(err) - }; - // All branches above emitted an error. Don't print any more lints. - // We errored. Signal that in the pattern, so that follow up errors can be silenced. - let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else if !have_valtree { - // Not being structural prevented us from constructing a valtree, - // so this is definitely a case we want to reject. - let err = TypeNotStructural { span: self.span, non_sm_ty }; - let e = self.tcx().dcx().emit_err(err); - let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } else { - // This could be a violation in an inactive enum variant. - // Since we have a valtree, we trust that we have traversed the full valtree and - // complained about structural match violations there, so we don't - // have to check anything any more. - } - } else if !have_valtree { - // The only way valtree construction can fail without the structural match - // checker finding a violation is if there is a pointer somewhere. - let e = self.tcx().dcx().emit_err(PointerPattern { span: self.span }); - let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); - } + // Convert the valtree to a const. + let inlined_const_as_pat = self.valtree_to_pat(valtree, ty); + if !inlined_const_as_pat.references_error() { // Always check for `PartialEq` if we had no other errors yet. - if !self.type_has_partial_eq_impl(cv.ty()) { - let err = TypeNotPartialEq { span: self.span, non_peq_ty: cv.ty() }; + if !self.type_has_partial_eq_impl(ty) { + let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty }; let e = self.tcx().dcx().emit_err(err); let kind = PatKind::Error(e); - return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); + return Box::new(Pat { span: self.span, ty: ty, kind }); } } @@ -243,40 +173,31 @@ impl<'tcx> ConstToPat<'tcx> { fn field_pats( &self, vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>, - ) -> Result<Vec<FieldPat<'tcx>>, FallbackToOpaqueConst> { + ) -> Vec<FieldPat<'tcx>> { vals.enumerate() .map(|(idx, (val, ty))| { let field = FieldIdx::new(idx); // Patterns can only use monomorphic types. let ty = self.tcx().normalize_erasing_regions(self.param_env, ty); - Ok(FieldPat { field, pattern: self.recur(val, ty)? }) + FieldPat { field, pattern: self.valtree_to_pat(val, ty) } }) .collect() } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). #[instrument(skip(self), level = "debug")] - fn recur( - &self, - cv: ValTree<'tcx>, - ty: Ty<'tcx>, - ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> { + fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { let span = self.span; let tcx = self.tcx(); let param_env = self.param_env; let kind = match ty.kind() { - ty::FnDef(..) => { - let e = tcx.dcx().emit_err(InvalidPattern { span, non_sm_ty: ty }); - self.saw_const_match_error.set(Some(e)); - // We errored. Signal that in the pattern, so that follow up errors can be silenced. - PatKind::Error(e) - } ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { + // Extremely important check for all ADTs! Make sure they opted-in to be used in + // patterns. debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); let err = TypeNotStructural { span, non_sm_ty: ty }; let e = tcx.dcx().emit_err(err); - self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Error(e) } @@ -294,13 +215,9 @@ impl<'tcx> ConstToPat<'tcx> { .iter() .map(|field| field.ty(self.tcx(), args)), ), - )?, + ), } } - ty::Tuple(fields) => PatKind::Leaf { - subpatterns: self - .field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?, - }, ty::Adt(def, args) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { @@ -311,15 +228,18 @@ impl<'tcx> ConstToPat<'tcx> { .iter() .map(|field| field.ty(self.tcx(), args)), ), - )?, + ), } } + ty::Tuple(fields) => PatKind::Leaf { + subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter())), + }, ty::Slice(elem_ty) => PatKind::Slice { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty)) - .collect::<Result<_, _>>()?, + .map(|val| self.valtree_to_pat(*val, *elem_ty)) + .collect(), slice: None, suffix: Box::new([]), }, @@ -327,8 +247,8 @@ impl<'tcx> ConstToPat<'tcx> { prefix: cv .unwrap_branch() .iter() - .map(|val| self.recur(*val, *elem_ty)) - .collect::<Result<_, _>>()?, + .map(|val| self.valtree_to_pat(*val, *elem_ty)) + .collect(), slice: None, suffix: Box::new([]), }, @@ -361,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> { _ => *pointee_ty, }; // References have the same valtree representation as their pointee. - let subpattern = self.recur(cv, pointee_ty)?; + let subpattern = self.valtree_to_pat(cv, pointee_ty); PatKind::Deref { subpattern } } } @@ -378,8 +298,7 @@ impl<'tcx> ConstToPat<'tcx> { // NaNs are not ever equal to anything so they make no sense as patterns. // Also see <https://github.com/rust-lang/rfcs/pull/3535>. let e = tcx.dcx().emit_err(NaNPattern { span }); - self.saw_const_match_error.set(Some(e)); - return Err(FallbackToOpaqueConst); + PatKind::Error(e) } else { PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), @@ -399,12 +318,11 @@ impl<'tcx> ConstToPat<'tcx> { _ => { let err = InvalidPattern { span, non_sm_ty: ty }; let e = tcx.dcx().emit_err(err); - self.saw_const_match_error.set(Some(e)); // We errored. Signal that in the pattern, so that follow up errors can be silenced. PatKind::Error(e) } }; - Ok(Box::new(Pat { span, ty, kind })) + Box::new(Pat { span, ty, kind }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index fd778ef78a3..622651800f4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -14,8 +14,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd}; use rustc_index::Idx; use rustc_lint as lint; -use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput}; -use rustc_middle::mir::{self, Const}; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::thir::{ Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; @@ -549,89 +548,36 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), }; - // Use `Reveal::All` here because patterns are always monomorphic even if their function - // isn't. - let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx); - // N.B. There is no guarantee that args collected in typeck results are fully normalized, - // so they need to be normalized in order to pass to `Instance::resolve`, which will ICE - // if given unnormalized types. - let args = self - .tcx - .normalize_erasing_regions(param_env_reveal_all, self.typeck_results.node_args(id)); - let instance = match ty::Instance::try_resolve(self.tcx, param_env_reveal_all, def_id, args) - { - Ok(Some(i)) => i, - Ok(None) => { - // It should be assoc consts if there's no error but we cannot resolve it. - debug_assert!(is_associated_const); - - let e = self.tcx.dcx().emit_err(AssocConstInPattern { span }); - return pat_from_kind(PatKind::Error(e)); - } - - Err(_) => { - let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span }); - return pat_from_kind(PatKind::Error(e)); - } - }; + let args = self.typeck_results.node_args(id); + let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); + let pattern = self.const_to_pat(c, ty, id, span); - let cid = GlobalId { instance, promoted: None }; - // Prefer valtrees over opaque constants. - let const_value = self - .tcx - .const_eval_global_id_for_typeck(param_env_reveal_all, cid, span) - .map(|val| match val { - Some(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), - None => mir::Const::Val( - self.tcx - .const_eval_global_id(param_env_reveal_all, cid, span) - .expect("const_eval_global_id_for_typeck should have already failed"), - ty, - ), - }); - - match const_value { - Ok(const_) => { - let pattern = self.const_to_pat(const_, id, span); - - if !is_associated_const { - return pattern; - } + if !is_associated_const { + return pattern; + } - let user_provided_types = self.typeck_results().user_provided_types(); - if let Some(&user_ty) = user_provided_types.get(id) { - let annotation = CanonicalUserTypeAnnotation { - user_ty: Box::new(user_ty), - span, - inferred_ty: self.typeck_results().node_type(id), - }; - Box::new(Pat { - span, - kind: PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - annotation, - // Note that use `Contravariant` here. See the - // `variance` field documentation for details. - variance: ty::Contravariant, - }, - }, - ty: const_.ty(), - }) - } else { - pattern - } - } - Err(ErrorHandled::TooGeneric(_)) => { - // While `Reported | Linted` cases will have diagnostics emitted already - // it is not true for TooGeneric case, so we need to give user more information. - let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span }); - pat_from_kind(PatKind::Error(e)) - } - Err(_) => { - let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span }); - pat_from_kind(PatKind::Error(e)) - } + let user_provided_types = self.typeck_results().user_provided_types(); + if let Some(&user_ty) = user_provided_types.get(id) { + let annotation = CanonicalUserTypeAnnotation { + user_ty: Box::new(user_ty), + span, + inferred_ty: self.typeck_results().node_type(id), + }; + Box::new(Pat { + span, + kind: PatKind::AscribeUserType { + subpattern: pattern, + ascription: Ascription { + annotation, + // Note that use `Contravariant` here. See the + // `variance` field documentation for details. + variance: ty::Contravariant, + }, + }, + ty, + }) + } else { + pattern } } @@ -662,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(Const::Ty(ty, c), id, span).kind, + Ok(c) => return self.const_to_pat(c, ty, id, span).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -675,33 +621,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { tcx.erase_regions(ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id)); let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args; - let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None }; debug_assert!(!args.has_free_regions()); let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; - // First try using a valtree in order to destructure the constant into a pattern. - // FIXME: replace "try to do a thing, then fall back to another thing" - // but something more principled, like a trait query checking whether this can be turned into a valtree. - if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span) - { - let subpattern = self.const_to_pat( - Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), - id, - span, - ); - PatKind::InlineConstant { subpattern, def: def_id } - } else { - // If that fails, convert it to an opaque constant pattern. - match tcx.const_eval_resolve(self.param_env, uneval, span) { - Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span).kind, - Err(ErrorHandled::TooGeneric(_)) => { - // If we land here it means the const can't be evaluated because it's `TooGeneric`. - let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span }); - PatKind::Error(e) - } - Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()), - } - } + let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); + PatKind::InlineConstant { subpattern, def: def_id } } /// Converts literals, paths and negation of literals to patterns. @@ -729,9 +653,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ct_ty = self.typeck_results.expr_ty(expr); let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => { - self.const_to_pat(Const::Ty(ct_ty, constant), expr.hir_id, lit.span).kind - } + Ok(constant) => self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind, Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 07cd4ae68d9..79d2107b2a0 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -20,10 +20,10 @@ tracing = "0.1" [features] default = ["nightly"] nightly = [ + "dep:rustc_data_structures", + "dep:rustc_macros", + "dep:rustc_serialize", "rustc_ast_ir/nightly", - "rustc_data_structures", "rustc_index/nightly", - "rustc_macros", - "rustc_serialize", "rustc_type_ir/nightly", ] diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index c2201b1c41e..c79dad3953b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -388,6 +388,9 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` parse_invalid_identifier_with_leading_number = identifiers cannot start with a number +parse_invalid_label = + invalid label name `{$name}` + 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 @@ -414,6 +417,9 @@ parse_invalid_unicode_escape = invalid unicode character escape parse_invalid_variable_declaration = invalid variable declaration +parse_keyword_lifetime = + lifetimes cannot use keyword names + parse_kw_bad_case = keyword `{$kw}` is written in the wrong case .suggestion = write it in the correct case @@ -518,6 +524,8 @@ parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter} .label_opening_candidate = closing delimiter possibly meant for this .label_unclosed = unclosed delimiter +parse_misplaced_return_type = place the return type after the function parameters + parse_missing_comma_after_match_arm = expected `,` following `match` arm .suggestion = missing a comma here to end this `match` arm diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 092a2a10ab7..109d36fe689 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -660,9 +660,8 @@ pub(crate) struct RemoveLet { #[diag(parse_use_eq_instead)] pub(crate) struct UseEqInstead { #[primary_span] + #[suggestion(style = "verbose", applicability = "machine-applicable", code = "=")] pub span: Span, - #[suggestion(style = "verbose", applicability = "machine-applicable", code = "")] - pub suggestion: Span, } #[derive(Diagnostic)] @@ -1504,6 +1503,20 @@ pub(crate) struct FnPtrWithGenerics { } #[derive(Subdiagnostic)] +#[multipart_suggestion( + parse_misplaced_return_type, + style = "verbose", + applicability = "maybe-incorrect" +)] +pub(crate) struct MisplacedReturnType { + #[suggestion_part(code = " {snippet}")] + pub fn_params_end: Span, + pub snippet: String, + #[suggestion_part(code = "")] + pub ret_ty_span: Span, +} + +#[derive(Subdiagnostic)] #[multipart_suggestion(parse_suggestion, applicability = "maybe-incorrect")] pub(crate) struct FnPtrWithGenericsSugg { #[suggestion_part(code = "{snippet}")] @@ -1517,7 +1530,6 @@ pub(crate) struct FnPtrWithGenericsSugg { pub(crate) struct FnTraitMissingParen { pub span: Span, - pub machine_applicable: bool, } impl Subdiagnostic for FnTraitMissingParen { @@ -1527,16 +1539,11 @@ impl Subdiagnostic for FnTraitMissingParen { _: &F, ) { diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren); - let applicability = if self.machine_applicable { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; diag.span_suggestion_short( self.span.shrink_to_hi(), crate::fluent_generated::parse_add_paren, "()", - applicability, + Applicability::MachineApplicable, ); } } @@ -2010,6 +2017,21 @@ pub struct CannotBeRawIdent { } #[derive(Diagnostic)] +#[diag(parse_keyword_lifetime)] +pub struct KeywordLifetime { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_invalid_label)] +pub struct InvalidLabel { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] #[diag(parse_cr_doc_comment)] pub struct CrDocComment { #[primary_span] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a8fe35f45b3..0b2c3044039 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -124,7 +124,7 @@ impl<'a> Parser<'a> { if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; this.expect(&token::OpenDelim(Delimiter::Bracket))?; - let item = this.parse_attr_item(false)?; + let item = this.parse_attr_item(ForceCollect::No)?; this.expect(&token::CloseDelim(Delimiter::Bracket))?; let attr_sp = lo.to(this.prev_token.span); @@ -248,16 +248,15 @@ impl<'a> Parser<'a> { /// PATH /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. - pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> { + pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> { maybe_whole!(self, NtMeta, |attr| attr.into_inner()); - let do_parse = |this: &mut Self| { + let do_parse = |this: &mut Self, _empty_attrs| { let is_unsafe = this.eat_keyword(kw::Unsafe); let unsafety = if is_unsafe { let unsafe_span = this.prev_token.span; this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); this.expect(&token::OpenDelim(Delimiter::Parenthesis))?; - ast::Safety::Unsafe(unsafe_span) } else { ast::Safety::Default @@ -268,10 +267,10 @@ impl<'a> Parser<'a> { if is_unsafe { this.expect(&token::CloseDelim(Delimiter::Parenthesis))?; } - Ok(ast::AttrItem { unsafety, path, args, tokens: None }) + Ok((ast::AttrItem { unsafety, path, args, tokens: None }, false)) }; - // Attr items don't have attributes - if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) } + // Attr items don't have attributes. + self.collect_tokens_trailing_token(AttrWrapper::empty(), force_collect, do_parse) } /// Parses attributes that appear after the opening of an item. These should @@ -303,17 +302,13 @@ impl<'a> Parser<'a> { None }; if let Some(attr) = attr { - let end_pos = self.num_bump_calls; - // If we are currently capturing tokens, mark the location of this inner attribute. - // If capturing ends up creating a `LazyAttrTokenStream`, we will include - // this replace range with it, removing the inner attribute from the final - // `AttrTokenStream`. Inner attributes are stored in the parsed AST note. - // During macro expansion, they are selectively inserted back into the - // token stream (the first inner attribute is removed each time we invoke the - // corresponding macro). - let range = start_pos..end_pos; + // If we are currently capturing tokens (i.e. we are within a call to + // `Parser::collect_tokens_trailing_tokens`) record the token positions of this + // inner attribute, for possible later processing in a `LazyAttrTokenStream`. if let Capturing::Yes = self.capture_state.capturing { - self.capture_state.inner_attr_ranges.insert(attr.id, (range, None)); + let end_pos = self.num_bump_calls; + let range = start_pos..end_pos; + self.capture_state.inner_attr_ranges.insert(attr.id, range); } attrs.push(attr); } else { @@ -344,7 +339,7 @@ impl<'a> Parser<'a> { let mut expanded_attrs = Vec::with_capacity(1); while self.token.kind != token::Eof { let lo = self.token.span; - let item = self.parse_attr_item(true)?; + let item = self.parse_attr_item(ForceCollect::Yes)?; expanded_attrs.push((item, lo.to(self.prev_token.span))); if !self.eat(&token::Comma) { break; @@ -463,7 +458,8 @@ impl<'a> Parser<'a> { } } -/// The attributes are complete if all attributes are either a doc comment or a builtin attribute other than `cfg_attr` +/// The attributes are complete if all attributes are either a doc comment or a +/// builtin attribute other than `cfg_attr`. pub fn is_complete(attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { attr.is_doc_comment() diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 1123c31f551..dc5f98f7be8 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,5 +1,5 @@ -use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; -use rustc_ast::token::{self, Delimiter, Token, TokenKind}; +use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor}; +use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing}; use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream}; use rustc_ast::{self as ast}; @@ -17,12 +17,12 @@ use std::{iter, mem}; /// /// This wrapper prevents direct access to the underlying `ast::AttrVec`. /// Parsing code can only get access to the underlying attributes -/// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`. +/// by passing an `AttrWrapper` to `collect_tokens_trailing_token`. /// This makes it difficult to accidentally construct an AST node /// (which stores an `ast::AttrVec`) without first collecting tokens. /// /// This struct has its own module, to ensure that the parser code -/// cannot directly access the `attrs` field +/// cannot directly access the `attrs` field. #[derive(Debug, Clone)] pub struct AttrWrapper { attrs: AttrVec, @@ -76,14 +76,13 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { }) } -// Produces a `TokenStream` on-demand. Using `cursor_snapshot` -// and `num_calls`, we can reconstruct the `TokenStream` seen -// by the callback. This allows us to avoid producing a `TokenStream` -// if it is never needed - for example, a captured `macro_rules!` -// argument that is never passed to a proc macro. -// In practice token stream creation happens rarely compared to -// calls to `collect_tokens` (see some statistics in #78736), -// so we are doing as little up-front work as possible. +// From a value of this type we can reconstruct the `TokenStream` seen by the +// `f` callback passed to a call to `Parser::collect_tokens_trailing_token`, by +// replaying the getting of the tokens. This saves us producing a `TokenStream` +// if it is never needed, e.g. a captured `macro_rules!` argument that is never +// passed to a proc macro. In practice, token stream creation happens rarely +// compared to calls to `collect_tokens` (see some statistics in #78736) so we +// are doing as little up-front work as possible. // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. @@ -163,44 +162,55 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { } impl<'a> Parser<'a> { - /// Records all tokens consumed by the provided callback, - /// including the current token. These tokens are collected - /// into a `LazyAttrTokenStream`, and returned along with the result - /// of the callback. + /// Parses code with `f`. If appropriate, it records the tokens (in + /// `LazyAttrTokenStream` form) that were parsed in the result, accessible + /// via the `HasTokens` trait. The second (bool) part of the callback's + /// result indicates if an extra token should be captured, e.g. a comma or + /// semicolon. /// /// The `attrs` passed in are in `AttrWrapper` form, which is opaque. The /// `AttrVec` within is passed to `f`. See the comment on `AttrWrapper` for /// details. /// - /// Note: If your callback consumes an opening delimiter - /// (including the case where you call `collect_tokens` - /// when the current token is an opening delimiter), - /// you must also consume the corresponding closing delimiter. + /// Note: If your callback consumes an opening delimiter (including the + /// case where `self.token` is an opening delimiter on entry to this + /// function), you must also consume the corresponding closing delimiter. + /// E.g. you can consume `something ([{ }])` or `([{}])`, but not `([{}]`. + /// This restriction isn't a problem in practice, because parsed AST items + /// always have matching delimiters. /// - /// That is, you can consume - /// `something ([{ }])` or `([{}])`, but not `([{}]` - /// - /// This restriction shouldn't be an issue in practice, - /// since this function is used to record the tokens for - /// a parsed AST item, which always has matching delimiters. + /// The following example code will be used to explain things in comments + /// below. It has an outer attribute and an inner attribute. Parsing it + /// involves two calls to this method, one of which is indirectly + /// recursive. + /// ```ignore (fake attributes) + /// #[cfg_eval] // token pos + /// mod m { // 0.. 3 + /// #[cfg_attr(cond1, attr1)] // 3..12 + /// fn g() { // 12..17 + /// #![cfg_attr(cond2, attr2)] // 17..27 + /// let _x = 3; // 27..32 + /// } // 32..33 + /// } // 33..34 + /// ``` pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>( &mut self, attrs: AttrWrapper, force_collect: ForceCollect, - f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, TrailingToken)>, + f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, bool)>, ) -> PResult<'a, R> { - // We only bail out when nothing could possibly observe the collected tokens: - // 1. We cannot be force collecting tokens (since force-collecting requires tokens - // by definition + // Skip collection when nothing could observe the collected tokens, i.e. + // all of the following conditions hold. + // - We are not force collecting tokens (because force collection + // requires tokens by definition). if matches!(force_collect, ForceCollect::No) - // None of our outer attributes can require tokens (e.g. a proc-macro) + // - None of our outer attributes require tokens. && attrs.is_complete() - // If our target supports custom inner attributes, then we cannot bail - // out early, since we may need to capture tokens for a custom inner attribute - // invocation. + // - Our target doesn't support custom inner attributes (custom + // inner attribute invocation might require token capturing). && !R::SUPPORTS_CUSTOM_INNER_ATTRS - // Never bail out early in `capture_cfg` mode, since there might be `#[cfg]` - // or `#[cfg_attr]` attributes. + // - We are not in `capture_cfg` mode (which requires tokens if + // the parsed node has `#[cfg]` or `#[cfg_attr]` attributes). && !self.capture_cfg { return Ok(f(self, attrs.attrs)?.0); @@ -212,81 +222,68 @@ impl<'a> Parser<'a> { let has_outer_attrs = !attrs.attrs.is_empty(); let replace_ranges_start = self.capture_state.replace_ranges.len(); - let (mut ret, trailing) = { + // We set and restore `Capturing::Yes` on either side of the call to + // `f`, so we can distinguish the outermost call to + // `collect_tokens_trailing_token` (e.g. parsing `m` in the example + // above) from any inner (indirectly recursive) calls (e.g. parsing `g` + // in the example above). This distinction is used below and in + // `Parser::parse_inner_attributes`. + let (mut ret, capture_trailing) = { let prev_capturing = mem::replace(&mut self.capture_state.capturing, Capturing::Yes); let ret_and_trailing = f(self, attrs.attrs); self.capture_state.capturing = prev_capturing; ret_and_trailing? }; - // When we're not in `capture-cfg` mode, then bail out early if: - // 1. Our target doesn't support tokens at all (e.g we're parsing an `NtIdent`) - // so there's nothing for us to do. - // 2. Our target already has tokens set (e.g. we've parsed something - // like `#[my_attr] $item`). The actual parsing code takes care of - // prepending any attributes to the nonterminal, so we don't need to - // modify the already captured tokens. - // Note that this check is independent of `force_collect`- if we already - // have tokens, or can't even store them, then there's never a need to - // force collection of new tokens. + // When we're not in `capture_cfg` mode, then skip collecting and + // return early if either of the following conditions hold. + // - `None`: Our target doesn't support tokens at all (e.g. `NtIdent`). + // - `Some(Some(_))`: Our target already has tokens set (e.g. we've + // parsed something like `#[my_attr] $item`). The actual parsing code + // takes care of prepending any attributes to the nonterminal, so we + // don't need to modify the already captured tokens. + // + // Note that this check is independent of `force_collect`. There's no + // need to collect tokens when we don't support tokens or already have + // tokens. if !self.capture_cfg && matches!(ret.tokens_mut(), None | Some(Some(_))) { return Ok(ret); } - // This is very similar to the bail out check at the start of this function. - // Now that we've parsed an AST node, we have more information available. + // This is similar to the "skip collection" check at the start of this + // function, but now that we've parsed an AST node we have more + // information available. (If we return early here that means the + // setup, such as cloning the token cursor, was unnecessary. That's + // hard to avoid.) + // + // Skip collection when nothing could observe the collected tokens, i.e. + // all of the following conditions hold. + // - We are not force collecting tokens. if matches!(force_collect, ForceCollect::No) - // We now have inner attributes available, so this check is more precise - // than `attrs.is_complete()` at the start of the function. - // As a result, we don't need to check `R::SUPPORTS_CUSTOM_INNER_ATTRS` + // - None of our outer *or* inner attributes require tokens. + // (`attrs` was just outer attributes, but `ret.attrs()` is outer + // and inner attributes. That makes this check more precise than + // `attrs.is_complete()` at the start of the function, and we can + // skip the subsequent check on `R::SUPPORTS_CUSTOM_INNER_ATTRS`. && crate::parser::attr::is_complete(ret.attrs()) - // Subtle: We call `has_cfg_or_cfg_attr` with the attrs from `ret`. - // This ensures that we consider inner attributes (e.g. `#![cfg]`), - // which require us to have tokens available - // We also call `has_cfg_or_cfg_attr` at the beginning of this function, - // but we only bail out if there's no possibility of inner attributes - // (!R::SUPPORTS_CUSTOM_INNER_ATTRS) - // We only capture about `#[cfg]` or `#[cfg_attr]` in `capture_cfg` - // mode - during normal parsing, we don't need any special capturing - // for those attributes, since they're builtin. - && !(self.capture_cfg && has_cfg_or_cfg_attr(ret.attrs())) + // - We are not in `capture_cfg` mode, or we are but there are no + // `#[cfg]` or `#[cfg_attr]` attributes. (During normal + // non-`capture_cfg` parsing, we don't need any special capturing + // for those attributes, because they're builtin.) + && (!self.capture_cfg || !has_cfg_or_cfg_attr(ret.attrs())) { return Ok(ret); } - let mut inner_attr_replace_ranges = Vec::new(); - // Take the captured ranges for any inner attributes that we parsed. - for inner_attr in ret.attrs().iter().filter(|a| a.style == ast::AttrStyle::Inner) { - if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) { - inner_attr_replace_ranges.push(attr_range); - } else { - self.dcx().span_delayed_bug(inner_attr.span, "Missing token range for attribute"); - } - } - let replace_ranges_end = self.capture_state.replace_ranges.len(); - // Capture a trailing token if requested by the callback 'f' - let captured_trailing = match trailing { - TrailingToken::None => false, - TrailingToken::Gt => { - assert_eq!(self.token.kind, token::Gt); - false - } - TrailingToken::Semi => { - assert_eq!(self.token.kind, token::Semi); - true - } - TrailingToken::MaybeComma => self.token.kind == token::Comma, - }; - assert!( - !(self.break_last_token && captured_trailing), + !(self.break_last_token && capture_trailing), "Cannot set break_last_token and have trailing token" ); let end_pos = self.num_bump_calls - + captured_trailing as u32 + + capture_trailing as u32 // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens), then // extend the range of captured tokens to include it, since the parser was not actually // bumped past it. When the `LazyAttrTokenStream` gets converted into an @@ -295,15 +292,28 @@ impl<'a> Parser<'a> { let num_calls = end_pos - start_pos; + // Take the captured ranges for any inner attributes that we parsed in + // `Parser::parse_inner_attributes`, and pair them in a `ReplaceRange` + // with `None`, which means the relevant tokens will be removed. (More + // details below.) + let mut inner_attr_replace_ranges = Vec::new(); + for inner_attr in ret.attrs().iter().filter(|a| a.style == ast::AttrStyle::Inner) { + if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) { + inner_attr_replace_ranges.push((attr_range, None)); + } else { + self.dcx().span_delayed_bug(inner_attr.span, "Missing token range for attribute"); + } + } + // This is hot enough for `deep-vector` that checking the conditions for an empty iterator // is measurably faster than actually executing the iterator. let replace_ranges: Box<[ReplaceRange]> = if replace_ranges_start == replace_ranges_end && inner_attr_replace_ranges.is_empty() { Box::new([]) } else { - // Grab any replace ranges that occur *inside* the current AST node. - // We will perform the actual replacement when we convert the `LazyAttrTokenStream` - // to an `AttrTokenStream`. + // Grab any replace ranges that occur *inside* the current AST node. We will + // perform the actual replacement only when we convert the `LazyAttrTokenStream` to + // an `AttrTokenStream`. self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end] .iter() .cloned() @@ -312,6 +322,28 @@ impl<'a> Parser<'a> { .collect() }; + // What is the status here when parsing the example code at the top of this method? + // + // When parsing `g`: + // - `start_pos..end_pos` is `12..33` (`fn g { ... }`, excluding the outer attr). + // - `inner_attr_replace_ranges` has one entry (`5..15`, when counting from `fn`), to + // delete the inner attr's tokens. + // - This entry is put into the lazy tokens for `g`, i.e. deleting the inner attr from + // those tokens (if they get evaluated). + // - Those lazy tokens are also put into an `AttrsTarget` that is appended to `self`'s + // replace ranges at the bottom of this function, for processing when parsing `m`. + // - `replace_ranges_start..replace_ranges_end` is empty. + // + // When parsing `m`: + // - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute). + // - `inner_attr_replace_ranges` is empty. + // - `replace_range_start..replace_ranges_end` has two entries. + // - One to delete the inner attribute (`17..27`), obtained when parsing `g` (see above). + // - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`, + // including its outer attribute), with: + // - `attrs`: includes the outer and the inner attr. + // - `tokens`: lazy tokens for `g` (with its inner attr deleted). + let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl { start_token, num_calls, @@ -325,27 +357,37 @@ impl<'a> Parser<'a> { *target_tokens = Some(tokens.clone()); } - let final_attrs = ret.attrs(); - // If `capture_cfg` is set and we're inside a recursive call to // `collect_tokens_trailing_token`, then we need to register a replace range // if we have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager cfg-expansion // on the captured token stream. if self.capture_cfg && matches!(self.capture_state.capturing, Capturing::Yes) - && has_cfg_or_cfg_attr(final_attrs) + && has_cfg_or_cfg_attr(ret.attrs()) { assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - // Replace the entire AST node that we just parsed, including attributes, with - // `target`. If this AST node is inside an item that has `#[derive]`, then this will - // allow us to cfg-expand this AST node. + // What is the status here when parsing the example code at the top of this method? + // + // When parsing `g`, we add two entries: + // - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with: + // - `attrs`: includes the outer and the inner attr. + // - `tokens`: lazy tokens for `g` (with its inner attr deleted). + // - `inner_attr_replace_ranges` contains the one entry to delete the inner attr's + // tokens (`17..27`). + // + // When parsing `m`, we do nothing here. + + // Set things up so that the entire AST node that we just parsed, including attributes, + // will be replaced with `target` in the lazy token stream. This will allow us to + // cfg-expand this AST node. let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; - let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; + let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens }; self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } else if matches!(self.capture_state.capturing, Capturing::No) { - // Only clear the ranges once we've finished capturing entirely. + // Only clear the ranges once we've finished capturing entirely, i.e. we've finished + // the outermost call to this method. self.capture_state.replace_ranges.clear(); self.capture_state.inner_attr_ranges.clear(); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 0da7fefe6ed..1a0d9aa6378 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -430,7 +430,7 @@ impl<'a> Parser<'a> { &mut self, edible: &[TokenKind], inedible: &[TokenKind], - ) -> PResult<'a, Recovered> { + ) -> PResult<'a, ErrorGuaranteed> { debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible); fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); @@ -533,7 +533,7 @@ impl<'a> Parser<'a> { sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); self.bump(); - return Ok(Recovered::Yes(guar)); + return Ok(guar); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(Delimiter::Brace) || ((t.can_begin_expr() || t.can_begin_item()) @@ -557,7 +557,7 @@ impl<'a> Parser<'a> { unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); - return Ok(Recovered::Yes(guar)); + return Ok(guar); } } @@ -566,10 +566,7 @@ impl<'a> Parser<'a> { && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq))) { // Likely typo: `=` → `==` in let expr or enum item - return Err(self.dcx().create_err(UseEqInstead { - span: self.token.span, - suggestion: self.token.span.with_lo(self.token.span.lo() + BytePos(1)), - })); + return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); } if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { @@ -715,7 +712,7 @@ impl<'a> Parser<'a> { if self.check_too_many_raw_str_terminators(&mut err) { if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) { let guar = err.emit(); - return Ok(Recovered::Yes(guar)); + return Ok(guar); } else { return Err(err); } @@ -2240,11 +2237,11 @@ impl<'a> Parser<'a> { } _ => { // Otherwise, try to get a type and emit a suggestion. - if let Some(ty) = pat.to_ty() { + if let Some(_) = pat.to_ty() { err.span_suggestion_verbose( - pat.span, + pat.span.shrink_to_lo(), "explicitly ignore the parameter name", - format!("_: {}", pprust::ty_to_string(&ty)), + "_: ".to_string(), Applicability::MachineApplicable, ); err.note(rfc_note); @@ -2256,7 +2253,7 @@ impl<'a> Parser<'a> { // `fn foo(a, b) {}`, `fn foo(a<x>, b<y>) {}` or `fn foo(usize, usize) {}` if first_param { - err.span_suggestion( + err.span_suggestion_verbose( self_span, "if this is a `self` type, give it a parameter name", self_sugg, @@ -2266,14 +2263,14 @@ impl<'a> Parser<'a> { // Avoid suggesting that `fn foo(HashMap<u32>)` is fixed with a change to // `fn foo(HashMap: TypeName<u32>)`. if self.token != token::Lt { - err.span_suggestion( + err.span_suggestion_verbose( param_span, "if this is a parameter name, give it a type", param_sugg, Applicability::HasPlaceholders, ); } - err.span_suggestion( + err.span_suggestion_verbose( type_span, "if this is a type, explicitly ignore the parameter name", type_sugg, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4bd20be4171..2542108728f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -5,7 +5,7 @@ use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, - SemiColonMode, SeqSep, TokenType, Trailing, TrailingToken, + SemiColonMode, SeqSep, TokenType, Trailing, }; use crate::errors; @@ -785,23 +785,14 @@ impl<'a> Parser<'a> { } }; - self.parse_and_disallow_postfix_after_cast(cast_expr) - } - - /// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast, - /// then emits an error and returns the newly parsed tree. - /// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`. - fn parse_and_disallow_postfix_after_cast( - &mut self, - cast_expr: P<Expr>, - ) -> PResult<'a, P<Expr>> { - if let ExprKind::Type(_, _) = cast_expr.kind { - panic!("ExprKind::Type must not be parsed"); - } + // Try to parse a postfix operator such as `.`, `?`, or index (`[]`) + // after a cast. If one is present, emit an error then return a valid + // parse tree; For something like `&x as T[0]` will be as if it was + // written `((&x) as T)[0]`. let span = cast_expr.span; - let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?; + let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?; // Check if an illegal postfix operator has been added after the cast. // If the resulting expression is not a cast, it is an illegal postfix operator. @@ -885,23 +876,63 @@ impl<'a> Parser<'a> { self.collect_tokens_for_expr(attrs, |this, attrs| { let base = this.parse_expr_bottom()?; let span = this.interpolated_or_expr_span(&base); - this.parse_expr_dot_or_call_with(base, span, attrs) + this.parse_expr_dot_or_call_with(attrs, base, span) }) } pub(super) fn parse_expr_dot_or_call_with( &mut self, - e0: P<Expr>, - lo: Span, mut attrs: ast::AttrVec, + mut e: P<Expr>, + lo: Span, ) -> PResult<'a, P<Expr>> { - // Stitch the list of outer attributes onto the return value. - // A little bit ugly, but the best way given the current code - // structure - let res = ensure_sufficient_stack( - // this expr demonstrates the recursion it guards against - || self.parse_expr_dot_or_call_with_(e0, lo), - ); + let res = ensure_sufficient_stack(|| { + loop { + let has_question = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `?` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Question) + } else { + self.eat(&token::Question) + }; + if has_question { + // `expr?` + e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); + continue; + } + let has_dot = + if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { + // We are using noexpect here because we don't expect a `.` directly after + // a `return` which could be suggested otherwise. + self.eat_noexpect(&token::Dot) + } else if self.token.kind == TokenKind::RArrow && self.may_recover() { + // Recovery for `expr->suffix`. + self.bump(); + let span = self.prev_token.span; + self.dcx().emit_err(errors::ExprRArrowCall { span }); + true + } else { + self.eat(&token::Dot) + }; + if has_dot { + // expr.f + e = self.parse_dot_suffix_expr(lo, e)?; + continue; + } + if self.expr_is_complete(&e) { + return Ok(e); + } + e = match self.token.kind { + token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), + token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, + _ => return Ok(e), + } + } + }); + + // Stitch the list of outer attributes onto the return value. A little + // bit ugly, but the best way given the current code structure. if attrs.is_empty() { res } else { @@ -915,50 +946,6 @@ impl<'a> Parser<'a> { } } - fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { - loop { - let has_question = - if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `?` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Question) - } else { - self.eat(&token::Question) - }; - if has_question { - // `expr?` - e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e)); - continue; - } - let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) { - // we are using noexpect here because we don't expect a `.` directly after a `return` - // which could be suggested otherwise - self.eat_noexpect(&token::Dot) - } else if self.token.kind == TokenKind::RArrow && self.may_recover() { - // Recovery for `expr->suffix`. - self.bump(); - let span = self.prev_token.span; - self.dcx().emit_err(errors::ExprRArrowCall { span }); - true - } else { - self.eat(&token::Dot) - }; - if has_dot { - // expr.f - e = self.parse_dot_suffix_expr(lo, e)?; - continue; - } - if self.expr_is_complete(&e) { - return Ok(e); - } - e = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e), - token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?, - _ => return Ok(e), - } - } - } - pub(super) fn parse_dot_suffix_expr( &mut self, lo: Span, @@ -1388,7 +1375,7 @@ impl<'a> Parser<'a> { /// Parses things like parenthesized exprs, macros, `return`, etc. /// /// N.B., this does not parse outer attributes, and is private because it only works - /// correctly if called from `parse_dot_or_call_expr()`. + /// correctly if called from `parse_expr_dot_or_call`. fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> { maybe_recover_from_interpolated_ty_qpath!(self, true); @@ -2487,7 +2474,7 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, is_placeholder: false, }, - TrailingToken::MaybeComma, + this.token == token::Comma, )) }) } @@ -2932,10 +2919,17 @@ impl<'a> Parser<'a> { } pub(crate) fn eat_label(&mut self) -> Option<Label> { - self.token.lifetime().map(|ident| { + if let Some(ident) = self.token.lifetime() { + // Disallow `'fn`, but with a better error message than `expect_lifetime`. + if ident.without_first_quote().is_reserved() { + self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); + } + self.bump(); - Label { ident } - }) + Some(Label { ident }) + } else { + None + } } /// Parses a `match ... { ... }` expression (`match` token already eaten). @@ -3263,7 +3257,7 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, is_placeholder: false, }, - TrailingToken::None, + false, )) }) } @@ -3772,7 +3766,7 @@ impl<'a> Parser<'a> { id: DUMMY_NODE_ID, is_placeholder: false, }, - TrailingToken::MaybeComma, + this.token == token::Comma, )) }) } @@ -3868,18 +3862,12 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P<Expr>> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let res = f(this, attrs)?; - let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR) - && this.token.kind == token::Semi - { - TrailingToken::Semi - } else if this.token.kind == token::Gt { - TrailingToken::Gt - } else { - // FIXME - pass this through from the place where we know - // we need a comma, rather than assuming that `#[attr] expr,` - // always captures a trailing comma - TrailingToken::MaybeComma - }; + let trailing = (this.restrictions.contains(Restrictions::STMT_EXPR) + && this.token.kind == token::Semi) + // FIXME: pass an additional condition through from the place + // where we know we need a comma, rather than assuming that + // `#[attr] expr,` always captures a trailing comma. + || this.token.kind == token::Comma; Ok((res, trailing)) }) } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 10c7715c7dc..523538e9643 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -4,7 +4,7 @@ use crate::errors::{ WhereClauseBeforeTupleStructBodySugg, }; -use super::{ForceCollect, Parser, TrailingToken}; +use super::{ForceCollect, Parser}; use ast::token::Delimiter; use rustc_ast::token; @@ -229,13 +229,13 @@ impl<'a> Parser<'a> { span: where_predicate.span(), }); // FIXME - try to continue parsing other generics? - return Ok((None, TrailingToken::None)); + return Ok((None, false)); } Err(err) => { err.cancel(); // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`? this.restore_snapshot(snapshot); - return Ok((None, TrailingToken::None)); + return Ok((None, false)); } } } else { @@ -249,14 +249,14 @@ impl<'a> Parser<'a> { .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span }); } } - return Ok((None, TrailingToken::None)); + return Ok((None, false)); }; if !this.eat(&token::Comma) { done = true; } - // We just ate the comma, so no need to use `TrailingToken` - Ok((param, TrailingToken::None)) + // We just ate the comma, so no need to capture the trailing token. + Ok((param, false)) })?; if let Some(param) = param { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 76857cb8504..fbc5b914600 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,8 +1,6 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; -use super::{ - AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, TrailingToken, -}; +use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing}; use crate::errors::{self, MacroExpandsToAdtField}; use crate::fluent_generated as fluent; use crate::maybe_whole; @@ -19,6 +17,7 @@ use rustc_span::edit_distance::edit_distance; use rustc_span::edition::Edition; use rustc_span::source_map; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::ErrorGuaranteed; use rustc_span::{Span, DUMMY_SP}; use std::fmt::Write; use std::mem; @@ -128,56 +127,41 @@ impl<'a> Parser<'a> { Some(item.into_inner()) }); - let item = - self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| { - let item = - this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode); - Ok((item?, TrailingToken::None)) - })?; - - Ok(item) - } - - fn parse_item_common_( - &mut self, - mut attrs: AttrVec, - mac_allowed: bool, - attrs_allowed: bool, - fn_parse_mode: FnParseMode, - ) -> PResult<'a, Option<Item>> { - let lo = self.token.span; - let vis = self.parse_visibility(FollowedByType::No)?; - let mut def = self.parse_defaultness(); - let kind = self.parse_item_kind( - &mut attrs, - mac_allowed, - lo, - &vis, - &mut def, - fn_parse_mode, - Case::Sensitive, - )?; - if let Some((ident, kind)) = kind { - self.error_on_unconsumed_default(def, &kind); - let span = lo.to(self.prev_token.span); - let id = DUMMY_NODE_ID; - let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; - return Ok(Some(item)); - } + self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| { + let lo = this.token.span; + let vis = this.parse_visibility(FollowedByType::No)?; + let mut def = this.parse_defaultness(); + let kind = this.parse_item_kind( + &mut attrs, + mac_allowed, + lo, + &vis, + &mut def, + fn_parse_mode, + Case::Sensitive, + )?; + if let Some((ident, kind)) = kind { + this.error_on_unconsumed_default(def, &kind); + let span = lo.to(this.prev_token.span); + let id = DUMMY_NODE_ID; + let item = Item { ident, attrs, id, kind, vis, span, tokens: None }; + return Ok((Some(item), false)); + } - // At this point, we have failed to parse an item. - if !matches!(vis.kind, VisibilityKind::Inherited) { - self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); - } + // At this point, we have failed to parse an item. + if !matches!(vis.kind, VisibilityKind::Inherited) { + this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + } - if let Defaultness::Default(span) = def { - self.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); - } + if let Defaultness::Default(span) = def { + this.dcx().emit_err(errors::DefaultNotFollowedByItem { span }); + } - if !attrs_allowed { - self.recover_attrs_no_item(&attrs)?; - } - Ok(None) + if !attrs_allowed { + this.recover_attrs_no_item(&attrs)?; + } + Ok((None, false)) + }) } /// Error in-case `default` was parsed in an in-appropriate context. @@ -1570,7 +1554,7 @@ impl<'a> Parser<'a> { let vis = this.parse_visibility(FollowedByType::No)?; if !this.recover_nested_adt_item(kw::Enum)? { - return Ok((None, TrailingToken::None)); + return Ok((None, false)); } let ident = this.parse_field_ident("enum", vlo)?; @@ -1582,7 +1566,7 @@ impl<'a> Parser<'a> { this.bump(); this.parse_delim_args()?; - return Ok((None, TrailingToken::MaybeComma)); + return Ok((None, this.token == token::Comma)); } let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { @@ -1639,7 +1623,7 @@ impl<'a> Parser<'a> { is_placeholder: false, }; - Ok((Some(vr), TrailingToken::MaybeComma)) + Ok((Some(vr), this.token == token::Comma)) }, ) .map_err(|mut err| { @@ -1831,7 +1815,7 @@ impl<'a> Parser<'a> { attrs, is_placeholder: false, }, - TrailingToken::MaybeComma, + p.token == token::Comma, )) }) }) @@ -1846,8 +1830,7 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - this.parse_single_struct_field(adt_ty, lo, vis, attrs) - .map(|field| (field, TrailingToken::None)) + this.parse_single_struct_field(adt_ty, lo, vis, attrs).map(|field| (field, false)) }) } @@ -2350,14 +2333,106 @@ impl<'a> Parser<'a> { } } }; + + // Store the end of function parameters to give better diagnostics + // inside `parse_fn_body()`. + let fn_params_end = self.prev_token.span.shrink_to_hi(); + generics.where_clause = self.parse_where_clause()?; // `where T: Ord` + // `fn_params_end` is needed only when it's followed by a where clause. + let fn_params_end = + if generics.where_clause.has_where_token { Some(fn_params_end) } else { None }; + let mut sig_hi = self.prev_token.span; - let body = self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body)?; // `;` or `{ ... }`. + // Either `;` or `{ ... }`. + let body = + self.parse_fn_body(attrs, &ident, &mut sig_hi, fn_parse_mode.req_body, fn_params_end)?; let fn_sig_span = sig_lo.to(sig_hi); Ok((ident, FnSig { header, decl, span: fn_sig_span }, generics, body)) } + /// Provide diagnostics when function body is not found + fn error_fn_body_not_found( + &mut self, + ident_span: Span, + req_body: bool, + fn_params_end: Option<Span>, + ) -> PResult<'a, ErrorGuaranteed> { + let expected = if req_body { + &[token::OpenDelim(Delimiter::Brace)][..] + } else { + &[token::Semi, token::OpenDelim(Delimiter::Brace)] + }; + match self.expected_one_of_not_found(&[], expected) { + Ok(error_guaranteed) => Ok(error_guaranteed), + Err(mut err) => { + if self.token.kind == token::CloseDelim(Delimiter::Brace) { + // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in + // the AST for typechecking. + err.span_label(ident_span, "while parsing this `fn`"); + Ok(err.emit()) + } else if self.token.kind == token::RArrow + && let Some(fn_params_end) = fn_params_end + { + // Instead of a function body, the parser has encountered a right arrow + // preceded by a where clause. + + // Find whether token behind the right arrow is a function trait and + // store its span. + let fn_trait_span = + [sym::FnOnce, sym::FnMut, sym::Fn].into_iter().find_map(|symbol| { + if self.prev_token.is_ident_named(symbol) { + Some(self.prev_token.span) + } else { + None + } + }); + + // Parse the return type (along with the right arrow) and store its span. + // If there's a parse error, cancel it and return the existing error + // as we are primarily concerned with the + // expected-function-body-but-found-something-else error here. + let arrow_span = self.token.span; + let ty_span = match self.parse_ret_ty( + AllowPlus::Yes, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + ) { + Ok(ty_span) => ty_span.span().shrink_to_hi(), + Err(parse_error) => { + parse_error.cancel(); + return Err(err); + } + }; + let ret_ty_span = arrow_span.to(ty_span); + + if let Some(fn_trait_span) = fn_trait_span { + // Typo'd Fn* trait bounds such as + // fn foo<F>() where F: FnOnce -> () {} + err.subdiagnostic(errors::FnTraitMissingParen { span: fn_trait_span }); + } else if let Ok(snippet) = self.psess.source_map().span_to_snippet(ret_ty_span) + { + // If token behind right arrow is not a Fn* trait, the programmer + // probably misplaced the return type after the where clause like + // `fn foo<T>() where T: Default -> u8 {}` + err.primary_message( + "return type should be specified after the function parameters", + ); + err.subdiagnostic(errors::MisplacedReturnType { + fn_params_end, + snippet, + ret_ty_span, + }); + } + Err(err) + } else { + Err(err) + } + } + } + } + /// Parse the "body" of a function. /// This can either be `;` when there's no body, /// or e.g. a block when the function is a provided one. @@ -2367,6 +2442,7 @@ impl<'a> Parser<'a> { ident: &Ident, sig_hi: &mut Span, req_body: bool, + fn_params_end: Option<Span>, ) -> PResult<'a, Option<P<Block>>> { let has_semi = if req_body { self.token.kind == TokenKind::Semi @@ -2395,33 +2471,7 @@ impl<'a> Parser<'a> { }); (AttrVec::new(), Some(self.mk_block_err(span, guar))) } else { - let expected = if req_body { - &[token::OpenDelim(Delimiter::Brace)][..] - } else { - &[token::Semi, token::OpenDelim(Delimiter::Brace)] - }; - if let Err(mut err) = self.expected_one_of_not_found(&[], expected) { - if self.token.kind == token::CloseDelim(Delimiter::Brace) { - // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in - // the AST for typechecking. - err.span_label(ident.span, "while parsing this `fn`"); - err.emit(); - } else { - // check for typo'd Fn* trait bounds such as - // fn foo<F>() where F: FnOnce -> () {} - if self.token.kind == token::RArrow { - let machine_applicable = [sym::FnOnce, sym::FnMut, sym::Fn] - .into_iter() - .any(|s| self.prev_token.is_ident_named(s)); - - err.subdiagnostic(errors::FnTraitMissingParen { - span: self.prev_token.span, - machine_applicable, - }); - } - return Err(err); - } - } + self.error_fn_body_not_found(ident.span, req_body, fn_params_end)?; (AttrVec::new(), None) }; attrs.extend(inner_attrs); @@ -2750,7 +2800,7 @@ impl<'a> Parser<'a> { if let Some(mut param) = this.parse_self_param()? { param.attrs = attrs; let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) }; - return Ok((res?, TrailingToken::None)); + return Ok((res?, false)); } let is_name_required = match this.token.kind { @@ -2766,7 +2816,7 @@ impl<'a> Parser<'a> { this.parameter_without_type(&mut err, pat, is_name_required, first_param) { let guar = err.emit(); - Ok((dummy_arg(ident, guar), TrailingToken::None)) + Ok((dummy_arg(ident, guar), false)) } else { Err(err) }; @@ -2809,7 +2859,7 @@ impl<'a> Parser<'a> { Ok(( Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty }, - TrailingToken::None, + false, )) }) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 958458eda9a..7326b9ec51f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -91,17 +91,6 @@ pub enum ForceCollect { No, } -#[derive(Debug, Eq, PartialEq)] -pub enum TrailingToken { - None, - Semi, - Gt, - /// If the trailing token is a comma, then capture it - /// Otherwise, ignore the trailing token - MaybeComma, -} - -/// Like `maybe_whole_expr`, but for things other than expressions. #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { @@ -232,11 +221,12 @@ enum Capturing { Yes, } +// This state is used by `Parser::collect_tokens_trailing_token`. #[derive(Clone, Debug)] struct CaptureState { capturing: Capturing, replace_ranges: Vec<ReplaceRange>, - inner_attr_ranges: FxHashMap<AttrId, ReplaceRange>, + inner_attr_ranges: FxHashMap<AttrId, Range<u32>>, } /// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that @@ -436,6 +426,11 @@ impl<'a> Parser<'a> { // Make parser point to the first token. parser.bump(); + // Change this from 1 back to 0 after the bump. This eases debugging of + // `Parser::collect_tokens_trailing_token` nicer because it makes the + // token positions 0-indexed which is nicer than 1-indexed. + parser.num_bump_calls = 0; + parser } @@ -506,6 +501,7 @@ impl<'a> Parser<'a> { FatalError.raise(); } else { self.expected_one_of_not_found(edible, inedible) + .map(|error_guaranteed| Recovered::Yes(error_guaranteed)) } } @@ -953,11 +949,10 @@ impl<'a> Parser<'a> { let initial_semicolon = self.token.span; while self.eat(&TokenKind::Semi) { - let _ = - self.parse_stmt_without_recovery(false, ForceCollect::Yes).unwrap_or_else(|e| { - e.cancel(); - None - }); + let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| { + e.cancel(); + None + }); } expect_err @@ -1509,7 +1504,7 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token( AttrWrapper::empty(), ForceCollect::Yes, - |this, _attrs| Ok((f(this)?, TrailingToken::None)), + |this, _attrs| Ok((f(this)?, false)), ) } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 4a78b427832..886d6af1735 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -171,14 +171,17 @@ impl<'a> Parser<'a> { NonterminalKind::Path => { NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) } - NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(true)?)), + NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)), NonterminalKind::Vis => { NtVis(P(self .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?)) } NonterminalKind::Lifetime => { - return if self.check_lifetime() { - Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident)) + // We want to keep `'keyword` parsing, just like `keyword` is still + // an ident for nonterminal purposes. + return if let Some(ident) = self.token.lifetime() { + self.bump(); + Ok(ParseNtResult::Lifetime(ident)) } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index e4e89615d71..18d531faeaa 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,4 +1,4 @@ -use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, TrailingToken}; +use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing}; use crate::errors::{ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed, DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt, @@ -392,9 +392,9 @@ impl<'a> Parser<'a> { // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. if let Ok(expr) = snapshot .parse_expr_dot_or_call_with( + AttrVec::new(), self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, - AttrVec::new(), ) .map_err(|err| err.cancel()) { @@ -542,12 +542,12 @@ impl<'a> Parser<'a> { None => PatKind::Path(qself, path), } } - } else if let token::Lifetime(lt) = self.token.kind + } else if let Some(lt) = self.token.lifetime() // In pattern position, we're totally fine with using "next token isn't colon" // as a heuristic. We could probably just always try to recover if it's a lifetime, // because we never have `'a: label {}` in a pattern position anyways, but it does // keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..` - && could_be_unclosed_char_literal(Ident::with_dummy_span(lt)) + && could_be_unclosed_char_literal(lt) && !self.look_ahead(1, |token| matches!(token.kind, token::Colon)) { // Recover a `'a` as a `'a'` literal @@ -683,12 +683,12 @@ impl<'a> Parser<'a> { /// Parse `&pat` / `&mut pat`. fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> { self.expect_and()?; - if let token::Lifetime(name) = self.token.kind { + if let Some(lifetime) = self.token.lifetime() { self.bump(); // `'a` self.dcx().emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, - symbol: name, + symbol: lifetime.name, suggestion: self.prev_token.span.until(self.token.span), }); } @@ -1315,9 +1315,8 @@ impl<'a> Parser<'a> { last_non_comma_dotdot_span = Some(this.prev_token.span); - // We just ate a comma, so there's no need to use - // `TrailingToken::Comma` - Ok((field, TrailingToken::None)) + // We just ate a comma, so there's no need to capture a trailing token. + Ok((field, false)) })?; fields.push(field) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 70d41de00a7..d8de7c1bfa1 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -3,7 +3,6 @@ use super::diagnostics::AttemptLocalParseRecovery; use super::expr::LhsExpr; use super::pat::{PatternLocation, RecoverComma}; use super::path::PathStyle; -use super::TrailingToken; use super::{ AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode, }; @@ -73,6 +72,7 @@ impl<'a> Parser<'a> { lo, attrs, errors::InvalidVariableDeclarationSub::MissingLet, + force_collect, )? } else if self.is_kw_followed_by_ident(kw::Auto) && self.may_recover() { self.bump(); // `auto` @@ -80,6 +80,7 @@ impl<'a> Parser<'a> { lo, attrs, errors::InvalidVariableDeclarationSub::UseLetNotAuto, + force_collect, )? } else if self.is_kw_followed_by_ident(sym::var) && self.may_recover() { self.bump(); // `var` @@ -87,6 +88,7 @@ impl<'a> Parser<'a> { lo, attrs, errors::InvalidVariableDeclarationSub::UseLetNotVar, + force_collect, )? } else if self.check_path() && !self.token.is_qpath_start() @@ -97,17 +99,17 @@ impl<'a> Parser<'a> { // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. // Also, we avoid stealing syntax from `parse_item_`. - match force_collect { - ForceCollect::Yes => { - self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))? + let stmt = self.collect_tokens_trailing_token( + AttrWrapper::empty(), + force_collect, + |this, _empty_attrs| Ok((this.parse_stmt_path_start(lo, attrs)?, false)), + ); + match stmt { + Ok(stmt) => stmt, + Err(mut err) => { + self.suggest_add_missing_let_for_stmt(&mut err); + return Err(err); } - ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) { - Ok(stmt) => stmt, - Err(mut err) => { - self.suggest_add_missing_let_for_stmt(&mut err); - return Err(err); - } - }, } } else if let Some(item) = self.parse_item_common( attrs.clone(), @@ -124,12 +126,13 @@ impl<'a> Parser<'a> { self.mk_stmt(lo, StmtKind::Empty) } else if self.token != token::CloseDelim(Delimiter::Brace) { // Remainder are line-expr stmts. - let e = match force_collect { - ForceCollect::Yes => self.collect_tokens_no_attrs(|this| { - this.parse_expr_res(Restrictions::STMT_EXPR, attrs) - })?, - ForceCollect::No => self.parse_expr_res(Restrictions::STMT_EXPR, attrs)?, - }; + let e = self.collect_tokens_trailing_token( + AttrWrapper::empty(), + force_collect, + |this, _empty_attrs| { + Ok((this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?, false)) + }, + )?; if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) { let bl = self.parse_block()?; // Destructuring assignment ... else. @@ -149,11 +152,7 @@ impl<'a> Parser<'a> { if this.eat(&token::Not) { let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?; - if this.token == token::Semi { - return Ok((stmt_mac, TrailingToken::Semi)); - } else { - return Ok((stmt_mac, TrailingToken::None)); - } + return Ok((stmt_mac, this.token == token::Semi)); } let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) { @@ -164,10 +163,10 @@ impl<'a> Parser<'a> { }; let expr = this.with_res(Restrictions::STMT_EXPR, |this| { - this.parse_expr_dot_or_call_with(expr, lo, attrs) + this.parse_expr_dot_or_call_with(attrs, expr, lo) })?; // `DUMMY_SP` will get overwritten later in this function - Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None)) + Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), false)) })?; if let StmtKind::Expr(expr) = stmt.kind { @@ -206,7 +205,7 @@ impl<'a> Parser<'a> { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac)); let e = self.maybe_recover_from_bad_qpath(e)?; - let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?; + let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?; let e = self .parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?; StmtKind::Expr(e) @@ -236,16 +235,13 @@ impl<'a> Parser<'a> { lo: Span, attrs: AttrWrapper, subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub, + force_collect: ForceCollect, ) -> PResult<'a, Stmt> { - let stmt = - self.collect_tokens_trailing_token(attrs, ForceCollect::Yes, |this, attrs| { - let local = this.parse_local(attrs)?; - // FIXME - maybe capture semicolon in recovery? - Ok(( - this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), - TrailingToken::None, - )) - })?; + let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { + let local = this.parse_local(attrs)?; + // FIXME - maybe capture semicolon in recovery? + Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), false)) + })?; self.dcx() .emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) }); Ok(stmt) @@ -261,11 +257,7 @@ impl<'a> Parser<'a> { self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| { this.expect_keyword(kw::Let)?; let local = this.parse_local(attrs)?; - let trailing = if capture_semi && this.token.kind == token::Semi { - TrailingToken::Semi - } else { - TrailingToken::None - }; + let trailing = capture_semi && this.token.kind == token::Semi; Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing)) }) } diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index cf791d332a2..491aa71155a 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1522,7 +1522,7 @@ fn debug_lookahead() { }, }, tokens: [], - approx_token_stream_pos: 1, + approx_token_stream_pos: 0, .. }" ); @@ -1566,7 +1566,7 @@ fn debug_lookahead() { Parenthesis, ), ], - approx_token_stream_pos: 1, + approx_token_stream_pos: 0, .. }" ); @@ -1631,7 +1631,7 @@ fn debug_lookahead() { Semi, Eof, ], - approx_token_stream_pos: 1, + approx_token_stream_pos: 0, .. }" ); @@ -1663,7 +1663,7 @@ fn debug_lookahead() { No, ), ], - approx_token_stream_pos: 9, + approx_token_stream_pos: 8, .. }" ); @@ -1701,7 +1701,7 @@ fn debug_lookahead() { No, ), ], - approx_token_stream_pos: 9, + approx_token_stream_pos: 8, .. }" ); @@ -1728,7 +1728,7 @@ fn debug_lookahead() { tokens: [ Eof, ], - approx_token_stream_pos: 15, + approx_token_stream_pos: 14, .. }" ); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 94321b1dddd..a8134110010 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -21,6 +21,11 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use thin_vec::{thin_vec, ThinVec}; +/// Signals whether parsing a type should allow `+`. +/// +/// For example, let T be the type `impl Default + 'static` +/// With `AllowPlus::Yes`, T will be parsed successfully +/// With `AllowPlus::No`, parsing T will return a parse error #[derive(Copy, Clone, PartialEq)] pub(super) enum AllowPlus { Yes, @@ -1230,6 +1235,12 @@ impl<'a> Parser<'a> { /// Parses a single lifetime `'a` or panics. pub(super) fn expect_lifetime(&mut self) -> Lifetime { if let Some(ident) = self.token.lifetime() { + if ident.without_first_quote().is_reserved() + && ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name) + { + self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); + } + self.bump(); Lifetime { ident, id: ast::DUMMY_NODE_ID } } else { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 0720efebf97..fb7529d93ed 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -452,7 +452,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { match ga { hir::GenericArg::Lifetime(lt) => self.visit_lifetime(lt), hir::GenericArg::Type(ty) => self.visit_ty(ty), - hir::GenericArg::Const(ct) => self.visit_anon_const(&ct.value), + hir::GenericArg::Const(ct) => self.visit_const_arg(ct), hir::GenericArg::Infer(inf) => self.visit_infer(inf), } } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index c9590ad06b0..1b4bcb789d2 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -21,9 +21,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } use std::fmt; -// Re-exports to avoid rustc_index version issues. -pub use rustc_index::Idx; -pub use rustc_index::IndexVec; +pub use rustc_index::{Idx, IndexVec}; // re-exported to avoid rustc_index version issues #[cfg(feature = "rustc")] use rustc_middle::ty::Ty; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d4dd4dd858c..d17ee8bff50 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -462,7 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // This is a box pattern. ty::Adt(adt, ..) if adt.is_box() => Struct, ty::Ref(..) => Ref, - _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), + _ => span_bug!( + pat.span, + "pattern has unexpected type: pat: {:?}, ty: {:?}", + pat.kind, + ty.inner() + ), }; } PatKind::DerefPattern { .. } => { @@ -518,7 +523,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { .map(|ipat| self.lower_pat(&ipat.pattern).at_index(ipat.field.index())) .collect(); } - _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, ty), + _ => span_bug!( + pat.span, + "pattern has unexpected type: pat: {:?}, ty: {}", + pat.kind, + ty.inner() + ), } } PatKind::Constant { value } => { @@ -663,7 +673,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } } } - _ => bug!("invalid type for range pattern: {}", ty.inner()), + _ => span_bug!(pat.span, "invalid type for range pattern: {}", ty.inner()), }; fields = vec![]; arity = 0; @@ -674,7 +684,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { Some(length.eval_target_usize(cx.tcx, cx.param_env) as usize) } ty::Slice(_) => None, - _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", ty), + _ => span_bug!(pat.span, "bad ty {} for slice pattern", ty.inner()), }; let kind = if slice.is_some() { SliceKind::VarLen(prefix.len(), suffix.len()) diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 4d845ab0d07..2f42fa47728 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -26,5 +26,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon-core"] +rustc_use_parallel_compiler = ["dep:rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 4b9c36ad39f..73d1a2ea49a 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -232,6 +232,8 @@ resolve_is_private = resolve_item_was_behind_feature = the item is gated behind the `{$feature}` feature +resolve_item_was_cfg_out = the item is gated here + resolve_items_in_traits_are_not_importable = items in traits are not importable diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 92cf73870ff..ced5ac17dac 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -316,7 +316,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn insert_field_def_ids(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) { + fn insert_field_idents(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) { if fields.iter().any(|field| field.is_placeholder) { // The fields are not expanded yet. return; @@ -652,7 +652,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let def_id = feed.key(); // Record field names for error reporting. - self.insert_field_def_ids(def_id, fields); + self.insert_field_idents(def_id, fields); self.insert_field_visibilities_local(def_id.to_def_id(), fields); for field in fields { @@ -1520,7 +1520,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // Record field names for error reporting. - self.insert_field_def_ids(def_id, variant.data.fields()); + self.insert_field_idents(def_id, variant.data.fields()); self.insert_field_visibilities_local(def_id.to_def_id(), variant.data.fields()); visit::walk_variant(self, variant); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index a4fdb4a0baf..1fb942de734 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -312,8 +312,19 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let def = self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + // HACK(min_generic_const_args): don't create defs for anon consts if we think they will + // later be turned into ConstArgKind::Path's. because this is before resolve is done, we + // may accidentally identify a construction of a unit struct as a param and not create a + // def. we'll then create a def later in ast lowering in this case. the parent of nested + // items will be messed up, but that's ok because there can't be any if we're just looking + // for bare idents. + if constant.value.is_potential_trivial_const_arg() { + visit::walk_anon_const(self, constant) + } else { + let def = + self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); + self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + } } fn visit_expr(&mut self, expr: &'a Expr) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3917acce65..7c0405c87e0 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -371,6 +371,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; let mut suggestion = None; + let mut span = binding_span; match import.kind { ImportKind::Single { type_ns_only: true, .. } => { suggestion = Some(format!("self as {suggested_name}")) @@ -381,12 +382,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) { if pos <= snippet.len() { - suggestion = Some(format!( - "{} as {}{}", - &snippet[..pos], - suggested_name, - if snippet.ends_with(';') { ";" } else { "" } - )) + span = binding_span + .with_lo(binding_span.lo() + BytePos(pos as u32)) + .with_hi( + binding_span.hi() + - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), + ); + suggestion = Some(format!(" as {suggested_name}")); } } } @@ -402,9 +404,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } if let Some(suggestion) = suggestion { - err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion }); + err.subdiagnostic(ChangeImportBindingSuggestion { span, suggestion }); } else { - err.subdiagnostic(ChangeImportBinding { span: binding_span }); + err.subdiagnostic(ChangeImportBinding { span }); } } @@ -2530,7 +2532,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && let NestedMetaItem::MetaItem(meta_item) = &nested[0] && let MetaItemKind::NameValue(feature_name) = &meta_item.kind { - let note = errors::ItemWasBehindFeature { feature: feature_name.symbol }; + let note = errors::ItemWasBehindFeature { + feature: feature_name.symbol, + span: meta_item.span, + }; + err.subdiagnostic(note); + } else { + let note = errors::ItemWasCfgOut { span: cfg.span }; err.subdiagnostic(note); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 097f4af05c3..0a68231c6fe 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1228,6 +1228,15 @@ pub(crate) struct FoundItemConfigureOut { #[note(resolve_item_was_behind_feature)] pub(crate) struct ItemWasBehindFeature { pub(crate) feature: Symbol, + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[note(resolve_item_was_cfg_out)] +pub(crate) struct ItemWasCfgOut { + #[primary_span] + pub(crate) span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 1d37264f96a..dc7200465d9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2175,13 +2175,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Handle `self` specially. if index == 0 && has_self { let self_lifetime = self.find_lifetime_for_self(ty); - if let Set1::One(lifetime) = self_lifetime { + elision_lifetime = match self_lifetime { // We found `self` elision. - elision_lifetime = Elision::Self_(lifetime); - } else { + Set1::One(lifetime) => Elision::Self_(lifetime), + // `self` itself had ambiguous lifetimes, e.g. + // &Box<&Self>. In this case we won't consider + // taking an alternative parameter lifetime; just avoid elision + // entirely. + Set1::Many => Elision::Err, // We do not have `self` elision: disregard the `Elision::Param` that we may // have found. - elision_lifetime = Elision::None; + Set1::Empty => Elision::None, } } debug!("(resolving function / closure) recorded parameter"); @@ -2201,15 +2205,55 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// List all the lifetimes that appear in the provided type. fn find_lifetime_for_self(&self, ty: &'ast Ty) -> Set1<LifetimeRes> { - struct SelfVisitor<'r, 'a, 'tcx> { + /// Visits a type to find all the &references, and determines the + /// set of lifetimes for all of those references where the referent + /// contains Self. + struct FindReferenceVisitor<'r, 'a, 'tcx> { r: &'r Resolver<'a, 'tcx>, impl_self: Option<Res>, lifetime: Set1<LifetimeRes>, } + impl<'a> Visitor<'a> for FindReferenceVisitor<'_, '_, '_> { + fn visit_ty(&mut self, ty: &'a Ty) { + trace!("FindReferenceVisitor considering ty={:?}", ty); + if let TyKind::Ref(lt, _) = ty.kind { + // See if anything inside the &thing contains Self + let mut visitor = + SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false }; + visitor.visit_ty(ty); + trace!("FindReferenceVisitor: SelfVisitor self_found={:?}", visitor.self_found); + if visitor.self_found { + let lt_id = if let Some(lt) = lt { + lt.id + } else { + let res = self.r.lifetimes_res_map[&ty.id]; + let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; + start + }; + let lt_res = self.r.lifetimes_res_map[<_id]; + trace!("FindReferenceVisitor inserting res={:?}", lt_res); + self.lifetime.insert(lt_res); + } + } + visit::walk_ty(self, ty) + } + + // A type may have an expression as a const generic argument. + // We do not want to recurse into those. + fn visit_expr(&mut self, _: &'a Expr) {} + } + + /// Visitor which checks the referent of a &Thing to see if the + /// Thing contains Self + struct SelfVisitor<'r, 'a, 'tcx> { + r: &'r Resolver<'a, 'tcx>, + impl_self: Option<Res>, + self_found: bool, + } + impl SelfVisitor<'_, '_, '_> { - // Look for `self: &'a Self` - also desugared from `&'a self`, - // and if that matches, use it for elision and return early. + // Look for `self: &'a Self` - also desugared from `&'a self` fn is_self_ty(&self, ty: &Ty) -> bool { match ty.kind { TyKind::ImplicitSelf => true, @@ -2228,19 +2272,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> { fn visit_ty(&mut self, ty: &'a Ty) { trace!("SelfVisitor considering ty={:?}", ty); - if let TyKind::Ref(lt, ref mt) = ty.kind - && self.is_self_ty(&mt.ty) - { - let lt_id = if let Some(lt) = lt { - lt.id - } else { - let res = self.r.lifetimes_res_map[&ty.id]; - let LifetimeRes::ElidedAnchor { start, .. } = res else { bug!() }; - start - }; - let lt_res = self.r.lifetimes_res_map[<_id]; - trace!("SelfVisitor inserting res={:?}", lt_res); - self.lifetime.insert(lt_res); + if self.is_self_ty(ty) { + trace!("SelfVisitor found Self"); + self.self_found = true; } visit::walk_ty(self, ty) } @@ -2271,9 +2305,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum, _,) | Res::PrimTy(_) ) }); - let mut visitor = SelfVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; + let mut visitor = FindReferenceVisitor { r: self.r, impl_self, lifetime: Set1::Empty }; visitor.visit_ty(ty); - trace!("SelfVisitor found={:?}", visitor.lifetime); + trace!("FindReferenceVisitor found={:?}", visitor.lifetime); visitor.lifetime } 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 f0f2d1fefd2..9b05576d721 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 @@ -9,10 +9,10 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{ - self, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, - TypeVisitableExt, UintTy, + self, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy, List, TraitRef, Ty, + TyCtxt, TypeFoldable, TypeVisitableExt, UintTy, }; -use rustc_span::sym; +use rustc_span::{def_id::DefId, sym}; use rustc_trait_selection::traits; use std::iter; use tracing::{debug, instrument}; @@ -360,41 +360,29 @@ pub fn transform_instance<'tcx>( if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) { // Perform type erasure for calls on trait objects by transforming self into a trait object // of the trait that defines the method. - if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) - && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) - { - let impl_method = tcx.associated_item(instance.def_id()); - let method_id = impl_method - .trait_item_def_id - .expect("Part of a trait implementation, but not linked to the def_id?"); - let trait_method = tcx.associated_item(method_id); - let trait_id = trait_ref.skip_binder().def_id; - if traits::is_vtable_safe_method(tcx, trait_id, trait_method) - && tcx.is_object_safe(trait_id) - { - // Trait methods will have a Self polymorphic parameter, where the concreteized - // implementatation will not. We need to walk back to the more general trait method - let trait_ref = tcx.instantiate_and_normalize_erasing_regions( - instance.args, - ty::ParamEnv::reveal_all(), - trait_ref, - ); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + if let Some((trait_ref, method_id, ancestor)) = implemented_method(tcx, instance) { + // Trait methods will have a Self polymorphic parameter, where the concreteized + // implementatation will not. We need to walk back to the more general trait method + let trait_ref = tcx.instantiate_and_normalize_erasing_regions( + instance.args, + ty::ParamEnv::reveal_all(), + trait_ref, + ); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - // At the call site, any call to this concrete function through a vtable will be - // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the - // original method id, and we've recovered the trait arguments, we can make the callee - // instance we're computing the alias set for match the caller instance. - // - // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. - // If we ever *do* start encoding the vtable index, we will need to generate an alias set - // based on which vtables we are putting this method into, as there will be more than one - // index value when supertraits are involved. - instance.def = ty::InstanceKind::Virtual(method_id, 0); - let abstract_trait_args = - tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); - } + // At the call site, any call to this concrete function through a vtable will be + // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the + // original method id, and we've recovered the trait arguments, we can make the callee + // instance we're computing the alias set for match the caller instance. + // + // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. + // If we ever *do* start encoding the vtable index, we will need to generate an alias set + // based on which vtables we are putting this method into, as there will be more than one + // index value when supertraits are involved. + instance.def = ty::InstanceKind::Virtual(method_id, 0); + let abstract_trait_args = + tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + instance.args = instance.args.rebase_onto(tcx, ancestor, abstract_trait_args); } else if tcx.is_closure_like(instance.def_id()) { // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, // instantiate it, and take the type of its only method as our own. @@ -452,3 +440,36 @@ pub fn transform_instance<'tcx>( instance } + +fn implemented_method<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> Option<(ty::EarlyBinder<'tcx, TraitRef<'tcx>>, DefId, DefId)> { + let trait_ref; + let method_id; + let trait_id; + let trait_method; + let ancestor = if let Some(impl_id) = tcx.impl_of_method(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?; + trait_method = tcx.associated_item(method_id); + trait_id = trait_ref.skip_binder().def_id; + impl_id + } else if let InstanceKind::Item(def_id) = instance.def + && let Some(trait_method_bound) = tcx.opt_associated_item(def_id) + { + // Provided method in a `trait` block + trait_method = trait_method_bound; + method_id = instance.def_id(); + trait_id = tcx.trait_of_item(method_id)?; + trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args)); + trait_id + } else { + return None; + }; + let vtable_possible = + traits::is_vtable_safe_method(tcx, trait_id, trait_method) && tcx.is_object_safe(trait_id); + vtable_possible.then_some((trait_ref, method_id, ancestor)) +} diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 7c3553b60fd..854295dc048 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -4,6 +4,7 @@ //! due to incomplete stable coverage. // Prefer importing stable_mir over internal rustc constructs to make this file more readable. + use crate::rustc_smir::Tables; use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy, TyCtxt}; use rustc_span::Symbol; diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 7da7dc610ec..d9e1ebaf0bc 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -35,25 +35,25 @@ pub fn analyze_source_file( cfg_match! { cfg(any(target_arch = "x86", target_arch = "x86_64")) => { - fn analyze_source_file_dispatch(src: &str, - lines: &mut Vec<RelativeBytePos>, - multi_byte_chars: &mut Vec<MultiByteChar>, - non_narrow_chars: &mut Vec<NonNarrowChar>) { + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + non_narrow_chars: &mut Vec<NonNarrowChar>, + ) { if is_x86_feature_detected!("sse2") { unsafe { - analyze_source_file_sse2(src, - lines, - multi_byte_chars, - non_narrow_chars); + analyze_source_file_sse2(src, lines, multi_byte_chars, non_narrow_chars); } } else { - analyze_source_file_generic(src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - non_narrow_chars); - + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } @@ -62,10 +62,12 @@ cfg_match! { /// function falls back to the generic implementation. Otherwise it uses /// SSE2 intrinsics to quickly find all newlines. #[target_feature(enable = "sse2")] - unsafe fn analyze_source_file_sse2(src: &str, - lines: &mut Vec<RelativeBytePos>, - multi_byte_chars: &mut Vec<MultiByteChar>, - non_narrow_chars: &mut Vec<NonNarrowChar>) { + unsafe fn analyze_source_file_sse2( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + non_narrow_chars: &mut Vec<NonNarrowChar>, + ) { #[cfg(target_arch = "x86")] use std::arch::x86::*; #[cfg(target_arch = "x86_64")] @@ -83,17 +85,17 @@ cfg_match! { // handled it. let mut intra_chunk_offset = 0; - for chunk_index in 0 .. chunk_count { + for chunk_index in 0..chunk_count { let ptr = src_bytes.as_ptr() as *const __m128i; // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = _mm_loadu_si128(ptr.add(chunk_index)); + let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) }; // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. - let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); + let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) }; // Create a bit mask from the comparison results. - let multibyte_mask = _mm_movemask_epi8(multibyte_test); + let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) }; // If the bit mask is all zero, we only have ASCII chars here: if multibyte_mask == 0 { @@ -102,19 +104,19 @@ cfg_match! { // Check if there are any control characters in the chunk. All // control characters that we can encounter at this point have a // byte value less than 32 or ... - let control_char_test0 = _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)); - let control_char_mask0 = _mm_movemask_epi8(control_char_test0); + let control_char_test0 = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(32)) }; + let control_char_mask0 = unsafe { _mm_movemask_epi8(control_char_test0) }; // ... it's the ASCII 'DEL' character with a value of 127. - let control_char_test1 = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)); - let control_char_mask1 = _mm_movemask_epi8(control_char_test1); + let control_char_test1 = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(127)) }; + let control_char_mask1 = unsafe { _mm_movemask_epi8(control_char_test1) }; let control_char_mask = control_char_mask0 | control_char_mask1; if control_char_mask != 0 { // Check for newlines in the chunk - let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); - let newlines_mask = _mm_movemask_epi8(newlines_test); + let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) }; + let newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) }; if control_char_mask == newlines_mask { // All control characters are newlines, record them @@ -126,7 +128,7 @@ cfg_match! { if index >= CHUNK_SIZE as u32 { // We have arrived at the end of the chunk. - break + break; } lines.push(RelativeBytePos(index) + output_offset); @@ -137,14 +139,14 @@ cfg_match! { // We are done for this chunk. All control characters were // newlines and we took care of those. - continue + continue; } else { // Some of the control characters are not newlines, // fall through to the slow path below. } } else { // No control characters, nothing to record for this chunk - continue + continue; } } @@ -152,43 +154,48 @@ cfg_match! { // There are control chars in here, fallback to generic decoding. let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; intra_chunk_offset = analyze_source_file_generic( - &src[scan_start .. ], + &src[scan_start..], CHUNK_SIZE - intra_chunk_offset, RelativeBytePos::from_usize(scan_start), lines, multi_byte_chars, - non_narrow_chars + non_narrow_chars, ); } // There might still be a tail left to analyze let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; if tail_start < src.len() { - analyze_source_file_generic(&src[tail_start ..], - src.len() - tail_start, - RelativeBytePos::from_usize(tail_start), - lines, - multi_byte_chars, - non_narrow_chars); + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + RelativeBytePos::from_usize(tail_start), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } } _ => { // The target (or compiler version) does not support SSE2 ... - fn analyze_source_file_dispatch(src: &str, - lines: &mut Vec<RelativeBytePos>, - multi_byte_chars: &mut Vec<MultiByteChar>, - non_narrow_chars: &mut Vec<NonNarrowChar>) { - analyze_source_file_generic(src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - non_narrow_chars); + fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec<RelativeBytePos>, + multi_byte_chars: &mut Vec<MultiByteChar>, + non_narrow_chars: &mut Vec<NonNarrowChar>, + ) { + analyze_source_file_generic( + src, + src.len(), + RelativeBytePos::from_u32(0), + lines, + multi_byte_chars, + non_narrow_chars, + ); } } } - // `scan_len` determines the number of bytes in `src` to scan. Note that the // function can read past `scan_len` if a multi-byte character start within the // range but extends past it. The overflow is returned by the function. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2fe7c951793..b64efadb261 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1926,6 +1926,7 @@ symbols! { type_ascription, type_changing_struct_update, type_id, + type_ir_inherent, type_length_limit, type_macros, type_name, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 4c67fa0f7aa..549706998d4 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -18,9 +18,7 @@ pub fn target() -> Target { relro_level: RelroLevel::Full, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - features: - "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" - .into(), + features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(), supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, disable_redzone: true, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index c301deac616..deab0451ccb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -8,7 +8,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor as _; use rustc_hir::LangItem; -use rustc_infer::infer::error_reporting::{TypeAnnotationNeeded, TypeErrCtxt}; +use rustc_infer::error_reporting::infer::TypeErrCtxt; +use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{ 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 2e6247b4640..0d040ddbacb 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 @@ -4,7 +4,6 @@ use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; -use crate::infer::error_reporting::TyCategory; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -25,7 +24,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TyCategory; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; use rustc_macros::extension; use rustc_middle::traits::select::OverflowError; 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 2131e236401..16dfa27b75a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index e90fe8fb94d..a448e1924c8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -3,7 +3,6 @@ use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; -use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::InferCtxtExt; use rustc_ast::AttrArgs; use rustc_ast::AttrArgsEq; @@ -14,6 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_macros::{extension, LintDiagnostic}; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; 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 061a5a4be20..fe1771f9096 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -5,7 +5,7 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_macros::extension; use rustc_middle::ty::print::{FmtPrinter, Print}; 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 2cf808f962f..fa2acdd4a54 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -23,7 +23,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; -use rustc_infer::infer::error_reporting::TypeErrCtxt; +use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; @@ -466,7 +466,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) { // Suggest dereferencing the argument to a function/method call if possible - let mut real_trait_pred = trait_pred; while let Some((parent_code, parent_trait_pred)) = code.parent() { code = parent_code; @@ -553,6 +552,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); if self.predicate_may_hold(&obligation) && self.predicate_must_hold_modulo_regions(&sized_obligation) + // Do not suggest * if it is already a reference, + // will suggest removing the borrow instead in that case. + && !matches!(expr.kind, hir::ExprKind::AddrOf(..)) { let call_node = self.tcx.hir_node(*call_hir_id); let msg = "consider dereferencing here"; @@ -3810,6 +3812,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { if let Some(where_pred) = where_pred.as_trait_clause() && let Some(failed_pred) = failed_pred.as_trait_clause() + && where_pred.def_id() == failed_pred.def_id() { self.enter_forall(where_pred, |where_pred| { let failed_pred = self.instantiate_binder_with_fresh_vars( diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index f67518a577e..ade26a40920 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -87,12 +87,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< ) -> Option<ty::Const<'tcx>> { use rustc_middle::mir::interpret::ErrorHandled; match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value( + Ok(Ok(val)) => Some(ty::Const::new_value( self.tcx, val, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), )), - Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, + Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())), } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1d32ef2ccd9..796f7fd5a54 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -765,8 +765,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { unevaluated, obligation.cause.span, ) { - Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), - Ok(None) => { + Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), + Ok(Err(_)) => { let tcx = self.tcx; let reported = tcx.dcx().emit_err(UnableToConstructConstantValue { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d28982ed849..f7eb1730582 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -16,7 +16,6 @@ pub mod query; #[allow(hidden_glob_reexports)] mod select; mod specialize; -mod structural_match; mod structural_normalize; #[allow(hidden_glob_reexports)] mod util; @@ -60,7 +59,6 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{ specialization_graph, translate_args, translate_args_with_cause, OverlapError, }; -pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo}; diff --git a/compiler/rustc_trait_selection/src/traits/select/_match.rs b/compiler/rustc_trait_selection/src/traits/select/_match.rs index 50d8e96aaf9..7ead65721f9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/_match.rs +++ b/compiler/rustc_trait_selection/src/traits/select/_match.rs @@ -3,7 +3,7 @@ use rustc_infer::infer::relate::{ }; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; -use tracing::{debug, instrument}; +use tracing::instrument; /// A type "A" *matches* "B" if the fresh types in B could be /// instantiated with values so as to make it equal to A. Matching is @@ -32,11 +32,7 @@ impl<'tcx> MatchAgainstFreshVars<'tcx> { } impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { - fn tag(&self) -> &'static str { - "MatchAgainstFreshVars" - } - - fn tcx(&self) -> TyCtxt<'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -50,7 +46,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { self.relate(a, b) } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, @@ -59,7 +55,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { Ok(a) } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "trace")] fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { if a == b { return Ok(a); @@ -77,18 +73,18 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), + (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.cx(), guar)), _ => structurally_relate_tys(self, a, b), } } + #[instrument(skip(self), level = "trace")] fn consts( &mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.consts({:?}, {:?})", self.tag(), a, b); if a == b { return Ok(a); } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs deleted file mode 100644 index d4535db951e..00000000000 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ /dev/null @@ -1,173 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_middle::bug; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use std::ops::ControlFlow; - -/// This method traverses the structure of `ty`, trying to find an -/// instance of an ADT (i.e. struct or enum) that doesn't implement -/// the structural-match traits, or a generic type parameter -/// (which cannot be determined to be structural-match). -/// -/// The "structure of a type" includes all components that would be -/// considered when doing a pattern match on a constant of that -/// type. -/// -/// * This means this method descends into fields of structs/enums, -/// and also descends into the inner type `T` of `&T` and `&mut T` -/// -/// * The traversal doesn't dereference unsafe pointers (`*const T`, -/// `*mut T`), and it does not visit the type arguments of an -/// instantiated generic like `PhantomData<T>`. -/// -/// The reason we do this search is Rust currently require all ADTs -/// reachable from a constant's type to implement the -/// structural-match traits, which essentially say that -/// the implementation of `PartialEq::eq` behaves *equivalently* to a -/// comparison against the unfolded structure. -/// -/// For more background on why Rust has this requirement, and issues -/// that arose when the requirement was not enforced completely, see -/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. -pub fn search_for_structural_match_violation<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option<Ty<'tcx>> { - ty.visit_with(&mut Search { tcx, seen: FxHashSet::default() }).break_value() -} - -/// This implements the traversal over the structure of a given type to try to -/// find instances of ADTs (specifically structs or enums) that do not implement -/// `StructuralPartialEq`. -struct Search<'tcx> { - tcx: TyCtxt<'tcx>, - - /// Tracks ADTs previously encountered during search, so that - /// we will not recur on them again. - seen: FxHashSet<hir::def_id::DefId>, -} - -impl<'tcx> Search<'tcx> { - fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { - adt_ty.is_structural_eq_shallow(self.tcx) - } -} - -impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { - type Result = ControlFlow<Ty<'tcx>>; - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - debug!("Search visiting ty: {:?}", ty); - - let (adt_def, args) = match *ty.kind() { - ty::Adt(adt_def, args) => (adt_def, args), - ty::Param(_) => { - return ControlFlow::Break(ty); - } - ty::Dynamic(..) => { - return ControlFlow::Break(ty); - } - ty::Foreign(_) => { - return ControlFlow::Break(ty); - } - ty::Alias(..) => { - return ControlFlow::Break(ty); - } - ty::Closure(..) => { - return ControlFlow::Break(ty); - } - ty::CoroutineClosure(..) => { - return ControlFlow::Break(ty); - } - ty::Coroutine(..) | ty::CoroutineWitness(..) => { - return ControlFlow::Break(ty); - } - ty::FnDef(..) => { - // Types of formals and return in `fn(_) -> _` are also irrelevant; - // so we do not recur into them via `super_visit_with` - return ControlFlow::Continue(()); - } - ty::Array(_, n) - if { n.try_eval_target_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } => - { - // rust-lang/rust#62336: ignore type of contents - // for empty array. - return ControlFlow::Continue(()); - } - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => { - // These primitive types are always structural match. - // - // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - return ControlFlow::Continue(()); - } - - ty::FnPtr(..) => { - return ControlFlow::Continue(()); - } - - ty::RawPtr(..) => { - // structural-match ignores substructure of - // `*const _`/`*mut _`, so skip `super_visit_with`. - // - // For example, if you have: - // ``` - // struct NonStructural; - // #[derive(PartialEq, Eq)] - // struct T(*const NonStructural); - // const C: T = T(std::ptr::null()); - // ``` - // - // Even though `NonStructural` does not implement `PartialEq`, - // structural equality on `T` does not recur into the raw - // pointer. Therefore, one can still use `C` in a pattern. - return ControlFlow::Continue(()); - } - - ty::Float(_) => { - return ControlFlow::Continue(()); - } - - ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { - // First check all contained types and then tell the caller to continue searching. - return ty.super_visit_with(self); - } - ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { - bug!("unexpected type during structural-match checking: {:?}", ty); - } - ty::Error(_) => { - // We still want to check other types after encountering an error, - // as this may still emit relevant errors. - return ControlFlow::Continue(()); - } - }; - - if !self.seen.insert(adt_def.did()) { - debug!("Search already seen adt_def: {:?}", adt_def); - return ControlFlow::Continue(()); - } - - if !self.type_marked_structural(ty) { - debug!("Search found ty: {:?}", ty); - return ControlFlow::Break(ty); - } - - // structural-match does not care about the - // instantiation of the generics in an ADT (it - // instead looks directly at its fields outside - // this match), so we skip super_visit_with. - // - // (Must not recur on args for `PhantomData<T>` cf - // rust-lang/rust#55028 and rust-lang/rust#55837; but also - // want to skip args when only uses of generic are - // behind unsafe pointers `*const T`/`*mut T`.) - - // even though we skip super_visit_with, we must recur on - // fields of ADT. - let tcx = self.tcx; - adt_def.all_fields().map(|field| field.ty(tcx, args)).try_for_each(|field_ty| { - let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); - debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - ty.visit_with(self) - }) - } -} diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 8f56f9c0f3e..4645d828461 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -364,7 +364,9 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe } /// Given a `dyn Subtrait` and `dyn Supertrait` trait object, find the slot of -/// // the trait vptr in the subtrait's vtable. +/// the trait vptr in the subtrait's vtable. +/// +/// A return value of `None` means that the original vtable can be reused. pub(crate) fn supertrait_vtable_slot<'tcx>( tcx: TyCtxt<'tcx>, key: ( @@ -373,20 +375,22 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( ), ) -> Option<usize> { debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); - let (source, target) = key; - let ty::Dynamic(source, _, _) = *source.kind() else { + + // If the target principal is `None`, we can just return `None`. + let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let source_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) + let target_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?) .with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let ty::Dynamic(target, _, _) = *target.kind() else { + // Given that we have a target principal, it is a bug for there not to be a source principal. + let ty::Dynamic(source, _, _) = *source.kind() else { bug!(); }; - let target_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal().unwrap()) + let source_principal = tcx + .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) .with_self_ty(tcx, tcx.types.trait_object_dummy_self); let vtable_segment_callback = { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f071dc6c784..e77a05dd8e6 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -672,9 +672,21 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); } - ty::Array(subty, _) => { + ty::Array(subty, len) => { self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); - // Note that we handle the len is implicitly checked while walking `arg`. + // Note that the len being WF is implicitly checked while visiting. + // Here we just check that it's of type usize. + let cause = self.cause(ObligationCauseCode::Misc); + self.out.push(traits::Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType( + len, + tcx.types.usize, + ))), + )); } ty::Pat(subty, _) => { diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 79939d62a51..4732e968f6b 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -18,13 +18,13 @@ tracing = "0.1" [features] rustc = [ - "rustc_hir", - "rustc_infer", - "rustc_macros", - "rustc_middle", - "rustc_span", - "rustc_target", - "rustc_ast_ir", + "dep:rustc_hir", + "dep:rustc_infer", + "dep:rustc_macros", + "dep:rustc_middle", + "dep:rustc_span", + "dep:rustc_target", + "dep:rustc_ast_ir", ] [dev-dependencies] diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index e4bf6069caf..769e350b835 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -22,12 +22,12 @@ tracing = "0.1" [features] default = ["nightly"] nightly = [ + "dep:rustc_serialize", + "dep:rustc_span", + "dep:rustc_data_structures", + "dep:rustc_macros", "smallvec/may_dangle", "smallvec/union", "rustc_index/nightly", - "rustc_serialize", - "rustc_span", - "rustc_data_structures", - "rustc_macros", "rustc_ast_ir/nightly" ] diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 2531219baec..17b35a2807a 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -49,10 +49,10 @@ where { type Lifted = Binder<U, T::Lifted>; - fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> { + fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> { Some(Binder { - value: self.value.lift_to_tcx(tcx)?, - bound_vars: self.bound_vars.lift_to_tcx(tcx)?, + value: self.value.lift_to_interner(cx)?, + bound_vars: self.bound_vars.lift_to_interner(cx)?, }) } } @@ -439,11 +439,11 @@ impl<I: Interner, Iter: IntoIterator> EarlyBinder<I, Iter> where Iter::Item: TypeFoldable<I>, { - pub fn iter_instantiated<A>(self, tcx: I, args: A) -> IterInstantiated<I, Iter, A> + pub fn iter_instantiated<A>(self, cx: I, args: A) -> IterInstantiated<I, Iter, A> where A: SliceLike<Item = I::GenericArg>, { - IterInstantiated { it: self.value.into_iter(), tcx, args } + IterInstantiated { it: self.value.into_iter(), cx, args } } /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), @@ -455,7 +455,7 @@ where pub struct IterInstantiated<I: Interner, Iter: IntoIterator, A> { it: Iter::IntoIter, - tcx: I, + cx: I, args: A, } @@ -469,7 +469,7 @@ where fn next(&mut self) -> Option<Self::Item> { Some( EarlyBinder { value: self.it.next()?, _tcx: PhantomData } - .instantiate(self.tcx, self.args), + .instantiate(self.cx, self.args), ) } @@ -487,7 +487,7 @@ where fn next_back(&mut self) -> Option<Self::Item> { Some( EarlyBinder { value: self.it.next_back()?, _tcx: PhantomData } - .instantiate(self.tcx, self.args), + .instantiate(self.cx, self.args), ) } } @@ -507,10 +507,10 @@ where { pub fn iter_instantiated_copied( self, - tcx: I, + cx: I, args: &'s [I::GenericArg], ) -> IterInstantiatedCopied<'s, I, Iter> { - IterInstantiatedCopied { it: self.value.into_iter(), tcx, args } + IterInstantiatedCopied { it: self.value.into_iter(), cx, args } } /// Similar to [`instantiate_identity`](EarlyBinder::instantiate_identity), @@ -522,7 +522,7 @@ where pub struct IterInstantiatedCopied<'a, I: Interner, Iter: IntoIterator> { it: Iter::IntoIter, - tcx: I, + cx: I, args: &'a [I::GenericArg], } @@ -535,7 +535,7 @@ where fn next(&mut self) -> Option<Self::Item> { self.it.next().map(|value| { - EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.cx, self.args) }) } @@ -552,7 +552,7 @@ where { fn next_back(&mut self) -> Option<Self::Item> { self.it.next_back().map(|value| { - EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.tcx, self.args) + EarlyBinder { value: *value, _tcx: PhantomData }.instantiate(self.cx, self.args) }) } } @@ -589,11 +589,11 @@ impl<I: Interner, T: Iterator> Iterator for EarlyBinderIter<I, T> { } impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> { - pub fn instantiate<A>(self, tcx: I, args: A) -> T + pub fn instantiate<A>(self, cx: I, args: A) -> T where A: SliceLike<Item = I::GenericArg>, { - let mut folder = ArgFolder { tcx, args: args.as_slice(), binders_passed: 0 }; + let mut folder = ArgFolder { cx, args: args.as_slice(), binders_passed: 0 }; self.value.fold_with(&mut folder) } @@ -619,7 +619,7 @@ impl<I: Interner, T: TypeFoldable<I>> ty::EarlyBinder<I, T> { // The actual instantiation engine itself is a type folder. struct ArgFolder<'a, I: Interner> { - tcx: I, + cx: I, args: &'a [I::GenericArg], /// Number of region binders we have passed through while doing the instantiation @@ -629,7 +629,7 @@ struct ArgFolder<'a, I: Interner> { impl<'a, I: Interner> TypeFolder<I> for ArgFolder<'a, I> { #[inline] fn cx(&self) -> I { - self.tcx + self.cx } fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> { @@ -858,6 +858,6 @@ impl<'a, I: Interner> ArgFolder<'a, I> { if self.binders_passed == 0 || !region.has_escaping_bound_vars() { return region; } - ty::fold::shift_region(self.tcx, region, self.binders_passed) + ty::fold::shift_region(self.cx, region, self.binders_passed) } } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 7b114f565f2..a9252711b2b 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -330,25 +330,25 @@ impl<I: Interner> CanonicalVarValues<I> { // Given a list of canonical variables, construct a set of values which are // the identity response. - pub fn make_identity(tcx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> { + pub fn make_identity(cx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> { CanonicalVarValues { - var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map( + var_values: cx.mk_args_from_iter(infos.iter().enumerate().map( |(i, info)| -> I::GenericArg { match info.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => { - Ty::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => { - Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Effect => { - Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { - Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } } diff --git a/compiler/rustc_type_ir/src/effects.rs b/compiler/rustc_type_ir/src/effects.rs index f7942f2f982..a29e0a43bef 100644 --- a/compiler/rustc_type_ir/src/effects.rs +++ b/compiler/rustc_type_ir/src/effects.rs @@ -1,4 +1,4 @@ -use crate::inherent::{AdtDef, IntoKind, Ty}; +use crate::inherent::*; use crate::lang_items::TraitSolverLangItem::{EffectsMaybe, EffectsNoRuntime, EffectsRuntime}; use crate::Interner; @@ -10,38 +10,38 @@ pub enum EffectKind { } impl EffectKind { - pub fn try_from_def_id<I: Interner>(tcx: I, def_id: I::DefId) -> Option<EffectKind> { - if tcx.is_lang_item(def_id, EffectsMaybe) { + pub fn try_from_def_id<I: Interner>(cx: I, def_id: I::DefId) -> Option<EffectKind> { + if cx.is_lang_item(def_id, EffectsMaybe) { Some(EffectKind::Maybe) - } else if tcx.is_lang_item(def_id, EffectsRuntime) { + } else if cx.is_lang_item(def_id, EffectsRuntime) { Some(EffectKind::Runtime) - } else if tcx.is_lang_item(def_id, EffectsNoRuntime) { + } else if cx.is_lang_item(def_id, EffectsNoRuntime) { Some(EffectKind::NoRuntime) } else { None } } - pub fn to_def_id<I: Interner>(self, tcx: I) -> I::DefId { + pub fn to_def_id<I: Interner>(self, cx: I) -> I::DefId { let lang_item = match self { EffectKind::Maybe => EffectsMaybe, EffectKind::NoRuntime => EffectsNoRuntime, EffectKind::Runtime => EffectsRuntime, }; - tcx.require_lang_item(lang_item) + cx.require_lang_item(lang_item) } - pub fn try_from_ty<I: Interner>(tcx: I, ty: I::Ty) -> Option<EffectKind> { + pub fn try_from_ty<I: Interner>(cx: I, ty: I::Ty) -> Option<EffectKind> { if let crate::Adt(def, _) = ty.kind() { - Self::try_from_def_id(tcx, def.def_id()) + Self::try_from_def_id(cx, def.def_id()) } else { None } } - pub fn to_ty<I: Interner>(self, tcx: I) -> I::Ty { - I::Ty::new_adt(tcx, tcx.adt_def(self.to_def_id(tcx)), Default::default()) + pub fn to_ty<I: Interner>(self, cx: I) -> I::Ty { + I::Ty::new_adt(cx, cx.adt_def(self.to_def_id(cx)), Default::default()) } /// Returns an intersection between two effect kinds. If one effect kind diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 0def7d12f74..7dd2f3de3f8 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -258,17 +258,17 @@ pub fn supertrait_def_ids<I: Interner>( } pub fn supertraits<I: Interner>( - tcx: I, + cx: I, trait_ref: ty::Binder<I, ty::TraitRef<I>>, ) -> FilterToTraits<I, Elaborator<I, I::Clause>> { - elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() + elaborate(cx, [trait_ref.upcast(cx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<I: Interner>( - tcx: I, + cx: I, trait_refs: impl Iterator<Item = ty::Binder<I, ty::TraitRef<I>>>, ) -> FilterToTraits<I, Elaborator<I, I::Clause>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) + elaborate(cx, trait_refs.map(|trait_ref| trait_ref.upcast(cx))) .filter_only_self() .filter_to_traits() } diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 0810fa5c558..456accd1a1b 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -105,7 +105,7 @@ pub enum TreatParams { /// /// ¹ meaning that if the outermost layers are different, then the whole types are also different. pub fn simplify_type<I: Interner>( - tcx: I, + cx: I, ty: I::Ty, treat_params: TreatParams, ) -> Option<SimplifiedType<I::DefId>> { @@ -119,10 +119,10 @@ pub fn simplify_type<I: Interner>( ty::Str => Some(SimplifiedType::Str), ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), - ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), + ty::Pat(ty, ..) => simplify_type(cx, ty, treat_params), ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { - Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { + Some(principal_def_id) if !cx.trait_is_auto(principal_def_id) => { Some(SimplifiedType::Trait(principal_def_id)) } _ => Some(SimplifiedType::MarkerTraitObject), diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 09ee12d1cc3..a4d8dafb246 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -345,20 +345,20 @@ impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, // `rustc_middle/src/ty/generic_args.rs` for more details. struct Shifter<I: Interner> { - tcx: I, + cx: I, current_index: ty::DebruijnIndex, amount: u32, } impl<I: Interner> Shifter<I> { - pub fn new(tcx: I, amount: u32) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount } + pub fn new(cx: I, amount: u32) -> Self { + Shifter { cx, current_index: ty::INNERMOST, amount } } } impl<I: Interner> TypeFolder<I> for Shifter<I> { fn cx(&self) -> I { - self.tcx + self.cx } fn fold_binder<T: TypeFoldable<I>>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> { @@ -372,7 +372,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { match r.kind() { ty::ReBound(debruijn, br) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Region::new_bound(self.tcx, debruijn, br) + Region::new_bound(self.cx, debruijn, br) } _ => r, } @@ -382,7 +382,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { match ty.kind() { ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Ty::new_bound(self.tcx, debruijn, bound_ty) + Ty::new_bound(self.cx, debruijn, bound_ty) } _ if ty.has_vars_bound_at_or_above(self.current_index) => ty.super_fold_with(self), @@ -394,7 +394,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Const::new_bound(self.tcx, debruijn, bound_ct) + Const::new_bound(self.cx, debruijn, bound_ct) } _ => ct.super_fold_with(self), } @@ -405,16 +405,16 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { } } -pub fn shift_region<I: Interner>(tcx: I, region: I::Region, amount: u32) -> I::Region { +pub fn shift_region<I: Interner>(cx: I, region: I::Region, amount: u32) -> I::Region { match region.kind() { ty::ReBound(debruijn, br) if amount > 0 => { - Region::new_bound(tcx, debruijn.shifted_in(amount), br) + Region::new_bound(cx, debruijn.shifted_in(amount), br) } _ => region, } } -pub fn shift_vars<I: Interner, T>(tcx: I, value: T, amount: u32) -> T +pub fn shift_vars<I: Interner, T>(cx: I, value: T, amount: u32) -> T where T: TypeFoldable<I>, { @@ -424,5 +424,5 @@ where return value; } - value.fold_with(&mut Shifter::new(tcx, amount)) + value.fold_with(&mut Shifter::new(cx, amount)) } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f05d626b470..63ad36efc85 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -475,7 +475,7 @@ pub trait Clause<I: Interner<Clause = Self>>: /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal /// instantiation in terms of what happens with bound regions. - fn instantiate_supertrait(self, tcx: I, trait_ref: ty::Binder<I, ty::TraitRef<I>>) -> Self; + fn instantiate_supertrait(self, cx: I, trait_ref: ty::Binder<I, ty::TraitRef<I>>) -> Self; } /// Common capabilities of placeholder kinds diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 37ee66fa222..80e970a23a9 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -24,6 +24,7 @@ pub mod elaborate; pub mod error; pub mod fast_reject; pub mod fold; +#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_inherent")] pub mod inherent; pub mod ir_print; pub mod lang_items; diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index 839da10db5e..e5a099d1f50 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -17,5 +17,5 @@ /// e.g., `()` or `u8`, was interned in a different context. pub trait Lift<I>: std::fmt::Debug { type Lifted: std::fmt::Debug; - fn lift_to_tcx(self, tcx: I) -> Option<Self::Lifted>; + fn lift_to_interner(self, cx: I) -> Option<Self::Lifted>; } diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index d8ed4770e2d..e5d18fcb3d1 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -22,8 +22,8 @@ pub struct OpaqueTypeKey<I: Interner> { } impl<I: Interner> OpaqueTypeKey<I> { - pub fn iter_captured_args(self, tcx: I) -> impl Iterator<Item = (usize, I::GenericArg)> { - let variances = tcx.variances_of(self.def_id.into()); + pub fn iter_captured_args(self, cx: I) -> impl Iterator<Item = (usize, I::GenericArg)> { + let variances = cx.variances_of(self.def_id.into()); std::iter::zip(self.args.iter(), variances.iter()).enumerate().filter_map( |(i, (arg, v))| match (arg.kind(), v) { (_, ty::Invariant) => Some((i, arg)), @@ -35,18 +35,18 @@ impl<I: Interner> OpaqueTypeKey<I> { pub fn fold_captured_lifetime_args( self, - tcx: I, + cx: I, mut f: impl FnMut(I::Region) -> I::Region, ) -> Self { let Self { def_id, args } = self; - let variances = tcx.variances_of(def_id.into()); + let variances = cx.variances_of(def_id.into()); let args = std::iter::zip(args.iter(), variances.iter()).map(|(arg, v)| match (arg.kind(), v) { (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), _ => arg, }); - let args = tcx.mk_args_from_iter(args); + let args = cx.mk_args_from_iter(args); Self { def_id, args } } } diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 10b6f3355d9..eb84f3dd587 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -54,15 +54,15 @@ pub enum Component<I: Interner> { /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. pub fn push_outlives_components<I: Interner>( - tcx: I, + cx: I, ty: I::Ty, out: &mut SmallVec<[Component<I>; 4]>, ) { - ty.visit_with(&mut OutlivesCollector { tcx, out, visited: Default::default() }); + ty.visit_with(&mut OutlivesCollector { cx, out, visited: Default::default() }); } struct OutlivesCollector<'a, I: Interner> { - tcx: I, + cx: I, out: &'a mut SmallVec<[Component<I>; 4]>, visited: SsoHashSet<I::Ty>, } @@ -147,7 +147,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> { // OutlivesProjectionComponents. Continue walking // through and constrain Pi. let mut subcomponents = smallvec![]; - compute_alias_components_recursive(self.tcx, ty, &mut subcomponents); + compute_alias_components_recursive(self.cx, ty, &mut subcomponents); self.out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); } } @@ -206,7 +206,7 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> { /// This should not be used to get the components of `parent` itself. /// Use [push_outlives_components] instead. pub fn compute_alias_components_recursive<I: Interner>( - tcx: I, + cx: I, alias_ty: I::Ty, out: &mut SmallVec<[Component<I>; 4]>, ) { @@ -215,9 +215,9 @@ pub fn compute_alias_components_recursive<I: Interner>( }; let opt_variances = - if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None }; + if kind == ty::Opaque { Some(cx.variances_of(alias_ty.def_id)) } else { None }; - let mut visitor = OutlivesCollector { tcx, out, visited: Default::default() }; + let mut visitor = OutlivesCollector { cx, out, visited: Default::default() }; for (index, child) in alias_ty.args.iter().enumerate() { if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) { diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e5bcbc67f94..e03f521c5b1 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -34,8 +34,8 @@ where { type Lifted = OutlivesPredicate<U, A::Lifted>; - fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> { - Some(OutlivesPredicate(self.0.lift_to_tcx(tcx)?, self.1.lift_to_tcx(tcx)?)) + fn lift_to_interner(self, cx: U) -> Option<Self::Lifted> { + Some(OutlivesPredicate(self.0.lift_to_interner(cx)?, self.1.lift_to_interner(cx)?)) } } @@ -267,25 +267,23 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> { /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example). - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> I::Clause { + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> I::Clause { match self.skip_binder() { - ExistentialPredicate::Trait(tr) => { - self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx) - } + ExistentialPredicate::Trait(tr) => self.rebind(tr).with_self_ty(cx, self_ty).upcast(cx), ExistentialPredicate::Projection(p) => { - self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx) + self.rebind(p.with_self_ty(cx, self_ty)).upcast(cx) } ExistentialPredicate::AutoTrait(did) => { - let generics = tcx.generics_of(did); + let generics = cx.generics_of(did); let trait_ref = if generics.count() == 1 { - ty::TraitRef::new(tcx, did, [self_ty]) + ty::TraitRef::new(cx, did, [self_ty]) } else { // If this is an ill-formed auto trait, then synthesize // new error args for the missing generics. - let err_args = GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]); - ty::TraitRef::new_from_args(tcx, did, err_args) + let err_args = GenericArgs::extend_with_error(cx, did, &[self_ty.into()]); + ty::TraitRef::new_from_args(cx, did, err_args) }; - self.rebind(trait_ref).upcast(tcx) + self.rebind(trait_ref).upcast(cx) } } } @@ -345,8 +343,8 @@ impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> { /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> { - self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> { + self.map_bound(|trait_ref| trait_ref.with_self_ty(cx, self_ty)) } } @@ -406,8 +404,8 @@ impl<I: Interner> ExistentialProjection<I> { } impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> { - pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> { - self.map_bound(|p| p.with_self_ty(tcx, self_ty)) + pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> { + self.map_bound(|p| p.with_self_ty(cx, self_ty)) } pub fn item_def_id(&self) -> I::DefId { @@ -669,21 +667,21 @@ impl<I: Interner> ProjectionPredicate<I> { impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> { /// Returns the `DefId` of the trait of the associated item being projected. #[inline] - pub fn trait_def_id(&self, tcx: I) -> I::DefId { - self.skip_binder().projection_term.trait_def_id(tcx) + pub fn trait_def_id(&self, cx: I) -> I::DefId { + self.skip_binder().projection_term.trait_def_id(cx) } /// Get the trait ref required for this projection to be well formed. /// Note that for generic associated types the predicates of the associated /// type also need to be checked. #[inline] - pub fn required_poly_trait_ref(&self, tcx: I) -> ty::Binder<I, TraitRef<I>> { + pub fn required_poly_trait_ref(&self, cx: I) -> ty::Binder<I, TraitRef<I>> { // Note: unlike with `TraitRef::to_poly_trait_ref()`, // `self.0.trait_ref` is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our // return value, so we are preserving the number of binding // levels. - self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx)) + self.map_bound(|predicate| predicate.projection_term.trait_ref(cx)) } pub fn term(&self) -> ty::Binder<I, I::Term> { diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 0439e7f857f..ae840ec0210 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -1,7 +1,7 @@ use std::iter; use rustc_ast_ir::Mutability; -use tracing::{debug, instrument}; +use tracing::{instrument, trace}; use crate::error::{ExpectedFound, TypeError}; use crate::fold::TypeFoldable; @@ -56,10 +56,7 @@ impl<I: Interner> VarianceDiagInfo<I> { } pub trait TypeRelation<I: Interner>: Sized { - fn tcx(&self) -> I; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; + fn cx(&self) -> I; /// Generic relation routine suitable for most anything. fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> { @@ -69,19 +66,15 @@ pub trait TypeRelation<I: Interner>: Sized { /// Relate the two args for the given item. The default /// is to look up the variance for the item and proceed /// accordingly. + #[instrument(skip(self), level = "trace")] fn relate_item_args( &mut self, item_def_id: I::DefId, a_arg: I::GenericArgs, b_arg: I::GenericArgs, ) -> RelateResult<I, I::GenericArgs> { - debug!( - "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", - item_def_id, a_arg, b_arg - ); - - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); + let cx = self.cx(); + let opt_variances = cx.variances_of(item_def_id); relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) } @@ -128,7 +121,7 @@ pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>( a_arg: I::GenericArgs, b_arg: I::GenericArgs, ) -> RelateResult<I, I::GenericArgs> { - relation.tcx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| { + relation.cx().mk_args_from_iter(iter::zip(a_arg.iter(), b_arg.iter()).map(|(a, b)| { relation.relate_with_variance(ty::Invariant, VarianceDiagInfo::default(), a, b) })) } @@ -141,14 +134,13 @@ pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>( b_arg: I::GenericArgs, fetch_ty_for_diag: bool, ) -> RelateResult<I, I::GenericArgs> { - let tcx = relation.tcx(); + let cx = relation.cx(); let mut cached_ty = None; let params = iter::zip(a_arg.iter(), b_arg.iter()).enumerate().map(|(i, (a, b))| { let variance = variances.get(i).unwrap(); let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = - *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg)); + let ty = *cached_ty.get_or_insert_with(|| cx.type_of(ty_def_id).instantiate(cx, a_arg)); VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } } else { VarianceDiagInfo::default() @@ -156,7 +148,7 @@ pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>( relation.relate_with_variance(variance, variance_info, a, b) }); - tcx.mk_args_from_iter(params) + cx.mk_args_from_iter(params) } impl<I: Interner> Relate<I> for ty::FnSig<I> { @@ -165,7 +157,7 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> { a: ty::FnSig<I>, b: ty::FnSig<I>, ) -> RelateResult<I, ty::FnSig<I>> { - let tcx = relation.tcx(); + let cx = relation.cx(); if a.c_variadic != b.c_variadic { return Err(TypeError::VariadicMismatch({ @@ -210,7 +202,7 @@ impl<I: Interner> Relate<I> for ty::FnSig<I> { r => r, }); Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, + inputs_and_output: cx.mk_type_list_from_iter(inputs_and_output)?, c_variadic: a.c_variadic, safety, abi, @@ -245,11 +237,11 @@ impl<I: Interner> Relate<I> for ty::AliasTy<I> { ExpectedFound::new(true, a, b) })) } else { - let args = match a.kind(relation.tcx()) { + let args = match a.kind(relation.cx()) { ty::Opaque => relate_args_with_variances( relation, a.def_id, - relation.tcx().variances_of(a.def_id), + relation.cx().variances_of(a.def_id), a.args, b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle @@ -258,7 +250,7 @@ impl<I: Interner> Relate<I> for ty::AliasTy<I> { relate_args_invariantly(relation, a.args, b.args)? } }; - Ok(ty::AliasTy::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::AliasTy::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -276,11 +268,11 @@ impl<I: Interner> Relate<I> for ty::AliasTerm<I> { ExpectedFound::new(true, a, b) })) } else { - let args = match a.kind(relation.tcx()) { + let args = match a.kind(relation.cx()) { ty::AliasTermKind::OpaqueTy => relate_args_with_variances( relation, a.def_id, - relation.tcx().variances_of(a.def_id), + relation.cx().variances_of(a.def_id), a.args, b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle @@ -293,7 +285,7 @@ impl<I: Interner> Relate<I> for ty::AliasTerm<I> { relate_args_invariantly(relation, a.args, b.args)? } }; - Ok(ty::AliasTerm::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::AliasTerm::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -343,7 +335,7 @@ impl<I: Interner> Relate<I> for ty::TraitRef<I> { })) } else { let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::TraitRef::new_from_args(relation.tcx(), a.def_id, args)) + Ok(ty::TraitRef::new_from_args(relation.cx(), a.def_id, args)) } } } @@ -377,7 +369,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( a: I::Ty, b: I::Ty, ) -> RelateResult<I, I::Ty> { - let tcx = relation.tcx(); + let cx = relation.cx(); match (a.kind(), b.kind()) { (ty::Infer(_), _) | (_, ty::Infer(_)) => { // The caller should handle these cases! @@ -388,7 +380,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( panic!("bound types encountered in structurally_relate_tys") } - (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), + (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(cx, guar)), (ty::Never, _) | (ty::Char, _) @@ -412,16 +404,16 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; - Ok(Ty::new_adt(tcx, a_def, args)) + Ok(Ty::new_adt(cx, a_def, args)) } - (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), + (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(cx, a_id)), (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr)) if a_repr == b_repr => { Ok(Ty::new_dynamic( - tcx, + cx, relation.relate(a_obj, b_obj)?, relation.relate(a_region, b_region)?, a_repr, @@ -433,7 +425,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( // the (anonymous) type of the same coroutine expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine(tcx, a_id, args)) + Ok(Ty::new_coroutine(cx, a_id, args)) } (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args)) @@ -443,7 +435,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( // the (anonymous) type of the same coroutine expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_witness(tcx, a_id, args)) + Ok(Ty::new_coroutine_witness(cx, a_id, args)) } (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => { @@ -451,14 +443,14 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_closure(tcx, a_id, args)) + Ok(Ty::new_closure(cx, a_id, args)) } (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args)) if a_id == b_id => { let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + Ok(Ty::new_coroutine_closure(cx, a_id, args)) } (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { @@ -475,7 +467,7 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - Ok(Ty::new_ptr(tcx, ty, a_mutbl)) + Ok(Ty::new_ptr(cx, ty, a_mutbl)) } (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => { @@ -493,18 +485,18 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( let r = relation.relate(a_r, b_r)?; let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) + Ok(Ty::new_ref(cx, r, ty, a_mutbl)) } (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => { let t = relation.relate(a_t, b_t)?; match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), + Ok(sz) => Ok(Ty::new_array_with_const_len(cx, t, sz)), Err(err) => { // Check whether the lengths are both concrete/known values, // but are unequal, for better diagnostics. - let sz_a = sz_a.try_to_target_usize(tcx); - let sz_b = sz_b.try_to_target_usize(tcx); + let sz_a = sz_a.try_to_target_usize(cx); + let sz_b = sz_b.try_to_target_usize(cx); match (sz_a, sz_b) { (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( @@ -518,13 +510,13 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( (ty::Slice(a_t), ty::Slice(b_t)) => { let t = relation.relate(a_t, b_t)?; - Ok(Ty::new_slice(tcx, t)) + Ok(Ty::new_slice(cx, t)) } (ty::Tuple(as_), ty::Tuple(bs)) => { if as_.len() == bs.len() { Ok(Ty::new_tup_from_iter( - tcx, + cx, iter::zip(as_.iter(), bs.iter()).map(|(a, b)| relation.relate(a, b)), )?) } else if !(as_.is_empty() || bs.is_empty()) { @@ -536,25 +528,25 @@ pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(tcx, a_def_id, args)) + Ok(Ty::new_fn_def(cx, a_def_id, args)) } (ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => { let fty = relation.relate(a_fty, b_fty)?; - Ok(Ty::new_fn_ptr(tcx, fty)) + Ok(Ty::new_fn_ptr(cx, fty)) } // Alias tend to mostly already be handled downstream due to normalization. (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => { let alias_ty = relation.relate(a_data, b_data)?; assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + Ok(Ty::new_alias(cx, a_kind, alias_ty)) } (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => { let ty = relation.relate(a_ty, b_ty)?; let pat = relation.relate(a_pat, b_pat)?; - Ok(Ty::new_pat(tcx, ty, pat)) + Ok(Ty::new_pat(cx, ty, pat)) } _ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))), @@ -572,15 +564,25 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( mut a: I::Const, mut b: I::Const, ) -> RelateResult<I, I::Const> { - debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); - let tcx = relation.tcx(); - - if tcx.features().generic_const_exprs() { - a = tcx.expand_abstract_consts(a); - b = tcx.expand_abstract_consts(b); + trace!( + "structurally_relate_consts::<{}>(a = {:?}, b = {:?})", + std::any::type_name::<R>(), + a, + b + ); + let cx = relation.cx(); + + if cx.features().generic_const_exprs() { + a = cx.expand_abstract_consts(a); + b = cx.expand_abstract_consts(b); } - debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + trace!( + "structurally_relate_consts::<{}>(normed_a = {:?}, normed_b = {:?})", + std::any::type_name::<R>(), + a, + b + ); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -607,8 +609,8 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( // be stabilized. (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { if cfg!(debug_assertions) { - let a_ty = tcx.type_of(au.def).instantiate(tcx, au.args); - let b_ty = tcx.type_of(bu.def).instantiate(tcx, bu.args); + let a_ty = cx.type_of(au.def).instantiate(cx, au.args); + let b_ty = cx.type_of(bu.def).instantiate(cx, bu.args); assert_eq!(a_ty, b_ty); } @@ -618,11 +620,11 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( au.args, bu.args, )?; - return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); + return Ok(Const::new_unevaluated(cx, ty::UnevaluatedConst { def: au.def, args })); } (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { let expr = relation.relate(ae, be)?; - return Ok(Const::new_expr(tcx, expr)); + return Ok(Const::new_expr(cx, expr)); } _ => false, }; diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 7934f996f0b..2449ac47db6 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -106,13 +106,13 @@ pub struct Goal<I: Interner, P> { } impl<I: Interner, P> Goal<I, P> { - pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> { - Goal { param_env, predicate: predicate.upcast(tcx) } + pub fn new(cx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> { + Goal { param_env, predicate: predicate.upcast(cx) } } /// Updates the goal to one with a different `predicate` but the same `param_env`. - pub fn with<Q>(self, tcx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> { - Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) } + pub fn with<Q>(self, cx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> { + Goal { param_env: self.param_env, predicate: predicate.upcast(cx) } } } diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 24a7c0c67e9..6c5bbbfd59b 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -136,9 +136,9 @@ pub struct ClosureArgsParts<I: Interner> { impl<I: Interner> ClosureArgs<I> { /// Construct `ClosureArgs` from `ClosureArgsParts`, containing `Args` /// for the closure parent, alongside additional closure-specific components. - pub fn new(tcx: I, parts: ClosureArgsParts<I>) -> ClosureArgs<I> { + pub fn new(cx: I, parts: ClosureArgsParts<I>) -> ClosureArgs<I> { ClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.closure_kind_ty.into(), parts.closure_sig_as_fn_ptr_ty.into(), parts.tupled_upvars_ty.into(), @@ -258,9 +258,9 @@ pub struct CoroutineClosureArgsParts<I: Interner> { } impl<I: Interner> CoroutineClosureArgs<I> { - pub fn new(tcx: I, parts: CoroutineClosureArgsParts<I>) -> CoroutineClosureArgs<I> { + pub fn new(cx: I, parts: CoroutineClosureArgsParts<I>) -> CoroutineClosureArgs<I> { CoroutineClosureArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.closure_kind_ty.into(), parts.signature_parts_ty.into(), parts.tupled_upvars_ty.into(), @@ -409,14 +409,14 @@ impl<I: Interner> CoroutineClosureSignature<I> { /// When the kind and upvars are known, use the other helper functions. pub fn to_coroutine( self, - tcx: I, + cx: I, parent_args: I::GenericArgsSlice, coroutine_kind_ty: I::Ty, coroutine_def_id: I::DefId, tupled_upvars_ty: I::Ty, ) -> I::Ty { let coroutine_args = ty::CoroutineArgs::new( - tcx, + cx, ty::CoroutineArgsParts { parent_args, kind_ty: coroutine_kind_ty, @@ -428,7 +428,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { }, ); - Ty::new_coroutine(tcx, coroutine_def_id, coroutine_args.args) + Ty::new_coroutine(cx, coroutine_def_id, coroutine_args.args) } /// Given known upvars and a [`ClosureKind`](ty::ClosureKind), compute the coroutine @@ -438,7 +438,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { /// that the `ClosureKind` is actually supported by the coroutine-closure. pub fn to_coroutine_given_kind_and_upvars( self, - tcx: I, + cx: I, parent_args: I::GenericArgsSlice, coroutine_def_id: I::DefId, goal_kind: ty::ClosureKind, @@ -447,7 +447,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { coroutine_captures_by_ref_ty: I::Ty, ) -> I::Ty { let tupled_upvars_ty = Self::tupled_upvars_by_closure_kind( - tcx, + cx, goal_kind, self.tupled_inputs_ty, closure_tupled_upvars_ty, @@ -456,9 +456,9 @@ impl<I: Interner> CoroutineClosureSignature<I> { ); self.to_coroutine( - tcx, + cx, parent_args, - Ty::from_coroutine_closure_kind(tcx, goal_kind), + Ty::from_coroutine_closure_kind(cx, goal_kind), coroutine_def_id, tupled_upvars_ty, ) @@ -474,7 +474,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { /// lifetimes are related to the lifetime of the borrow on the closure made for /// the call. This allows borrowck to enforce the self-borrows correctly. pub fn tupled_upvars_by_closure_kind( - tcx: I, + cx: I, kind: ty::ClosureKind, tupled_inputs_ty: I::Ty, closure_tupled_upvars_ty: I::Ty, @@ -488,12 +488,12 @@ impl<I: Interner> CoroutineClosureSignature<I> { }; let coroutine_captures_by_ref_ty = sig.output().skip_binder().fold_with(&mut FoldEscapingRegions { - interner: tcx, + interner: cx, region: env_region, debruijn: ty::INNERMOST, }); Ty::new_tup_from_iter( - tcx, + cx, tupled_inputs_ty .tuple_fields() .iter() @@ -501,7 +501,7 @@ impl<I: Interner> CoroutineClosureSignature<I> { ) } ty::ClosureKind::FnOnce => Ty::new_tup_from_iter( - tcx, + cx, tupled_inputs_ty .tuple_fields() .iter() @@ -615,9 +615,9 @@ pub struct CoroutineArgsParts<I: Interner> { impl<I: Interner> CoroutineArgs<I> { /// Construct `CoroutineArgs` from `CoroutineArgsParts`, containing `Args` /// for the coroutine parent, alongside additional coroutine-specific components. - pub fn new(tcx: I, parts: CoroutineArgsParts<I>) -> CoroutineArgs<I> { + pub fn new(cx: I, parts: CoroutineArgsParts<I>) -> CoroutineArgs<I> { CoroutineArgs { - args: tcx.mk_args_from_iter(parts.parent_args.iter().chain([ + args: cx.mk_args_from_iter(parts.parent_args.iter().chain([ parts.kind_ty.into(), parts.resume_ty.into(), parts.yield_ty.into(), diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 25eb56fe3fb..6ec38b78fc2 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -101,8 +101,12 @@ pub trait TypeVisitor<I: Interner>: Sized { // The default region visitor is a no-op because `Region` is non-recursive // and has no `super_visit_with` method to call. - fn visit_region(&mut self, _r: I::Region) -> Self::Result { - Self::Result::output() + fn visit_region(&mut self, r: I::Region) -> Self::Result { + if let ty::ReError(guar) = r.kind() { + self.visit_error(guar) + } else { + Self::Result::output() + } } fn visit_const(&mut self, c: I::Const) -> Self::Result { @@ -116,6 +120,10 @@ pub trait TypeVisitor<I: Interner>: Sized { fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result { p.super_visit_with(self) } + + fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result { + Self::Result::output() + } } /////////////////////////////////////////////////////////////////////////// @@ -439,6 +447,15 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_error(&mut self, _guar: <I as Interner>::ErrorGuaranteed) -> Self::Result { + if self.flags.intersects(TypeFlags::HAS_ERROR) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -547,27 +564,7 @@ struct HasErrorVisitor; impl<I: Interner> TypeVisitor<I> for HasErrorVisitor { type Result = ControlFlow<I::ErrorGuaranteed>; - fn visit_ty(&mut self, t: <I as Interner>::Ty) -> Self::Result { - if let ty::Error(guar) = t.kind() { - ControlFlow::Break(guar) - } else { - t.super_visit_with(self) - } - } - - fn visit_const(&mut self, c: <I as Interner>::Const) -> Self::Result { - if let ty::ConstKind::Error(guar) = c.kind() { - ControlFlow::Break(guar) - } else { - c.super_visit_with(self) - } - } - - fn visit_region(&mut self, r: <I as Interner>::Region) -> Self::Result { - if let ty::ReError(guar) = r.kind() { - ControlFlow::Break(guar) - } else { - ControlFlow::Continue(()) - } + fn visit_error(&mut self, guar: <I as Interner>::ErrorGuaranteed) -> Self::Result { + ControlFlow::Break(guar) } } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 000bcf2d3b2..f5b90424afb 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -71,7 +71,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift<J, Lifted = #lifted_ty> }); let bind = &bindings[index]; quote! { - #bind.lift_to_tcx(interner)? + #bind.lift_to_interner(interner)? } }) }); @@ -89,7 +89,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { quote! { type Lifted = #lifted_ty; - fn lift_to_tcx( + fn lift_to_interner( self, interner: J, ) -> Option<Self::Lifted> { diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloc/src/testing/crash_test.rs index bcf5f5f7251..ff72f99b2cb 100644 --- a/library/alloc/src/testing/crash_test.rs +++ b/library/alloc/src/testing/crash_test.rs @@ -1,5 +1,4 @@ -// We avoid relying on anything else in the crate, apart from the `Debug` trait. -use crate::fmt::Debug; +use crate::fmt::Debug; // the `Debug` trait is the only thing we use from `crate::fmt` use std::cmp::Ordering; use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 26b463e25ea..3c641a2e01c 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -24,7 +24,6 @@ mod convert; mod decode; mod methods; -// stable re-exports #[stable(feature = "try_from", since = "1.34.0")] pub use self::convert::CharTryFromError; #[stable(feature = "char_from_str", since = "1.20.0")] @@ -32,11 +31,10 @@ pub use self::convert::ParseCharError; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{DecodeUtf16, DecodeUtf16Error}; -// perma-unstable re-exports #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -pub use self::methods::encode_utf16_raw; +pub use self::methods::encode_utf16_raw; // perma-unstable #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] -pub use self::methods::encode_utf8_raw; +pub use self::methods::encode_utf8_raw; // perma-unstable use crate::ascii; use crate::error::Error; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 76752f22ed8..563f0a324e3 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -781,8 +781,15 @@ const unsafe fn strlen(ptr: *const c_char) -> usize { pub struct Bytes<'a> { // since we know the string is nul-terminated, we only need one pointer ptr: NonNull<u8>, - phantom: PhantomData<&'a u8>, + phantom: PhantomData<&'a [c_char]>, } + +#[unstable(feature = "cstr_bytes", issue = "112115")] +unsafe impl Send for Bytes<'_> {} + +#[unstable(feature = "cstr_bytes", issue = "112115")] +unsafe impl Sync for Bytes<'_> {} + impl<'a> Bytes<'a> { #[inline] fn new(s: &'a CStr) -> Self { @@ -815,7 +822,7 @@ impl Iterator for Bytes<'_> { if ret == 0 { None } else { - self.ptr = self.ptr.offset(1); + self.ptr = self.ptr.add(1); Some(ret) } } @@ -825,6 +832,12 @@ impl Iterator for Bytes<'_> { fn size_hint(&self) -> (usize, Option<usize>) { if self.is_empty() { (0, Some(0)) } else { (1, None) } } + + #[inline] + fn count(self) -> usize { + // SAFETY: We always hold a valid pointer to a C string + unsafe { strlen(self.ptr.as_ptr().cast()) } + } } #[unstable(feature = "cstr_bytes", issue = "112115")] diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index 4ccb585862c..36fae1c1596 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -1026,7 +1026,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// assert_eq!(format!("{}", value), "a"); /// assert_eq!(format!("{:?}", value), "'a'"); /// -/// let wrapped = fmt::FormatterFn(|f| write!(f, "{:?}", &value)); +/// let wrapped = fmt::FormatterFn(|f| write!(f, "{value:?}")); /// assert_eq!(format!("{}", wrapped), "'a'"); /// assert_eq!(format!("{:?}", wrapped), "'a'"); /// ``` diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 720da0feece..c4c63883389 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -947,7 +947,6 @@ extern "rust-intrinsic" { #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[rustc_nounwind] pub fn unreachable() -> !; - } /// Informs the optimizer that a condition is always true. @@ -1018,78 +1017,40 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn breakpoint(); - /// The size of a type in bytes. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// More specifically, this is the offset in bytes between successive - /// items of the same type, including alignment padding. - /// - /// The stabilized version of this intrinsic is [`core::mem::size_of`]. + #[cfg(bootstrap)] #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn size_of<T>() -> usize; - /// The minimum alignment of a type. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::mem::align_of`]. + #[cfg(bootstrap)] #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn min_align_of<T>() -> usize; - /// The preferred alignment of a type. - /// - /// This intrinsic does not have a stable counterpart. - /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). + + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] #[rustc_nounwind] pub fn pref_align_of<T>() -> usize; - /// The size of the referenced value in bytes. - /// - /// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] #[rustc_nounwind] pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - /// The required alignment of the referenced value. - /// - /// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. + + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] #[rustc_nounwind] pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; - /// Gets a static string slice containing the name of a type. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::any::type_name`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn type_name<T: ?Sized>() -> &'static str; - /// Gets an identifier which is globally unique to the specified type. This - /// function will return the same value for a type regardless of whichever - /// crate it is invoked in. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] #[rustc_safe_intrinsic] #[rustc_nounwind] @@ -2424,15 +2385,7 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant; - /// Returns the number of variants of the type `T` cast to a `usize`; - /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. + #[cfg(bootstrap)] #[rustc_const_unstable(feature = "variant_count", issue = "73662")] #[rustc_safe_intrinsic] #[rustc_nounwind] @@ -2773,8 +2726,11 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } -/// `ptr` must point to a vtable. /// The intrinsic will return the size stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -2783,8 +2739,11 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize { unreachable!() } -/// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. +/// +/// # Safety +/// +/// `ptr` must point to a vtable. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -2793,6 +2752,150 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { unreachable!() } +/// The size of a type in bytes. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// More specifically, this is the offset in bytes between successive +/// items of the same type, including alignment padding. +/// +/// The stabilized version of this intrinsic is [`core::mem::size_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn size_of<T>() -> usize { + unreachable!() +} + +/// The minimum alignment of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn min_align_of<T>() -> usize { + unreachable!() +} + +/// The preferred alignment of a type. +/// +/// This intrinsic does not have a stable counterpart. +/// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn pref_align_of<T>() -> usize { + unreachable!() +} + +/// Returns the number of variants of the type `T` cast to a `usize`; +/// if `T` has no variants, returns `0`. Uninhabited variants will be counted. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn variant_count<T>() -> usize { + unreachable!() +} + +/// The size of the referenced value in bytes. +/// +/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::size_of_val_raw`] for safety conditions. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize { + unreachable!() +} + +/// The required alignment of the referenced value. +/// +/// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. +/// +/// # Safety +/// +/// See [`crate::mem::align_of_val_raw`] for safety conditions. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const unsafe fn min_align_of_val<T: ?Sized>(_ptr: *const T) -> usize { + unreachable!() +} + +/// Gets a static string slice containing the name of a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::type_name`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_type_name", issue = "63084")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn type_name<T: ?Sized>() -> &'static str { + unreachable!() +} + +/// Gets an identifier which is globally unique to the specified type. This +/// function will return the same value for a type regardless of whichever +/// crate it is invoked in. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn type_id<T: ?Sized + 'static>() -> u128 { + unreachable!() +} + /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// /// This is used to implement functions like `slice::from_raw_parts_mut` and diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index a4bc8b1c9b0..9aac2332dce 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -250,8 +250,10 @@ pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> { None => return Err(pfe_invalid()), }; num.negative = negative; - if let Some(value) = num.try_fast_path::<F>() { - return Ok(value); + if !cfg!(feature = "optimize_for_size") { + if let Some(value) = num.try_fast_path::<F>() { + return Ok(value); + } } // If significant digits were truncated, then we can have rounding error diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 002a41b5669..05dc1e97852 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -170,7 +170,7 @@ impl f128 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS #[unstable(feature = "f128", issue = "116909")] - pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128; + pub const EPSILON: f128 = 1.92592994438723585305597794258492732e-34_f128; /// Smallest finite `f128` value. /// @@ -178,7 +178,7 @@ impl f128 { /// /// [`MAX`]: f128::MAX #[unstable(feature = "f128", issue = "116909")] - pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128; + pub const MIN: f128 = -1.18973149535723176508575932662800702e+4932_f128; /// Smallest positive normal `f128` value. /// /// Equal to 2<sup>[`MIN_EXP`] − 1</sup>. @@ -194,7 +194,7 @@ impl f128 { /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS /// [`MAX_EXP`]: f128::MAX_EXP #[unstable(feature = "f128", issue = "116909")] - pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128; + pub const MAX: f128 = 1.18973149535723176508575932662800702e+4932_f128; /// One greater than the minimum possible normal power of 2 exponent. /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 034af6a0d57..4e8e0ecdde9 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,7 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; -use crate::hint; use crate::intrinsics; use crate::mem; use crate::str::FromStr; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 0c6f06dc017..d80d3241b1e 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -3,6 +3,7 @@ use crate::cmp::Ordering; use crate::fmt; use crate::hash::{Hash, Hasher}; +use crate::hint; use crate::intrinsics; use crate::marker::{Freeze, StructuralPartialEq}; use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign}; @@ -604,7 +605,6 @@ macro_rules! nonzero_integer { } nonzero_integer_signedness_dependent_methods! { - Self = $Ty, Primitive = $signedness $Int, UnsignedPrimitive = $Uint, } @@ -823,7 +823,7 @@ macro_rules! nonzero_integer { } } - nonzero_integer_signedness_dependent_impls!($Ty $signedness $Int); + nonzero_integer_signedness_dependent_impls!($signedness $Int); }; (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => { @@ -849,7 +849,7 @@ macro_rules! nonzero_integer { macro_rules! nonzero_integer_signedness_dependent_impls { // Impls for unsigned nonzero types only. - ($Ty:ident unsigned $Int:ty) => { + (unsigned $Int:ty) => { #[stable(feature = "nonzero_div", since = "1.51.0")] impl Div<NonZero<$Int>> for $Int { type Output = $Int; @@ -897,7 +897,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { } }; // Impls for signed nonzero types only. - ($Ty:ident signed $Int:ty) => { + (signed $Int:ty) => { #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] impl Neg for NonZero<$Int> { type Output = Self; @@ -918,7 +918,6 @@ macro_rules! nonzero_integer_signedness_dependent_impls { macro_rules! nonzero_integer_signedness_dependent_methods { // Associated items for unsigned nonzero types only. ( - Self = $Ty:ident, Primitive = unsigned $Int:ident, UnsignedPrimitive = $Uint:ty, ) => { @@ -1224,11 +1223,60 @@ macro_rules! nonzero_integer_signedness_dependent_methods { intrinsics::ctpop(self.get()) < 2 } + + /// Returns the square root of the number, rounded down. + /// + /// # Examples + /// + /// Basic usage: + /// ``` + /// #![feature(isqrt)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let ten = NonZero::new(10", stringify!($Int), ")?;")] + #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")] + /// + /// assert_eq!(ten.isqrt(), three); + /// # Some(()) + /// # } + #[unstable(feature = "isqrt", issue = "116226")] + #[rustc_const_unstable(feature = "isqrt", issue = "116226")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn isqrt(self) -> Self { + // The algorithm is based on the one presented in + // <https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)> + // which cites as source the following C code: + // <https://web.archive.org/web/20120306040058/http://medialab.freaknet.org/martin/src/sqrt/sqrt.c>. + + let mut op = self.get(); + let mut res = 0; + let mut one = 1 << (self.ilog2() & !1); + + while one != 0 { + if op >= res + one { + op -= res + one; + res = (res >> 1) + one; + } else { + res >>= 1; + } + one >>= 2; + } + + // SAFETY: The result fits in an integer with half as many bits. + // Inform the optimizer about it. + unsafe { hint::assert_unchecked(res < 1 << (Self::BITS / 2)) }; + + // SAFETY: The square root of an integer >= 1 is always >= 1. + unsafe { Self::new_unchecked(res) } + } }; // Associated items for signed nonzero types only. ( - Self = $Ty:ident, Primitive = signed $Int:ident, UnsignedPrimitive = $Uint:ty, ) => { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ad72c29758b..d50bcde0157 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1226,10 +1226,9 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_ilog2(self) -> Option<u32> { - if let Some(x) = NonZero::new(self) { - Some(x.ilog2()) - } else { - None + match NonZero::new(self) { + Some(x) => Some(x.ilog2()), + None => None, } } @@ -1248,10 +1247,9 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn checked_ilog10(self) -> Option<u32> { - if let Some(x) = NonZero::new(self) { - Some(x.ilog10()) - } else { - None + match NonZero::new(self) { + Some(x) => Some(x.ilog10()), + None => None, } } @@ -2590,37 +2588,10 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn isqrt(self) -> Self { - if self < 2 { - return self; - } - - // The algorithm is based on the one presented in - // <https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)> - // which cites as source the following C code: - // <https://web.archive.org/web/20120306040058/http://medialab.freaknet.org/martin/src/sqrt/sqrt.c>. - - let mut op = self; - let mut res = 0; - let mut one = 1 << (self.ilog2() & !1); - - while one != 0 { - if op >= res + one { - op -= res + one; - res = (res >> 1) + one; - } else { - res >>= 1; - } - one >>= 2; + match NonZero::new(self) { + Some(x) => x.isqrt().get(), + None => 0, } - - // SAFETY: the result is positive and fits in an integer with half as many bits. - // Inform the optimizer about it. - unsafe { - hint::assert_unchecked(0 < res); - hint::assert_unchecked(res < 1 << (Self::BITS / 2)); - } - - res } /// Performs Euclidean division. diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 8ec7716012f..1a8fe1e6051 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -770,6 +770,13 @@ impl<T> Option<T> { } } + #[inline] + const fn len(&self) -> usize { + // Using the intrinsic avoids emitting a branch to get the 0 or 1. + let discriminant: isize = crate::intrinsics::discriminant_value(self); + discriminant as usize + } + /// Returns a slice of the contained value, if any. If this is `None`, an /// empty slice is returned. This can be useful to have a single type of /// iterator over an `Option` or slice. @@ -812,7 +819,7 @@ impl<T> Option<T> { unsafe { slice::from_raw_parts( (self as *const Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - self.is_some() as usize, + self.len(), ) } } @@ -869,7 +876,7 @@ impl<T> Option<T> { unsafe { slice::from_raw_parts_mut( (self as *mut Self).byte_add(core::mem::offset_of!(Self, Some.0)).cast(), - self.is_some() as usize, + self.len(), ) } } @@ -2242,10 +2249,8 @@ impl<A> Iterator for Item<A> { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - match self.opt { - Some(_) => (1, Some(1)), - None => (0, Some(0)), - } + let len = self.len(); + (len, Some(len)) } } @@ -2256,7 +2261,12 @@ impl<A> DoubleEndedIterator for Item<A> { } } -impl<A> ExactSizeIterator for Item<A> {} +impl<A> ExactSizeIterator for Item<A> { + #[inline] + fn len(&self) -> usize { + self.opt.len() + } +} impl<A> FusedIterator for Item<A> {} unsafe impl<A> TrustedLen for Item<A> {} diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index a6a1a055e29..e38ef1e147c 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -2,6 +2,9 @@ //! //! See the [module-level documentation](super) for more. +// No formatting: this file is nothing but re-exports, and their order is worth preserving. +#![cfg_attr(rustfmt, rustfmt::skip)] + // Re-exported core operators #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] @@ -33,10 +36,7 @@ pub use crate::convert::{AsMut, AsRef, From, Into}; pub use crate::default::Default; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] -pub use crate::iter::{DoubleEndedIterator, ExactSizeIterator}; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -pub use crate::iter::{Extend, IntoIterator, Iterator}; +pub use crate::iter::{DoubleEndedIterator, ExactSizeIterator, Extend, IntoIterator, Iterator}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::option::Option::{self, None, Some}; diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index ca33ef160e8..496b78439ea 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -4,6 +4,9 @@ //! This module is imported by default when `#![no_std]` is used in the same //! manner as the standard library's prelude. +// No formatting: this file is nothing but re-exports, and their order is worth preserving. +#![cfg_attr(rustfmt, rustfmt::skip)] + #![stable(feature = "core_prelude", since = "1.4.0")] mod common; diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index eb86bf66206..06f205c0f26 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -5,6 +5,7 @@ use crate::hash::{Hash, Hasher}; use crate::intrinsics::aggregate_raw_ptr; use crate::intrinsics::ptr_metadata; use crate::marker::Freeze; +use crate::ptr::NonNull; /// Provides the pointer metadata type of any pointed-to type. /// @@ -153,7 +154,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>( /// compare equal (since identical vtables can be deduplicated within a codegen unit). #[lang = "dyn_metadata"] pub struct DynMetadata<Dyn: ?Sized> { - _vtable_ptr: &'static VTable, + _vtable_ptr: NonNull<VTable>, _phantom: crate::marker::PhantomData<Dyn>, } @@ -166,15 +167,18 @@ extern "C" { } impl<Dyn: ?Sized> DynMetadata<Dyn> { - /// One of the things that rustc_middle does with this being a lang item is - /// give it `FieldsShape::Primitive`, which means that as far as codegen can - /// tell, it *is* a reference, and thus doesn't have any fields. - /// That means we can't use field access, and have to transmute it instead. + /// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout + /// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead + /// it is a `FieldsShape::Primitive`. This means that the same type can have different layout + /// depending on whether it appears as the metadata field of a wide pointer or as a stand-alone + /// type, which understandably confuses codegen and leads to ICEs when trying to project to a + /// field of `DynMetadata`. To work around that issue, we use `transmute` instead of using a + /// field projection. #[inline] fn vtable_ptr(self) -> *const VTable { // SAFETY: this layout assumption is hard-coded into the compiler. // If it's somehow not a size match, the transmute will error. - unsafe { crate::mem::transmute::<Self, &'static VTable>(self) } + unsafe { crate::mem::transmute::<Self, *const VTable>(self) } } /// Returns the size of the type associated with this vtable. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index a8a47b69632..f2247e83ec5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1809,10 +1809,9 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz // FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <= // 1, where the method versions of these operations are not inlined. use intrinsics::{ - assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_sub, - wrapping_add, wrapping_mul, wrapping_sub, + assume, cttz_nonzero, exact_div, mul_with_overflow, unchecked_rem, unchecked_shl, + unchecked_shr, unchecked_sub, wrapping_add, wrapping_mul, wrapping_sub, }; - use intrinsics::{unchecked_shl, unchecked_shr}; /// Calculate multiplicative modular inverse of `x` modulo `m`. /// diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index e1faa407d54..5ddd9f7476d 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -1,6 +1,19 @@ #![unstable(feature = "unicode_internals", issue = "none")] #![allow(missing_docs)] +// The `pub use` ones are for use in alloc, and are not re-exported in std. + +pub(crate) use unicode_data::alphabetic::lookup as Alphabetic; +pub use unicode_data::case_ignorable::lookup as Case_Ignorable; +pub use unicode_data::cased::lookup as Cased; +pub(crate) use unicode_data::cc::lookup as Cc; +pub use unicode_data::conversions; +pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend; +pub(crate) use unicode_data::lowercase::lookup as Lowercase; +pub(crate) use unicode_data::n::lookup as N; +pub(crate) use unicode_data::uppercase::lookup as Uppercase; +pub(crate) use unicode_data::white_space::lookup as White_Space; + pub(crate) mod printable; mod unicode_data; @@ -16,16 +29,3 @@ mod unicode_data; /// [Unicode 11.0 or later, Section 3.1 Versions of the Unicode Standard](https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf#page=4). #[stable(feature = "unicode_version", since = "1.45.0")] pub const UNICODE_VERSION: (u8, u8, u8) = unicode_data::UNICODE_VERSION; - -// For use in alloc, not re-exported in std. -pub use unicode_data::{ - case_ignorable::lookup as Case_Ignorable, cased::lookup as Cased, conversions, -}; - -pub(crate) use unicode_data::alphabetic::lookup as Alphabetic; -pub(crate) use unicode_data::cc::lookup as Cc; -pub(crate) use unicode_data::grapheme_extend::lookup as Grapheme_Extend; -pub(crate) use unicode_data::lowercase::lookup as Lowercase; -pub(crate) use unicode_data::n::lookup as N; -pub(crate) use unicode_data::uppercase::lookup as Uppercase; -pub(crate) use unicode_data::white_space::lookup as White_Space; diff --git a/library/core/tests/future.rs b/library/core/tests/future.rs index db417256dd0..93aca72d590 100644 --- a/library/core/tests/future.rs +++ b/library/core/tests/future.rs @@ -56,7 +56,7 @@ fn test_join() { let y = String::new(); let x = join!(async { - println!("{}", &y); + println!("{y}"); 1 }) .await; diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 581d7e3efe3..57247359fbf 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -1544,10 +1544,10 @@ impl fmt::Debug for Literal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Literal") // format the kind on one line even in {:#?} mode - .field("kind", &format_args!("{:?}", &self.0.kind)) + .field("kind", &format_args!("{:?}", self.0.kind)) .field("symbol", &self.0.symbol) // format `Some("...")` on one line even in {:#?} mode - .field("suffix", &format_args!("{:?}", &self.0.suffix)) + .field("suffix", &format_args!("{:?}", self.0.suffix)) .field("span", &self.0.span) .finish() } diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 36add02d68c..fc9b8cfd46d 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -120,11 +120,8 @@ pub struct VarsOs { /// # Examples /// /// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars(); -/// for (key, value) in env::vars() { +/// // Print all environment variables. +/// for (key, value) in std::env::vars() { /// println!("{key}: {value}"); /// } /// ``` @@ -150,11 +147,8 @@ pub fn vars() -> Vars { /// # Examples /// /// ``` -/// use std::env; -/// -/// // We will iterate through the references to the element returned by -/// // env::vars_os(); -/// for (key, value) in env::vars_os() { +/// // Print all environment variables. +/// for (key, value) in std::env::vars_os() { /// println!("{key:?}: {value:?}"); /// } /// ``` diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 5ca631399aa..c1fc2e5488d 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -683,7 +683,7 @@ fn recursive_rmdir_toctou() { let drop_canary_arc = Arc::new(()); let drop_canary_weak = Arc::downgrade(&drop_canary_arc); - eprintln!("x: {:?}", &victim_del_path); + eprintln!("x: {victim_del_path:?}"); // victim just continuously removes `victim_del` thread::spawn(move || { diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index f366cb8f42b..8de27367a3f 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -775,7 +775,7 @@ impl Error { /// /// impl Display for MyError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// write!(f, "MyError: {}", &self.v) + /// write!(f, "MyError: {}", self.v) /// } /// } /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d4d68c2068d..f0a73a308a4 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -470,7 +470,6 @@ pub mod rt; // The Rust prelude pub mod prelude; -// Public module declarations and re-exports #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 972b6015932..ba519afc62b 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -230,7 +230,7 @@ macro_rules! eprintln { /// ```rust /// let a = 2; /// let b = dbg!(a * 2) + 1; -/// // ^-- prints: [src/main.rs:2] a * 2 = 4 +/// // ^-- prints: [src/main.rs:2:9] a * 2 = 4 /// assert_eq!(b, 5); /// ``` /// @@ -281,7 +281,7 @@ macro_rules! eprintln { /// This prints to [stderr]: /// /// ```text,ignore -/// [src/main.rs:4] n.checked_sub(4) = None +/// [src/main.rs:2:22] n.checked_sub(4) = None /// ``` /// /// Naive factorial implementation: @@ -301,15 +301,15 @@ macro_rules! eprintln { /// This prints to [stderr]: /// /// ```text,ignore -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = false -/// [src/main.rs:3] n <= 1 = true -/// [src/main.rs:4] 1 = 1 -/// [src/main.rs:5] n * factorial(n - 1) = 2 -/// [src/main.rs:5] n * factorial(n - 1) = 6 -/// [src/main.rs:5] n * factorial(n - 1) = 24 -/// [src/main.rs:11] factorial(4) = 24 +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = false +/// [src/main.rs:2:8] n <= 1 = true +/// [src/main.rs:3:9] 1 = 1 +/// [src/main.rs:7:9] n * factorial(n - 1) = 2 +/// [src/main.rs:7:9] n * factorial(n - 1) = 6 +/// [src/main.rs:7:9] n * factorial(n - 1) = 24 +/// [src/main.rs:9:1] factorial(4) = 24 /// ``` /// /// The `dbg!(..)` macro moves the input: diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a1f83029d27..5833c597256 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -24,9 +24,14 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// passed as an argument, it is not captured or consumed, and it never has the /// value `-1`. /// -/// This type's `.to_owned()` implementation returns another `BorrowedFd` -/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file -/// descriptor, which is then borrowed under the same lifetime. +/// This type does not have a [`ToOwned`][crate::borrow::ToOwned] +/// implementation. Calling `.to_owned()` on a variable of this type will call +/// it on `&BorrowedFd` and use `Clone::clone()` like `ToOwned` does for all +/// types implementing `Clone`. The result will be descriptor borrowed under +/// the same lifetime. +/// +/// To obtain an [`OwnedFd`], you can use [`BorrowedFd::try_clone_to_owned`] +/// instead, but this is not supported on all platforms. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -50,6 +55,8 @@ pub struct BorrowedFd<'fd> { /// descriptor, so it can be used in FFI in places where a file descriptor is /// passed as a consumed argument or returned as an owned value, and it never /// has the value `-1`. +/// +/// You can use [`AsFd::as_fd`] to obtain a [`BorrowedFd`]. #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs index 39a42f4e17f..b31dc06f8df 100644 --- a/library/std/src/os/fortanix_sgx/mod.rs +++ b/library/std/src/os/fortanix_sgx/mod.rs @@ -28,7 +28,6 @@ pub mod usercalls { pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs}; pub use crate::sys::abi::usercalls::raw::{Register, RegisterArgument, ReturnValue}; - // fortanix-sgx-abi re-exports pub use crate::sys::abi::usercalls::raw::Error; pub use crate::sys::abi::usercalls::raw::{ ByteBuffer, Cancel, FifoDescriptor, Return, Usercall, diff --git a/library/std/src/os/uefi/mod.rs b/library/std/src/os/uefi/mod.rs index 8ef05eee1f4..b42d796b28f 100644 --- a/library/std/src/os/uefi/mod.rs +++ b/library/std/src/os/uefi/mod.rs @@ -2,6 +2,7 @@ #![unstable(feature = "uefi_std", issue = "100499")] #![doc(cfg(target_os = "uefi"))] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod env; #[path = "../windows/ffi.rs"] diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 27947d91c99..7cac8c39ea8 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -471,6 +471,13 @@ pub trait MetadataExt { /// `fs::metadata` or `File::metadata`, then this will return `Some`. #[unstable(feature = "windows_by_handle", issue = "63010")] fn file_index(&self) -> Option<u64>; + + /// Returns the change time, which is the last time file metadata was changed, such as + /// renames, attributes, etc + /// + /// This will return `None` if the `Metadata` instance was not created using the `FILE_BASIC_INFO` type. + #[unstable(feature = "windows_change_time", issue = "121478")] + fn change_time(&self) -> Option<u64>; } #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -499,6 +506,9 @@ impl MetadataExt for Metadata { fn file_index(&self) -> Option<u64> { self.as_inner().file_index() } + fn change_time(&self) -> Option<u64> { + self.as_inner().changed_u64() + } } /// Windows-specific extensions to [`fs::FileType`]. diff --git a/library/std/src/os/xous/mod.rs b/library/std/src/os/xous/mod.rs index 153694a89a7..4b21695c4ac 100644 --- a/library/std/src/os/xous/mod.rs +++ b/library/std/src/os/xous/mod.rs @@ -1,5 +1,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![doc(cfg(target_os = "xous"))] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod ffi; diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index 055ab7eb6d9..b231bd871b3 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -2,6 +2,9 @@ //! //! See the [module-level documentation](super) for more. +// No formatting: this file is nothing but re-exports, and their order is worth preserving. +#![cfg_attr(rustfmt, rustfmt::skip)] + // Re-exported core operators #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 2d4639342bf..0c610ba67e6 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -95,6 +95,9 @@ //! [book-enums]: ../../book/ch06-01-defining-an-enum.html //! [book-iter]: ../../book/ch13-02-iterators.html +// No formatting: this file is nothing but re-exports, and their order is worth preserving. +#![cfg_attr(rustfmt, rustfmt::skip)] + #![stable(feature = "rust1", since = "1.0.0")] mod common; diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index d030017cfb4..deb4a8fa7ee 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -16,7 +16,6 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(unused_macros)] -// Re-export some of our utilities which are expected by other crates. pub use crate::panicking::{begin_panic, panic_count}; pub use core::panicking::{panic_display, panic_fmt}; diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 042c439394e..84a0b36db17 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -1,12 +1,14 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; +use cfg_if::cfg_if; + use crate::cell::UnsafeCell; use crate::fmt; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; use crate::sys::sync as sys; +use crate::thread::{current_id, ThreadId}; /// A re-entrant mutual exclusion lock /// @@ -53,8 +55,8 @@ use crate::sys::sync as sys; // // The 'owner' field tracks which thread has locked the mutex. // -// We use current_thread_unique_ptr() as the thread identifier, -// which is just the address of a thread local variable. +// We use thread::current_id() as the thread identifier, which is just the +// current thread's ThreadId, so it's unique across the process lifetime. // // If `owner` is set to the identifier of the current thread, // we assume the mutex is already locked and instead of locking it again, @@ -72,14 +74,109 @@ use crate::sys::sync as sys; // since we're not dealing with multiple threads. If it's not equal, // synchronization is left to the mutex, making relaxed memory ordering for // the `owner` field fine in all cases. +// +// On systems without 64 bit atomics we also store the address of a TLS variable +// along the 64-bit TID. We then first check that address against the address +// of that variable on the current thread, and only if they compare equal do we +// compare the actual TIDs. Because we only ever read the TID on the same thread +// that it was written on (or a thread sharing the TLS block with that writer thread), +// we don't need to further synchronize the TID accesses, so they can be regular 64-bit +// non-atomic accesses. #[unstable(feature = "reentrant_lock", issue = "121440")] pub struct ReentrantLock<T: ?Sized> { mutex: sys::Mutex, - owner: AtomicUsize, + owner: Tid, lock_count: UnsafeCell<u32>, data: T, } +cfg_if!( + if #[cfg(target_has_atomic = "64")] { + use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + + struct Tid(AtomicU64); + + impl Tid { + const fn new() -> Self { + Self(AtomicU64::new(0)) + } + + #[inline] + fn contains(&self, owner: ThreadId) -> bool { + owner.as_u64().get() == self.0.load(Relaxed) + } + + #[inline] + // This is just unsafe to match the API of the Tid type below. + unsafe fn set(&self, tid: Option<ThreadId>) { + let value = tid.map_or(0, |tid| tid.as_u64().get()); + self.0.store(value, Relaxed); + } + } + } else { + /// Returns the address of a TLS variable. This is guaranteed to + /// be unique across all currently alive threads. + fn tls_addr() -> usize { + thread_local! { static X: u8 = const { 0u8 } }; + + X.with(|p| <*const u8>::addr(p)) + } + + use crate::sync::atomic::{ + AtomicUsize, + Ordering, + }; + + struct Tid { + // When a thread calls `set()`, this value gets updated to + // the address of a thread local on that thread. This is + // used as a first check in `contains()`; if the `tls_addr` + // doesn't match the TLS address of the current thread, then + // the ThreadId also can't match. Only if the TLS addresses do + // match do we read out the actual TID. + // Note also that we can use relaxed atomic operations here, because + // we only ever read from the tid if `tls_addr` matches the current + // TLS address. In that case, either the the tid has been set by + // the current thread, or by a thread that has terminated before + // the current thread was created. In either case, no further + // synchronization is needed (as per <https://github.com/rust-lang/miri/issues/3450>) + tls_addr: AtomicUsize, + tid: UnsafeCell<u64>, + } + + unsafe impl Send for Tid {} + unsafe impl Sync for Tid {} + + impl Tid { + const fn new() -> Self { + Self { tls_addr: AtomicUsize::new(0), tid: UnsafeCell::new(0) } + } + + #[inline] + // NOTE: This assumes that `owner` is the ID of the current + // thread, and may spuriously return `false` if that's not the case. + fn contains(&self, owner: ThreadId) -> bool { + // SAFETY: See the comments in the struct definition. + self.tls_addr.load(Ordering::Relaxed) == tls_addr() + && unsafe { *self.tid.get() } == owner.as_u64().get() + } + + #[inline] + // This may only be called by one thread at a time, and can lead to + // race conditions otherwise. + unsafe fn set(&self, tid: Option<ThreadId>) { + // It's important that we set `self.tls_addr` to 0 if the tid is + // cleared. Otherwise, there might be race conditions between + // `set()` and `get()`. + let tls_addr = if tid.is_some() { tls_addr() } else { 0 }; + let value = tid.map_or(0, |tid| tid.as_u64().get()); + self.tls_addr.store(tls_addr, Ordering::Relaxed); + unsafe { *self.tid.get() = value }; + } + } + } +); + #[unstable(feature = "reentrant_lock", issue = "121440")] unsafe impl<T: Send + ?Sized> Send for ReentrantLock<T> {} #[unstable(feature = "reentrant_lock", issue = "121440")] @@ -134,7 +231,7 @@ impl<T> ReentrantLock<T> { pub const fn new(t: T) -> ReentrantLock<T> { ReentrantLock { mutex: sys::Mutex::new(), - owner: AtomicUsize::new(0), + owner: Tid::new(), lock_count: UnsafeCell::new(0), data: t, } @@ -184,14 +281,16 @@ impl<T: ?Sized> ReentrantLock<T> { /// assert_eq!(lock.lock().get(), 10); /// ``` pub fn lock(&self) -> ReentrantLockGuard<'_, T> { - let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock. + let this_thread = current_id(); + // Safety: We only touch lock_count when we own the inner mutex. + // Additionally, we only call `self.owner.set()` while holding + // the inner mutex, so no two threads can call it concurrently. unsafe { - if self.owner.load(Relaxed) == this_thread { + if self.owner.contains(this_thread) { self.increment_lock_count().expect("lock count overflow in reentrant mutex"); } else { self.mutex.lock(); - self.owner.store(this_thread, Relaxed); + self.owner.set(Some(this_thread)); debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; } @@ -226,14 +325,16 @@ impl<T: ?Sized> ReentrantLock<T> { /// /// This function does not block. pub(crate) fn try_lock(&self) -> Option<ReentrantLockGuard<'_, T>> { - let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock. + let this_thread = current_id(); + // Safety: We only touch lock_count when we own the inner mutex. + // Additionally, we only call `self.owner.set()` while holding + // the inner mutex, so no two threads can call it concurrently. unsafe { - if self.owner.load(Relaxed) == this_thread { + if self.owner.contains(this_thread) { self.increment_lock_count()?; Some(ReentrantLockGuard { lock: self }) } else if self.mutex.try_lock() { - self.owner.store(this_thread, Relaxed); + self.owner.set(Some(this_thread)); debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; Some(ReentrantLockGuard { lock: self }) @@ -308,18 +409,9 @@ impl<T: ?Sized> Drop for ReentrantLockGuard<'_, T> { unsafe { *self.lock.lock_count.get() -= 1; if *self.lock.lock_count.get() == 0 { - self.lock.owner.store(0, Relaxed); + self.lock.owner.set(None); self.lock.mutex.unlock(); } } } } - -/// Get an address that is unique per running thread. -/// -/// This can be used as a non-null usize-sized ID. -pub(crate) fn current_thread_unique_ptr() -> usize { - // Use a non-drop type to make sure it's still available during thread destruction. - thread_local! { static X: u8 = const { 0 } } - X.with(|x| <*const _>::addr(x)) -} diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs index b509729475b..345e661586d 100644 --- a/library/std/src/sys/os_str/mod.rs +++ b/library/std/src/sys/os_str/mod.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + cfg_if::cfg_if! { if #[cfg(any( target_os = "windows", diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index edb923a4750..806bf033dbc 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,6 +1,5 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. - use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::fmt; @@ -71,7 +70,7 @@ impl Buf { #[inline] pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self { - Self { inner: Wtf8Buf::from_bytes_unchecked(s) } + unsafe { Self { inner: Wtf8Buf::from_bytes_unchecked(s) } } } pub fn with_capacity(capacity: usize) -> Buf { @@ -190,7 +189,7 @@ impl Slice { #[inline] pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { - mem::transmute(Wtf8::from_bytes_unchecked(s)) + unsafe { mem::transmute(Wtf8::from_bytes_unchecked(s)) } } #[track_caller] diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs index b2d74d1311b..21c5facd52f 100644 --- a/library/std/src/sys/pal/hermit/futex.rs +++ b/library/std/src/sys/pal/hermit/futex.rs @@ -3,6 +3,11 @@ use crate::ptr::null; use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool { // Calculate the timeout as a relative timespec. // diff --git a/library/std/src/sys/pal/teeos/alloc.rs b/library/std/src/sys/pal/teeos/alloc.rs index e236819aa23..b280d1dd76f 100644 --- a/library/std/src/sys/pal/teeos/alloc.rs +++ b/library/std/src/sys/pal/teeos/alloc.rs @@ -11,9 +11,9 @@ unsafe impl GlobalAlloc for System { // Also see <https://github.com/rust-lang/rust/issues/45955> and // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>. if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 + unsafe { libc::malloc(layout.size()) as *mut u8 } } else { - aligned_malloc(&layout) + unsafe { aligned_malloc(&layout) } } } @@ -21,11 +21,11 @@ unsafe impl GlobalAlloc for System { unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { // See the comment above in `alloc` for why this check looks the way it does. if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 + unsafe { libc::calloc(layout.size(), 1) as *mut u8 } } else { - let ptr = self.alloc(layout); + let ptr = unsafe { self.alloc(layout) }; if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); + unsafe { ptr::write_bytes(ptr, 0, layout.size()) }; } ptr } @@ -33,15 +33,15 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) + unsafe { libc::free(ptr as *mut libc::c_void) } } #[inline] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } } else { - realloc_fallback(self, ptr, layout, new_size) + unsafe { realloc_fallback(self, ptr, layout, new_size) } } } } @@ -52,6 +52,6 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. // Since these are all powers of 2, we can just use max. let align = layout.align().max(crate::mem::size_of::<usize>()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); + let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) }; if ret != 0 { ptr::null_mut() } else { out as *mut u8 } } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 2a789e72722..adefd1bb42c 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -2,7 +2,7 @@ //! //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Teeos. -#![allow(unsafe_op_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs index f4723b2ea46..7a27d749f1c 100644 --- a/library/std/src/sys/pal/teeos/thread.rs +++ b/library/std/src/sys/pal/teeos/thread.rs @@ -28,22 +28,24 @@ impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = Box::into_raw(Box::new(p)); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + 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); assert_eq!( - libc::pthread_attr_settee( - &mut attr, - libc::TEESMP_THREAD_ATTR_CA_INHERIT, - libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT, - libc::TEESMP_THREAD_ATTR_HAS_SHADOW, - ), + unsafe { + libc::pthread_attr_settee( + &mut attr, + libc::TEESMP_THREAD_ATTR_CA_INHERIT, + libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT, + libc::TEESMP_THREAD_ATTR_HAS_SHADOW, + ) + }, 0, ); let stack_size = cmp::max(stack, min_stack_size(&attr)); - match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -54,7 +56,7 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0); } }; @@ -62,12 +64,12 @@ impl Thread { // 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!(libc::pthread_attr_destroy(&mut attr), 0); + 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. - drop(Box::from_raw(p)); + drop(unsafe { Box::from_raw(p) }); Err(io::Error::from_raw_os_error(ret)) } else { // The new thread will start running earliest after the next yield. diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 408031a4616..4d50d9e8c3d 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -11,6 +11,7 @@ //! //! [`OsStr`]: crate::ffi::OsStr //! [`OsString`]: crate::ffi::OsString +#![forbid(unsafe_op_in_unsafe_fn)] pub mod alloc; pub mod args; diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 26161a9af79..b8900da4cdd 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -11,6 +11,11 @@ use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + /// Wait for a futex_wake operation to wake us. /// /// Returns directly if the futex doesn't hold the expected value. diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 2e5bd85327a..0db08c1a926 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -44,6 +44,7 @@ mod imp { use crate::ops::Range; use crate::ptr; use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; + use crate::sync::OnceLock; use crate::sys::pal::unix::os; use crate::thread; @@ -306,9 +307,8 @@ mod imp { ret } - unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> { - let page_size = PAGE_SIZE.load(Ordering::Relaxed); - let stackptr = get_stack_start()?; + fn stack_start_aligned(page_size: usize) -> Option<*mut libc::c_void> { + let stackptr = unsafe { get_stack_start()? }; let stackaddr = stackptr.addr(); // Ensure stackaddr is page aligned! A parent process might @@ -325,104 +325,133 @@ mod imp { }) } + #[forbid(unsafe_op_in_unsafe_fn)] unsafe fn install_main_guard() -> Option<Range<usize>> { let page_size = PAGE_SIZE.load(Ordering::Relaxed); - if cfg!(all(target_os = "linux", not(target_env = "musl"))) { - // Linux doesn't allocate the whole stack right away, and - // the kernel has its own stack-guard mechanism to fault - // when growing too close to an existing mapping. If we map - // our own guard, then the kernel starts enforcing a rather - // large gap above that, rendering much of the possible - // stack space useless. See #43052. - // - // Instead, we'll just note where we expect rlimit to start - // faulting, so our handler can report "stack overflow", and - // trust that the kernel's own stack guard will work. - let stackptr = get_stack_start_aligned()?; - let stackaddr = stackptr.addr(); - Some(stackaddr - page_size..stackaddr) - } else if cfg!(all(target_os = "linux", target_env = "musl")) { - // For the main thread, the musl's pthread_attr_getstack - // returns the current stack size, rather than maximum size - // it can eventually grow to. It cannot be used to determine - // the position of kernel's stack guard. - None - } else if cfg!(target_os = "freebsd") { - // FreeBSD's stack autogrows, and optionally includes a guard page - // at the bottom. If we try to remap the bottom of the stack - // ourselves, FreeBSD's guard page moves upwards. So we'll just use - // the builtin guard page. - let stackptr = get_stack_start_aligned()?; - let guardaddr = stackptr.addr(); - // Technically the number of guard pages is tunable and controlled - // by the security.bsd.stack_guard_page sysctl. - // By default it is 1, checking once is enough since it is - // a boot time config value. - static PAGES: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new(); - - let pages = PAGES.get_or_init(|| { - use crate::sys::weak::dlsym; - dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); - let mut guard: usize = 0; - let mut size = crate::mem::size_of_val(&guard); - let oid = crate::ffi::CStr::from_bytes_with_nul( - b"security.bsd.stack_guard_page\0", - ) - .unwrap(); - match sysctlbyname.get() { - Some(fcn) => { - if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 { - guard - } else { - 1 - } - }, - _ => 1, - } - }); - Some(guardaddr..guardaddr + pages * page_size) - } else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) { - // OpenBSD stack already includes a guard page, and stack is - // immutable. - // NetBSD stack includes the guard page. - // - // We'll just note where we expect rlimit to start - // faulting, so our handler can report "stack overflow", and - // trust that the kernel's own stack guard will work. - let stackptr = get_stack_start_aligned()?; - let stackaddr = stackptr.addr(); - Some(stackaddr - page_size..stackaddr) - } else { - // Reallocate the last page of the stack. - // This ensures SIGBUS will be raised on - // stack overflow. - // Systems which enforce strict PAX MPROTECT do not allow - // to mprotect() a mapping with less restrictive permissions - // than the initial mmap() used, so we mmap() here with - // read/write permissions and only then mprotect() it to - // no permissions at all. See issue #50313. - let stackptr = get_stack_start_aligned()?; - let result = mmap64( + + unsafe { + // this way someone on any unix-y OS can check that all these compile + if cfg!(all(target_os = "linux", not(target_env = "musl"))) { + install_main_guard_linux(page_size) + } else if cfg!(all(target_os = "linux", target_env = "musl")) { + install_main_guard_linux_musl(page_size) + } else if cfg!(target_os = "freebsd") { + install_main_guard_freebsd(page_size) + } else if cfg!(any(target_os = "netbsd", target_os = "openbsd")) { + install_main_guard_bsds(page_size) + } else { + install_main_guard_default(page_size) + } + } + } + + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn install_main_guard_linux(page_size: usize) -> Option<Range<usize>> { + // Linux doesn't allocate the whole stack right away, and + // the kernel has its own stack-guard mechanism to fault + // when growing too close to an existing mapping. If we map + // our own guard, then the kernel starts enforcing a rather + // large gap above that, rendering much of the possible + // stack space useless. See #43052. + // + // Instead, we'll just note where we expect rlimit to start + // faulting, so our handler can report "stack overflow", and + // trust that the kernel's own stack guard will work. + let stackptr = stack_start_aligned(page_size)?; + let stackaddr = stackptr.addr(); + Some(stackaddr - page_size..stackaddr) + } + + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn install_main_guard_linux_musl(_page_size: usize) -> Option<Range<usize>> { + // For the main thread, the musl's pthread_attr_getstack + // returns the current stack size, rather than maximum size + // it can eventually grow to. It cannot be used to determine + // the position of kernel's stack guard. + None + } + + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn install_main_guard_freebsd(page_size: usize) -> Option<Range<usize>> { + // FreeBSD's stack autogrows, and optionally includes a guard page + // at the bottom. If we try to remap the bottom of the stack + // ourselves, FreeBSD's guard page moves upwards. So we'll just use + // the builtin guard page. + let stackptr = stack_start_aligned(page_size)?; + let guardaddr = stackptr.addr(); + // Technically the number of guard pages is tunable and controlled + // by the security.bsd.stack_guard_page sysctl. + // By default it is 1, checking once is enough since it is + // a boot time config value. + static PAGES: OnceLock<usize> = OnceLock::new(); + + let pages = PAGES.get_or_init(|| { + use crate::sys::weak::dlsym; + dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); + let mut guard: usize = 0; + let mut size = mem::size_of_val(&guard); + let oid = c"security.bsd.stack_guard_page"; + match sysctlbyname.get() { + Some(fcn) if unsafe { + fcn(oid.as_ptr(), + ptr::addr_of_mut!(guard).cast(), + ptr::addr_of_mut!(size), + ptr::null_mut(), + 0) == 0 + } => guard, + _ => 1, + } + }); + Some(guardaddr..guardaddr + pages * page_size) + } + + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn install_main_guard_bsds(page_size: usize) -> Option<Range<usize>> { + // OpenBSD stack already includes a guard page, and stack is + // immutable. + // NetBSD stack includes the guard page. + // + // We'll just note where we expect rlimit to start + // faulting, so our handler can report "stack overflow", and + // trust that the kernel's own stack guard will work. + let stackptr = stack_start_aligned(page_size)?; + let stackaddr = stackptr.addr(); + Some(stackaddr - page_size..stackaddr) + } + + #[forbid(unsafe_op_in_unsafe_fn)] + unsafe fn install_main_guard_default(page_size: usize) -> Option<Range<usize>> { + // Reallocate the last page of the stack. + // This ensures SIGBUS will be raised on + // stack overflow. + // Systems which enforce strict PAX MPROTECT do not allow + // to mprotect() a mapping with less restrictive permissions + // than the initial mmap() used, so we mmap() here with + // read/write permissions and only then mprotect() it to + // no permissions at all. See issue #50313. + let stackptr = stack_start_aligned(page_size)?; + let result = unsafe { + mmap64( stackptr, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0, - ); - if result != stackptr || result == MAP_FAILED { - panic!("failed to allocate a guard page: {}", io::Error::last_os_error()); - } + ) + }; + if result != stackptr || result == MAP_FAILED { + panic!("failed to allocate a guard page: {}", io::Error::last_os_error()); + } - let result = mprotect(stackptr, page_size, PROT_NONE); - if result != 0 { - panic!("failed to protect the guard page: {}", io::Error::last_os_error()); - } + let result = unsafe { mprotect(stackptr, page_size, PROT_NONE) }; + if result != 0 { + panic!("failed to protect the guard page: {}", io::Error::last_os_error()); + } - let guardaddr = stackptr.addr(); + let guardaddr = stackptr.addr(); - Some(guardaddr..guardaddr + page_size) - } + Some(guardaddr..guardaddr + page_size) } #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))] diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 8dfb733043e..d8fe06d1973 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -39,12 +39,15 @@ pub mod time; #[deny(unsafe_op_in_unsafe_fn)] #[allow(unused)] mod common; + pub use common::*; mod helpers; -// These exports are listed individually to work around Rust's glob import -// conflict rules. If we glob export `helpers` and `common` together, then -// the compiler complains about conflicts. + +// The following exports are listed individually to work around Rust's glob +// import conflict rules. If we glob export `helpers` and `common` together, +// then the compiler complains about conflicts. + pub use helpers::abort_internal; pub use helpers::decode_error_kind; use helpers::err2io; diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 7af0917b8ed..0930d2e22fa 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -41,13 +41,16 @@ pub mod time; #[deny(unsafe_op_in_unsafe_fn)] #[allow(unused)] mod common; + pub use common::*; #[path = "../wasi/helpers.rs"] mod helpers; -// These exports are listed individually to work around Rust's glob import -// conflict rules. If we glob export `helpers` and `common` together, then -// the compiler complains about conflicts. + +// The following exports are listed individually to work around Rust's glob +// import conflict rules. If we glob export `helpers` and `common` together, +// then the compiler complains about conflicts. + pub use helpers::abort_internal; pub use helpers::decode_error_kind; use helpers::err2io; diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs index a21b71efbbc..3584138ca04 100644 --- a/library/std/src/sys/pal/wasm/atomics/futex.rs +++ b/library/std/src/sys/pal/wasm/atomics/futex.rs @@ -6,6 +6,11 @@ use core::arch::wasm64 as wasm; use crate::sync::atomic::AtomicU32; use crate::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU32; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u32; + /// Wait for a futex_wake operation to wake us. /// /// Returns directly if the futex doesn't hold the expected value. diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs index 9f0194492b0..987be6b69ee 100644 --- a/library/std/src/sys/pal/windows/alloc.rs +++ b/library/std/src/sys/pal/windows/alloc.rs @@ -1,5 +1,3 @@ -#![deny(unsafe_op_in_unsafe_fn)] - use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ffi::c_void; use crate::ptr; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 296d19a926d..9ab31bf6f75 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -457,44 +457,3 @@ compat_fn_with_fallback! { Status as u32 } } - -// # Arm32 shim -// -// AddVectoredExceptionHandler and WSAStartup use platform-specific types. -// However, Microsoft no longer supports thumbv7a so definitions for those targets -// are not included in the win32 metadata. We work around that by defining them here. -// -// Where possible, these definitions should be kept in sync with https://docs.rs/windows-sys -cfg_if::cfg_if! { -if #[cfg(not(target_vendor = "uwp"))] { - #[link(name = "kernel32")] - extern "system" { - pub fn AddVectoredExceptionHandler( - first: u32, - handler: PVECTORED_EXCEPTION_HANDLER, - ) -> *mut c_void; - } - pub type PVECTORED_EXCEPTION_HANDLER = Option< - unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32, - >; - #[repr(C)] - pub struct EXCEPTION_POINTERS { - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ContextRecord: *mut CONTEXT, - } - #[cfg(target_arch = "arm")] - pub enum CONTEXT {} -}} -// WSAStartup is only redefined here so that we can override WSADATA for Arm32 -windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32); -#[cfg(target_arch = "arm")] -#[repr(C)] -pub struct WSADATA { - pub wVersion: u16, - pub wHighVersion: u16, - pub szDescription: [u8; 257], - pub szSystemStatus: [u8; 129], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: PSTR, -} diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 5ad4a3731d8..258403e090a 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2175,6 +2175,7 @@ Windows.Win32.Networking.WinSock.WSARecv Windows.Win32.Networking.WinSock.WSASend Windows.Win32.Networking.WinSock.WSASERVICE_NOT_FOUND Windows.Win32.Networking.WinSock.WSASocketW +Windows.Win32.Networking.WinSock.WSAStartup Windows.Win32.Networking.WinSock.WSASYSCALLFAILURE Windows.Win32.Networking.WinSock.WSASYSNOTREADY Windows.Win32.Networking.WinSock.WSATRY_AGAIN @@ -2419,6 +2420,7 @@ Windows.Win32.System.Console.STD_HANDLE Windows.Win32.System.Console.STD_INPUT_HANDLE Windows.Win32.System.Console.STD_OUTPUT_HANDLE Windows.Win32.System.Console.WriteConsoleW +Windows.Win32.System.Diagnostics.Debug.AddVectoredExceptionHandler Windows.Win32.System.Diagnostics.Debug.ARM64_NT_NEON128 Windows.Win32.System.Diagnostics.Debug.CONTEXT Windows.Win32.System.Diagnostics.Debug.EXCEPTION_RECORD diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index fea00fec9ae..1f06cc990b6 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -5,6 +5,7 @@ windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> BOOLEAN); windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK)); windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK)); +windows_targets::link!("kernel32.dll" "system" fn AddVectoredExceptionHandler(first : u32, handler : PVECTORED_EXCEPTION_HANDLER) -> *mut core::ffi::c_void); windows_targets::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT); @@ -113,6 +114,7 @@ windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR); windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32); windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET); +windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested : u16, lpwsadata : *mut WSADATA) -> i32); windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET); windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32); windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32); @@ -2283,6 +2285,12 @@ pub type EXCEPTION_DISPOSITION = i32; pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32; #[repr(C)] #[derive(Clone, Copy)] +pub struct EXCEPTION_POINTERS { + pub ExceptionRecord: *mut EXCEPTION_RECORD, + pub ContextRecord: *mut CONTEXT, +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct EXCEPTION_RECORD { pub ExceptionCode: NTSTATUS, pub ExceptionFlags: u32, @@ -2859,6 +2867,8 @@ pub type PTIMERAPCROUTINE = Option< dwtimerhighvalue: u32, ), >; +pub type PVECTORED_EXCEPTION_HANDLER = + Option<unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32>; pub type PWSTR = *mut u16; pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32; pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32; @@ -3283,5 +3293,19 @@ pub struct XSAVE_FORMAT { pub XmmRegisters: [M128A; 8], pub Reserved4: [u8; 224], } + +#[cfg(target_arch = "arm")] +#[repr(C)] +pub struct WSADATA { + pub wVersion: u16, + pub wHighVersion: u16, + pub szDescription: [u8; 257], + pub szSystemStatus: [u8; 129], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: PSTR, +} +#[cfg(target_arch = "arm")] +pub enum CONTEXT {} // ignore-tidy-filelength use super::windows_targets; diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index 85fd9153d53..15d446786ad 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use core::ptr::addr_of; use crate::os::windows::prelude::*; @@ -33,6 +32,7 @@ pub struct FileAttr { creation_time: c::FILETIME, last_access_time: c::FILETIME, last_write_time: c::FILETIME, + change_time: Option<c::FILETIME>, file_size: u64, reparse_tag: u32, volume_serial_number: Option<u32>, @@ -378,6 +378,7 @@ impl File { creation_time: info.ftCreationTime, last_access_time: info.ftLastAccessTime, last_write_time: info.ftLastWriteTime, + change_time: None, // Only available in FILE_BASIC_INFO file_size: (info.nFileSizeLow as u64) | ((info.nFileSizeHigh as u64) << 32), reparse_tag, volume_serial_number: Some(info.dwVolumeSerialNumber), @@ -414,6 +415,10 @@ impl File { dwLowDateTime: info.LastWriteTime as u32, dwHighDateTime: (info.LastWriteTime >> 32) as u32, }, + change_time: Some(c::FILETIME { + dhLowDateTime: info.ChangeTime as c::DWORD, + dhHighDateTime: (info.ChangeTime >> 32) as c::DWORD, + }), file_size: 0, reparse_tag: 0, volume_serial_number: None, @@ -795,10 +800,12 @@ impl<'a> Iterator for DirBuffIter<'a> { } unsafe fn from_maybe_unaligned<'a>(p: *const u16, len: usize) -> Cow<'a, [u16]> { - if p.is_aligned() { - Cow::Borrowed(crate::slice::from_raw_parts(p, len)) - } else { - Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect()) + unsafe { + if p.is_aligned() { + Cow::Borrowed(crate::slice::from_raw_parts(p, len)) + } else { + Cow::Owned((0..len).map(|i| p.add(i).read_unaligned()).collect()) + } } } @@ -897,7 +904,9 @@ impl IntoRawHandle for File { impl FromRawHandle for File { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + unsafe { + Self { handle: FromInner::from_inner(FromRawHandle::from_raw_handle(raw_handle)) } + } } } @@ -954,6 +963,10 @@ impl FileAttr { to_u64(&self.creation_time) } + pub fn changed_u64(&self) -> Option<u64> { + self.change_time.as_ref().map(|c| to_u64(c)) + } + pub fn volume_serial_number(&self) -> Option<u32> { self.volume_serial_number } @@ -973,6 +986,7 @@ impl From<c::WIN32_FIND_DATAW> for FileAttr { creation_time: wfd.ftCreationTime, last_access_time: wfd.ftLastAccessTime, last_write_time: wfd.ftLastWriteTime, + change_time: None, file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64), reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { // reserved unless this is a reparse point @@ -1427,10 +1441,12 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { _hDestinationFile: c::HANDLE, lpData: *const c_void, ) -> u32 { - if dwStreamNumber == 1 { - *(lpData as *mut i64) = StreamBytesTransferred; + unsafe { + if dwStreamNumber == 1 { + *(lpData as *mut i64) = StreamBytesTransferred; + } + c::PROGRESS_CONTINUE } - c::PROGRESS_CONTINUE } let pfrom = maybe_verbatim(from)?; let pto = maybe_verbatim(to)?; diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index 08b7fe300dc..c54810e06cd 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -10,6 +10,12 @@ use core::sync::atomic::{ }; use core::time::Duration; +/// An atomic for use as a futex that is at least 8-bits but may be larger. +pub type SmallAtomic = AtomicU8; +/// Must be the underlying type of SmallAtomic +pub type SmallPrimitive = u8; + +pub unsafe trait Futex {} pub unsafe trait Waitable { type Atomic; } @@ -19,6 +25,7 @@ macro_rules! unsafe_waitable_int { unsafe impl Waitable for $int { type Atomic = $atomic; } + unsafe impl Futex for $atomic {} )* }; } @@ -41,6 +48,7 @@ unsafe impl<T> Waitable for *const T { unsafe impl<T> Waitable for *mut T { type Atomic = AtomicPtr<T>; } +unsafe impl<T> Futex for AtomicPtr<T> {} pub fn wait_on_address<W: Waitable>( address: &W::Atomic, @@ -56,14 +64,14 @@ pub fn wait_on_address<W: Waitable>( } } -pub fn wake_by_address_single<T>(address: &T) { +pub fn wake_by_address_single<T: Futex>(address: &T) { unsafe { let addr = ptr::from_ref(address).cast::<c_void>(); c::WakeByAddressSingle(addr); } } -pub fn wake_by_address_all<T>(address: &T) { +pub fn wake_by_address_all<T: Futex>(address: &T) { unsafe { let addr = ptr::from_ref(address).cast::<c_void>(); c::WakeByAddressAll(addr); @@ -75,11 +83,11 @@ pub fn futex_wait<W: Waitable>(futex: &W::Atomic, expected: W, timeout: Option<D wait_on_address(futex, expected, timeout) || api::get_last_error() != WinError::TIMEOUT } -pub fn futex_wake<T>(futex: &T) -> bool { +pub fn futex_wake<T: Futex>(futex: &T) -> bool { wake_by_address_single(futex); false } -pub fn futex_wake_all<T>(futex: &T) { +pub fn futex_wake_all<T: Futex>(futex: &T) { wake_by_address_all(futex) } diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index ae9ea8ff584..aaa1831dcc2 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -1,5 +1,4 @@ #![unstable(issue = "none", feature = "windows_handle")] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -73,7 +72,7 @@ impl IntoRawHandle for Handle { impl FromRawHandle for Handle { unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self { - Self(FromRawHandle::from_raw_handle(raw_handle)) + unsafe { Self(FromRawHandle::from_raw_handle(raw_handle)) } } } @@ -139,13 +138,23 @@ impl Handle { pub unsafe fn read_overlapped( &self, - buf: &mut [u8], + buf: &mut [mem::MaybeUninit<u8>], overlapped: *mut c::OVERLAPPED, ) -> io::Result<Option<usize>> { - let len = cmp::min(buf.len(), u32::MAX as usize) as u32; - let mut amt = 0; - let res = - cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped)); + // SAFETY: We have exclusive access to the buffer and it's up to the caller to + // ensure the OVERLAPPED pointer is valid for the lifetime of this function. + let (res, amt) = unsafe { + let len = cmp::min(buf.len(), u32::MAX as usize) as u32; + let mut amt = 0; + let res = cvt(c::ReadFile( + self.as_raw_handle(), + buf.as_mut_ptr().cast::<u8>(), + len, + &mut amt, + overlapped, + )); + (res, amt) + }; match res { Ok(_) => Ok(Some(amt as usize)), Err(e) => { @@ -230,20 +239,24 @@ impl Handle { // The length is clamped at u32::MAX. let len = cmp::min(len, u32::MAX as usize) as u32; - let status = c::NtReadFile( - self.as_handle(), - ptr::null_mut(), - None, - ptr::null_mut(), - &mut io_status, - buf, - len, - offset.map(|n| n as _).as_ref(), - None, - ); + // SAFETY: It's up to the caller to ensure `buf` is writeable up to + // the provided `len`. + let status = unsafe { + c::NtReadFile( + self.as_handle(), + ptr::null_mut(), + None, + ptr::null_mut(), + &mut io_status, + buf, + len, + offset.map(|n| n as _).as_ref(), + None, + ) + }; let status = if status == c::STATUS_PENDING { - c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE); + unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) }; io_status.status() } else { status @@ -261,7 +274,7 @@ impl Handle { status if c::nt_success(status) => Ok(io_status.Information), status => { - let error = c::RtlNtStatusToDosError(status); + let error = unsafe { c::RtlNtStatusToDosError(status) }; Err(io::Error::from_raw_os_error(error as _)) } } diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 86d457db50a..bf3dfdfdd3e 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::marker::PhantomData; use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; @@ -81,19 +80,17 @@ impl<'a> IoSliceMut<'a> { } pub fn is_terminal(h: &impl AsHandle) -> bool { - unsafe { handle_is_console(h.as_handle()) } + handle_is_console(h.as_handle()) } -unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { - let handle = handle.as_raw_handle(); - +fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { // A null handle means the process has no console. - if handle.is_null() { + if handle.as_raw_handle().is_null() { return false; } let mut out = 0; - if c::GetConsoleMode(handle, &mut out) != 0 { + if unsafe { c::GetConsoleMode(handle.as_raw_handle(), &mut out) != 0 } { // False positives aren't possible. If we got a console then we definitely have a console. return true; } @@ -102,9 +99,9 @@ unsafe fn handle_is_console(handle: BorrowedHandle<'_>) -> bool { msys_tty_on(handle) } -unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { +fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { // Early return if the handle is not a pipe. - if c::GetFileType(handle) != c::FILE_TYPE_PIPE { + if unsafe { c::GetFileType(handle.as_raw_handle()) != c::FILE_TYPE_PIPE } { return false; } @@ -120,12 +117,14 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool { } let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] }; // Safety: buffer length is fixed. - let res = c::GetFileInformationByHandleEx( - handle, - c::FileNameInfo, - core::ptr::addr_of_mut!(name_info) as *mut c_void, - size_of::<FILE_NAME_INFO>() as u32, - ); + let res = unsafe { + c::GetFileInformationByHandleEx( + handle.as_raw_handle(), + c::FileNameInfo, + core::ptr::addr_of_mut!(name_info) as *mut c_void, + size_of::<FILE_NAME_INFO>() as u32, + ) + }; if res == 0 { return false; } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 0a9279e50ba..f1f4d3a5d26 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -1,7 +1,6 @@ //! Implementation of `std::os` functionality for Windows. #![allow(nonstandard_style)] -#![allow(unsafe_op_in_unsafe_fn)] #[cfg(test)] mod tests; @@ -305,15 +304,21 @@ pub fn getenv(k: &OsStr) -> Option<OsString> { } pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = to_u16s(k)?; - let v = to_u16s(v)?; + // SAFETY: We ensure that k and v are null-terminated wide strings. + unsafe { + let k = to_u16s(k)?; + let v = to_u16s(v)?; - cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + } } pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + // SAFETY: We ensure that v is a null-terminated wide strings. + unsafe { + let v = to_u16s(n)?; + cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + } } pub fn temp_dir() -> PathBuf { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8b785f027c..7a309b9638b 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::os::windows::prelude::*; use crate::ffi::OsStr; @@ -6,7 +5,6 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read}; use crate::mem; use crate::path::Path; use crate::ptr; -use crate::slice; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::Relaxed; use crate::sys::c; @@ -325,6 +323,7 @@ impl AnonPipe { /// [`ReadFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfileex /// [`WriteFileEx`]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefileex /// [Asynchronous Procedure Call]: https://docs.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls + #[allow(unsafe_op_in_unsafe_fn)] unsafe fn alertable_io_internal( &self, io: AlertableIoFn, @@ -479,8 +478,11 @@ impl<'a> AsyncPipe<'a> { fn schedule_read(&mut self) -> io::Result<bool> { assert_eq!(self.state, State::NotReading); let amt = unsafe { - let slice = slice_to_end(self.dst); - self.pipe.read_overlapped(slice, &mut *self.overlapped)? + if self.dst.capacity() == self.dst.len() { + let additional = if self.dst.capacity() == 0 { 16 } else { 1 }; + self.dst.reserve(additional); + } + self.pipe.read_overlapped(self.dst.spare_capacity_mut(), &mut *self.overlapped)? }; // If this read finished immediately then our overlapped event will @@ -560,13 +562,3 @@ impl<'a> Drop for AsyncPipe<'a> { } } } - -unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] { - if v.capacity() == 0 { - v.reserve(16); - } - if v.capacity() == v.len() { - v.reserve(1); - } - slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len()) -} diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs index ea89429cb83..467e21ab56a 100644 --- a/library/std/src/sys/pal/windows/stack_overflow.rs +++ b/library/std/src/sys/pal/windows/stack_overflow.rs @@ -1,18 +1,18 @@ #![cfg_attr(test, allow(dead_code))] -#![allow(unsafe_op_in_unsafe_fn)] use crate::sys::c; use crate::thread; /// Reserve stack space for use in stack overflow exceptions. -pub unsafe fn reserve_stack() { - let result = c::SetThreadStackGuarantee(&mut 0x5000); +pub fn reserve_stack() { + let result = unsafe { c::SetThreadStackGuarantee(&mut 0x5000) }; // Reserving stack space is not critical so we allow it to fail in the released build of libstd. // We still use debug assert here so that CI will test that we haven't made a mistake calling the function. debug_assert_ne!(result, 0, "failed to reserve stack space for exception handling"); } unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -> i32 { + // SAFETY: It's up to the caller (which in this case is the OS) to ensure that `ExceptionInfo` is valid. unsafe { let rec = &(*(*ExceptionInfo).ExceptionRecord); let code = rec.ExceptionCode; @@ -27,11 +27,14 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN } } -pub unsafe fn init() { - let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); - // Similar to the above, adding the stack overflow handler is allowed to fail - // but a debug assert is used so CI will still test that it normally works. - debug_assert!(!result.is_null(), "failed to install exception handler"); +pub fn init() { + // SAFETY: `vectored_handler` has the correct ABI and is safe to call during exception handling. + unsafe { + let result = c::AddVectoredExceptionHandler(0, Some(vectored_handler)); + // Similar to the above, adding the stack overflow handler is allowed to fail + // but a debug assert is used so CI will still test that it normally works. + debug_assert!(!result.is_null(), "failed to install exception handler"); + } // Set the thread stack guarantee for the main thread. reserve_stack(); } diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs index 3648272a343..668a3c05e20 100644 --- a/library/std/src/sys/pal/windows/thread.rs +++ b/library/std/src/sys/pal/windows/thread.rs @@ -1,4 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] use crate::ffi::CStr; use crate::io; use crate::num::NonZero; @@ -28,21 +27,25 @@ impl Thread { // CreateThread rounds up values for the stack size to the nearest page size (at least 4kb). // If a value of zero is given then the default stack size is used instead. - let ret = c::CreateThread( - ptr::null_mut(), - stack, - Some(thread_start), - p as *mut _, - c::STACK_SIZE_PARAM_IS_A_RESERVATION, - ptr::null_mut(), - ); - let ret = HandleOrNull::from_raw_handle(ret); + // SAFETY: `thread_start` has the right ABI for a thread's entry point. + // `p` is simply passed through to the new thread without being touched. + let ret = unsafe { + let ret = c::CreateThread( + ptr::null_mut(), + stack, + Some(thread_start), + p as *mut _, + c::STACK_SIZE_PARAM_IS_A_RESERVATION, + ptr::null_mut(), + ); + HandleOrNull::from_raw_handle(ret) + }; return if let Ok(handle) = ret.try_into() { Ok(Thread { handle: Handle::from_inner(handle) }) } else { // 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. - drop(Box::from_raw(p)); + unsafe { drop(Box::from_raw(p)) }; Err(io::Error::last_os_error()) }; @@ -50,7 +53,9 @@ impl Thread { // Next, reserve some stack space for if we otherwise run out of stack. stack_overflow::reserve_stack(); // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); + // SAFETY: We are simply recreating the box that was leaked earlier. + // It's the responsibility of the one who call `Thread::new` to ensure this is safe to call here. + unsafe { Box::from_raw(main as *mut Box<dyn FnOnce()>)() }; 0 } } @@ -70,7 +75,7 @@ impl Thread { /// /// `name` must end with a zero value pub unsafe fn set_name_wide(name: &[u16]) { - c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()); + unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) }; } pub fn join(self) { diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index a28a52e305e..961d45c5e83 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -1,4 +1,4 @@ -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod alloc; #[path = "../unsupported/args.rs"] diff --git a/library/std/src/sys/pal/zkvm/alloc.rs b/library/std/src/sys/pal/zkvm/alloc.rs index fd333f12151..2fdca223524 100644 --- a/library/std/src/sys/pal/zkvm/alloc.rs +++ b/library/std/src/sys/pal/zkvm/alloc.rs @@ -5,7 +5,7 @@ use crate::alloc::{GlobalAlloc, Layout, System}; unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - abi::sys_alloc_aligned(layout.size(), layout.align()) + unsafe { abi::sys_alloc_aligned(layout.size(), layout.align()) } } #[inline] diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index bacde9d880c..651f25d6623 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -6,6 +6,7 @@ //! This is all super highly experimental and not actually intended for //! wide/production use yet, it's still all in the experimental category. This //! will likely change over time. +#![forbid(unsafe_op_in_unsafe_fn)] const WORD_SIZE: usize = core::mem::size_of::<u32>(); diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs index 652fbe95a14..89f7f133e21 100644 --- a/library/std/src/sys/personality/dwarf/mod.rs +++ b/library/std/src/sys/personality/dwarf/mod.rs @@ -17,32 +17,30 @@ pub struct DwarfReader { pub ptr: *const u8, } -#[repr(C, packed)] -struct Unaligned<T>(T); - +#[forbid(unsafe_op_in_unsafe_fn)] impl DwarfReader { pub fn new(ptr: *const u8) -> DwarfReader { DwarfReader { ptr } } - // DWARF streams are packed, so e.g., a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. + /// Read a type T and then bump the pointer by that amount. + /// + /// DWARF streams are "packed", so all types must be read at align 1. pub unsafe fn read<T: Copy>(&mut self) -> T { - let Unaligned(result) = *(self.ptr as *const Unaligned<T>); - self.ptr = self.ptr.add(mem::size_of::<T>()); - result + unsafe { + let result = self.ptr.cast::<T>().read_unaligned(); + self.ptr = self.ptr.byte_add(mem::size_of::<T>()); + result + } } - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". + /// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable Length Data". pub unsafe fn read_uleb128(&mut self) -> u64 { let mut shift: usize = 0; let mut result: u64 = 0; let mut byte: u8; loop { - byte = self.read::<u8>(); + byte = unsafe { self.read::<u8>() }; result |= ((byte & 0x7F) as u64) << shift; shift += 7; if byte & 0x80 == 0 { @@ -57,7 +55,7 @@ impl DwarfReader { let mut result: u64 = 0; let mut byte: u8; loop { - byte = self.read::<u8>(); + byte = unsafe { self.read::<u8>() }; result |= ((byte & 0x7F) as u64) << shift; shift += 7; if byte & 0x80 == 0 { diff --git a/library/std/src/sys/sync/condvar/teeos.rs b/library/std/src/sys/sync/condvar/teeos.rs index 0a931f407d2..6457da91c2a 100644 --- a/library/std/src/sys/sync/condvar/teeos.rs +++ b/library/std/src/sys/sync/condvar/teeos.rs @@ -76,16 +76,16 @@ impl Condvar { #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let mutex = mutex::raw(mutex); + let mutex = unsafe { mutex::raw(mutex) }; self.verify(mutex); - let r = libc::pthread_cond_wait(raw(self), mutex); + let r = unsafe { libc::pthread_cond_wait(raw(self), mutex) }; debug_assert_eq!(r, 0); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { use crate::sys::time::Timespec; - let mutex = mutex::raw(mutex); + let mutex = unsafe { mutex::raw(mutex) }; self.verify(mutex); let timeout = Timespec::now(libc::CLOCK_MONOTONIC) @@ -93,7 +93,7 @@ impl Condvar { .and_then(|t| t.to_timespec()) .unwrap_or(TIMESPEC_MAX); - let r = pthread_cond_timedwait(raw(self), mutex, &timeout); + let r = unsafe { pthread_cond_timedwait(raw(self), mutex, &timeout) }; assert!(r == libc::ETIMEDOUT || r == 0); r == 0 } diff --git a/library/std/src/sys/sync/mutex/futex.rs b/library/std/src/sys/sync/mutex/futex.rs index 7427cae94d6..81afa94b147 100644 --- a/library/std/src/sys/sync/mutex/futex.rs +++ b/library/std/src/sys/sync/mutex/futex.rs @@ -1,19 +1,8 @@ -use crate::sync::atomic::{ - self, - Ordering::{Acquire, Relaxed, Release}, -}; -use crate::sys::futex::{futex_wait, futex_wake}; - -cfg_if::cfg_if! { -if #[cfg(windows)] { - // On Windows we can have a smol futex - type Atomic = atomic::AtomicU8; - type State = u8; -} else { - type Atomic = atomic::AtomicU32; - type State = u32; -} -} +use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; +use crate::sys::futex::{self, futex_wait, futex_wake}; + +type Atomic = futex::SmallAtomic; +type State = futex::SmallPrimitive; pub struct Mutex { futex: Atomic, diff --git a/library/std/src/sys/sync/once/futex.rs b/library/std/src/sys/sync/once/futex.rs index 609085dcd47..8a231e65ad1 100644 --- a/library/std/src/sys/sync/once/futex.rs +++ b/library/std/src/sys/sync/once/futex.rs @@ -57,7 +57,7 @@ impl<'a> Drop for CompletionGuard<'a> { // up on the Once. `futex_wake_all` does its own synchronization, hence // we do not need `AcqRel`. if self.state.swap(self.set_state_on_drop_to, Release) == QUEUED { - futex_wake_all(&self.state); + futex_wake_all(self.state); } } } diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index 61b29713fa1..0e38937b121 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -9,6 +9,7 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), diff --git a/library/std/src/sys/sync/thread_parking/futex.rs b/library/std/src/sys/sync/thread_parking/futex.rs index 588e7b27826..034eececb2a 100644 --- a/library/std/src/sys/sync/thread_parking/futex.rs +++ b/library/std/src/sys/sync/thread_parking/futex.rs @@ -1,15 +1,18 @@ +#![forbid(unsafe_op_in_unsafe_fn)] use crate::pin::Pin; -use crate::sync::atomic::AtomicU32; use crate::sync::atomic::Ordering::{Acquire, Release}; -use crate::sys::futex::{futex_wait, futex_wake}; +use crate::sys::futex::{self, futex_wait, futex_wake}; use crate::time::Duration; -const PARKED: u32 = u32::MAX; -const EMPTY: u32 = 0; -const NOTIFIED: u32 = 1; +type Atomic = futex::SmallAtomic; +type State = futex::SmallPrimitive; + +const PARKED: State = State::MAX; +const EMPTY: State = 0; +const NOTIFIED: State = 1; pub struct Parker { - state: AtomicU32, + state: Atomic, } // Notes about memory ordering: @@ -36,7 +39,7 @@ impl Parker { /// Construct the futex parker. The UNIX parker implementation /// requires this to happen in-place. pub unsafe fn new_in_place(parker: *mut Parker) { - parker.write(Self { state: AtomicU32::new(EMPTY) }); + unsafe { parker.write(Self { state: Atomic::new(EMPTY) }) }; } // Assumes this is only called by the thread that owns the Parker, diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index ed1a6437faa..0ebc5e093ee 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -1,5 +1,6 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", all(target_arch = "wasm32", target_feature = "atomics"), @@ -18,9 +19,9 @@ cfg_if::cfg_if! { ))] { mod id; pub use id::Parker; - } else if #[cfg(target_os = "windows")] { - mod windows; - pub use windows::Parker; + } else if #[cfg(target_vendor = "win7")] { + mod windows7; + pub use windows7::Parker; } else if #[cfg(all(target_vendor = "apple", not(miri)))] { mod darwin; pub use darwin::Parker; diff --git a/library/std/src/sys/sync/thread_parking/windows.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index 3a8d40dc5cf..3a8d40dc5cf 100644 --- a/library/std/src/sys/sync/thread_parking/windows.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index c8ee365392f..7b98f2ae763 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -159,7 +159,7 @@ mod tests; use crate::any::Any; -use crate::cell::{OnceCell, UnsafeCell}; +use crate::cell::{Cell, OnceCell, UnsafeCell}; use crate::env; use crate::ffi::{CStr, CString}; use crate::fmt; @@ -699,17 +699,22 @@ where } thread_local! { + // Invariant: `CURRENT` and `CURRENT_ID` will always be initialized together. + // If `CURRENT` is initialized, then `CURRENT_ID` will hold the same value + // as `CURRENT.id()`. static CURRENT: OnceCell<Thread> = const { OnceCell::new() }; + static CURRENT_ID: Cell<Option<ThreadId>> = const { Cell::new(None) }; } /// Sets the thread handle for the current thread. /// /// Aborts if the handle has been set already to reduce code size. pub(crate) fn set_current(thread: Thread) { + let tid = thread.id(); // Using `unwrap` here can add ~3kB to the binary size. We have complete // control over where this is called, so just abort if there is a bug. CURRENT.with(|current| match current.set(thread) { - Ok(()) => {} + Ok(()) => CURRENT_ID.set(Some(tid)), Err(_) => rtabort!("thread::set_current should only be called once per thread"), }); } @@ -719,7 +724,28 @@ pub(crate) fn set_current(thread: Thread) { /// In contrast to the public `current` function, this will not panic if called /// from inside a TLS destructor. pub(crate) fn try_current() -> Option<Thread> { - CURRENT.try_with(|current| current.get_or_init(|| Thread::new_unnamed()).clone()).ok() + CURRENT + .try_with(|current| { + current + .get_or_init(|| { + let thread = Thread::new_unnamed(); + CURRENT_ID.set(Some(thread.id())); + thread + }) + .clone() + }) + .ok() +} + +/// Gets the id of the thread that invokes it. +#[inline] +pub(crate) fn current_id() -> ThreadId { + CURRENT_ID.get().unwrap_or_else(|| { + // If `CURRENT_ID` isn't initialized yet, then `CURRENT` must also not be initialized. + // `current()` will initialize both `CURRENT` and `CURRENT_ID` so subsequent calls to + // `current_id()` will succeed immediately. + current().id() + }) } /// Gets a handle to the thread that invokes it. diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 7aff7fe1fdd..71cb796b937 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -25,7 +25,6 @@ #![feature(test)] #![allow(internal_features)] -// Public reexports pub use self::bench::{black_box, Bencher}; pub use self::console::run_tests_console; pub use self::options::{ColorConfig, Options, OutputFormat, RunIgnored, ShouldPanic}; diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs index bb32c70d663..98c54f038da 100644 --- a/library/test/src/test_result.rs +++ b/library/test/src/test_result.rs @@ -19,7 +19,15 @@ pub const TR_OK: i32 = 50; // On Windows we use __fastfail to abort, which is documented to use this // exception code. #[cfg(windows)] -const STATUS_ABORTED: i32 = 0xC0000409u32 as i32; +const STATUS_FAIL_FAST_EXCEPTION: i32 = 0xC0000409u32 as i32; + +// On Zircon (the Fuchsia kernel), an abort from userspace calls the +// LLVM implementation of __builtin_trap(), e.g., ud2 on x86, which +// raises a kernel exception. If a userspace process does not +// otherwise arrange exception handling, the kernel kills the process +// with this return code. +#[cfg(target_os = "fuchsia")] +const ZX_TASK_RETCODE_EXCEPTION_KILL: i32 = -1028; #[derive(Debug, Clone, PartialEq)] pub enum TestResult { @@ -96,7 +104,7 @@ pub fn get_result_from_exit_code( let result = match status.code() { Some(TR_OK) => TestResult::TrOk, #[cfg(windows)] - Some(STATUS_ABORTED) => TestResult::TrFailed, + Some(STATUS_FAIL_FAST_EXCEPTION) => TestResult::TrFailed, #[cfg(unix)] None => match status.signal() { Some(libc::SIGABRT) => TestResult::TrFailed, @@ -105,6 +113,9 @@ pub fn get_result_from_exit_code( } None => unreachable!("status.code() returned None but status.signal() was None"), }, + // Upon an abort, Fuchsia returns the status code ZX_TASK_RETCODE_EXCEPTION_KILL. + #[cfg(target_os = "fuchsia")] + Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => TestResult::TrFailed, #[cfg(not(unix))] None => TestResult::TrFailedMsg(format!("unknown return code")), #[cfg(any(windows, unix))] diff --git a/rustfmt.toml b/rustfmt.toml index e060fd8fe8b..8c1d3b94f19 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -31,7 +31,6 @@ ignore = [ "library/backtrace", "library/portable-simd", "library/stdarch", - "compiler/rustc_codegen_gcc", "src/doc/book", "src/doc/edition-guide", "src/doc/embedded-book", @@ -50,4 +49,8 @@ ignore = [ # These are ignored by a standard cargo fmt run. "compiler/rustc_codegen_cranelift/scripts", "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024 + "compiler/rustc_codegen_gcc/tests", + # Code automatically generated and included. + "compiler/rustc_codegen_gcc/src/intrinsic/archs.rs", + "compiler/rustc_codegen_gcc/example", ] diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 6e6c3660027..75ad37ce335 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -1,10 +1,6 @@ # These defaults are meant for contributors to tools which build on the # compiler, but do not modify it directly. [rust] -# This enables `RUSTC_LOG=debug`, avoiding confusing situations -# where adding `debug!()` appears to do nothing. -# However, it makes running the compiler slightly slower. -debug-logging = true # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true # Download rustc from CI instead of building it from source. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6a280a63358..d4dd3e546ec 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -14,7 +14,7 @@ use std::fs; use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Stdio; use std::str; use serde_derive::Deserialize; @@ -695,10 +695,10 @@ fn copy_sanitizers( || target == "x86_64-apple-ios" { // Update the library’s install name to reflect that it has been renamed. - apple_darwin_update_library_name(&dst, &format!("@rpath/{}", &runtime.name)); + apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name)); // Upon renaming the install name, the code signature of the file will invalidate, // so we will sign it again. - apple_darwin_sign_file(&dst); + apple_darwin_sign_file(builder, &dst); } target_deps.push(dst); @@ -707,25 +707,17 @@ fn copy_sanitizers( target_deps } -fn apple_darwin_update_library_name(library_path: &Path, new_name: &str) { - let status = Command::new("install_name_tool") - .arg("-id") - .arg(new_name) - .arg(library_path) - .status() - .expect("failed to execute `install_name_tool`"); - assert!(status.success()); +fn apple_darwin_update_library_name(builder: &Builder<'_>, library_path: &Path, new_name: &str) { + command("install_name_tool").arg("-id").arg(new_name).arg(library_path).run(builder); } -fn apple_darwin_sign_file(file_path: &Path) { - let status = Command::new("codesign") +fn apple_darwin_sign_file(builder: &Builder<'_>, file_path: &Path) { + command("codesign") .arg("-f") // Force to rewrite the existing signature .arg("-s") .arg("-") .arg(file_path) - .status() - .expect("failed to execute `codesign`"); - assert!(status.success()); + .run(builder); } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1171,7 +1163,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_profile_generate && target.is_msvc() { if let Some(ref clang_cl_path) = builder.config.llvm_clang_cl { // Add clang's runtime library directory to the search path - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); llvm_linker_flags.push_str(&format!("-L{}", clang_rt_dir.display())); } } @@ -1828,6 +1820,21 @@ impl Step for Assemble { &self_contained_lld_dir.join(exe(name, target_compiler.host)), ); } + + // In addition to `rust-lld` also install `wasm-component-ld` when + // LLD is enabled. This is a relatively small binary that primarily + // delegates to the `rust-lld` binary for linking and then runs + // logic to create the final binary. This is used by the + // `wasm32-wasip2` target of Rust. + let wasm_component_ld_exe = + builder.ensure(crate::core::build_steps::tool::WasmComponentLd { + compiler: build_compiler, + target: target_compiler.host, + }); + builder.copy_link( + &wasm_component_ld_exe, + &libdir_bin.join(wasm_component_ld_exe.file_name().unwrap()), + ); } if builder.config.llvm_enabled(target_compiler.host) { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 41dff2123f1..888290a0479 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -125,6 +125,7 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { generate_smart_stamp_hash( + builder, &builder.config.src.join("src/llvm-project"), builder.in_tree_llvm_info.sha().unwrap_or_default(), ) @@ -912,7 +913,7 @@ impl Step for Lld { if let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref() { // Find clang's runtime library directory and push that as a search path to the // cmake linker flags. - let clang_rt_dir = get_clang_cl_resource_dir(clang_cl_path); + let clang_rt_dir = get_clang_cl_resource_dir(builder, clang_cl_path); ldflags.push_all(format!("/libpath:{}", clang_rt_dir.display())); } } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 29cc5e00637..226b3729c10 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -8,6 +8,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::t; use crate::utils::change_tracker::CONFIG_CHANGE_HISTORY; +use crate::utils::exec::command; use crate::utils::helpers::{self, hex_encode}; use crate::Config; use sha2::Digest; @@ -16,7 +17,6 @@ use std::fmt::Write as _; use std::fs::File; use std::io::Write; use std::path::{Path, PathBuf, MAIN_SEPARATOR_STR}; -use std::process::Command; use std::str::FromStr; use std::{fmt, fs, io}; @@ -266,20 +266,16 @@ impl Step for Link { } let stage_path = ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR); - if !rustup_installed() { + if !rustup_installed(builder) { eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() { - attempt_toolchain_link(&stage_path[..]); + attempt_toolchain_link(builder, &stage_path[..]); } } } -fn rustup_installed() -> bool { - Command::new("rustup") - .arg("--version") - .stdout(std::process::Stdio::null()) - .output() - .map_or(false, |output| output.status.success()) +fn rustup_installed(builder: &Builder<'_>) -> bool { + command("rustup").capture_stdout().arg("--version").run(builder).is_success() } fn stage_dir_exists(stage_path: &str) -> bool { @@ -289,8 +285,8 @@ fn stage_dir_exists(stage_path: &str) -> bool { } } -fn attempt_toolchain_link(stage_path: &str) { - if toolchain_is_linked() { +fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { + if toolchain_is_linked(builder) { return; } @@ -301,7 +297,7 @@ fn attempt_toolchain_link(stage_path: &str) { return; } - if try_link_toolchain(stage_path) { + if try_link_toolchain(builder, stage_path) { println!( "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); @@ -315,14 +311,16 @@ fn attempt_toolchain_link(stage_path: &str) { } } -fn toolchain_is_linked() -> bool { - match Command::new("rustup") +fn toolchain_is_linked(builder: &Builder<'_>) -> bool { + match command("rustup") + .capture_stdout() + .allow_failure() .args(["toolchain", "list"]) - .stdout(std::process::Stdio::piped()) - .output() + .run(builder) + .stdout_if_ok() { - Ok(toolchain_list) => { - if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") { + Some(toolchain_list) => { + if !toolchain_list.contains("stage1") { return false; } // The toolchain has already been linked. @@ -330,7 +328,7 @@ fn toolchain_is_linked() -> bool { "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" ); } - Err(_) => { + None => { // In this case, we don't know if the `stage1` toolchain has been linked; // but `rustup` failed, so let's not go any further. println!( @@ -341,12 +339,12 @@ fn toolchain_is_linked() -> bool { true } -fn try_link_toolchain(stage_path: &str) -> bool { - Command::new("rustup") - .stdout(std::process::Stdio::null()) +fn try_link_toolchain(builder: &Builder<'_>, stage_path: &str) -> bool { + command("rustup") + .capture_stdout() .args(["toolchain", "link", "stage1", stage_path]) - .output() - .map_or(false, |output| output.status.success()) + .run(builder) + .is_success() } fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool { @@ -476,20 +474,18 @@ impl Step for Hook { if config.dry_run() { return; } - t!(install_git_hook_maybe(config)); + t!(install_git_hook_maybe(builder, config)); } } // install a git hook to automatically run tidy, if they want -fn install_git_hook_maybe(config: &Config) -> io::Result<()> { +fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<()> { let git = helpers::git(Some(&config.src)) + .capture() .args(["rev-parse", "--git-common-dir"]) - .as_command_mut() - .output() - .map(|output| { - assert!(output.status.success(), "failed to run `git`"); - PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) - })?; + .run(builder) + .stdout(); + let git = PathBuf::from(git.trim()); let hooks_dir = git.join("hooks"); let dst = hooks_dir.join("pre-push"); if dst.exists() { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 4d69d6b5231..3f0cbde64e3 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -9,7 +9,6 @@ use std::ffi::OsString; use std::fs; use std::iter; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; use clap_complete::shells; @@ -169,12 +168,8 @@ You can skip linkcheck with --skip src/tools/linkchecker" } } -fn check_if_tidy_is_installed() -> bool { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) +fn check_if_tidy_is_installed(builder: &Builder<'_>) -> bool { + command("tidy").capture_stdout().allow_failure().arg("--version").run(builder).is_success() } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -188,8 +183,9 @@ impl Step for HtmlCheck { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; let run = run.path("src/tools/html-checker"); - run.lazy_default_condition(Box::new(check_if_tidy_is_installed)) + run.lazy_default_condition(Box::new(|| check_if_tidy_is_installed(builder))) } fn make_run(run: RunConfig<'_>) { @@ -197,7 +193,7 @@ impl Step for HtmlCheck { } fn run(self, builder: &Builder<'_>) { - if !check_if_tidy_is_installed() { + if !check_if_tidy_is_installed(builder) { eprintln!("not running HTML-check tool because `tidy` is missing"); eprintln!( "You need the HTML tidy tool https://www.html-tidy.org/, this tool is *not* part of the rust project and needs to be installed separately, for example via your package manager." @@ -2099,9 +2095,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let git_config = builder.config.git_config(); cmd.arg("--git-repository").arg(git_config.git_repository); cmd.arg("--nightly-branch").arg(git_config.nightly_branch); - - // FIXME: Move CiEnv back to bootstrap, it is only used here anyway - builder.ci_env.force_coloring_in_ci(cmd.as_command_mut()); + cmd.force_coloring_in_ci(builder.ci_env); #[cfg(feature = "build-metrics")] builder.metrics.begin_test_suite( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index ad92a01bce7..2f8b41334fc 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -337,6 +337,7 @@ bootstrap_tool!( RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper"; + WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -857,6 +858,15 @@ impl Step for LlvmBitcodeLinker { &self.extra_features, ); + let _guard = builder.msg_tool( + Kind::Build, + Mode::ToolRustc, + bin_name, + self.compiler.stage, + &self.compiler.host, + &self.target, + ); + cargo.into_cmd().run(builder); let tool_out = builder diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 9ddd68da59d..2ab0ce7454b 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -99,24 +99,16 @@ fn print_error(tool: &str, submodule: &str) { crate::exit!(3); } -fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) { +fn check_changed_files(builder: &Builder<'_>, toolstates: &HashMap<Box<str>, ToolState>) { // Changed files let output = helpers::git(None) + .capture() .arg("diff") .arg("--name-status") .arg("HEAD") .arg("HEAD^") - .as_command_mut() - .output(); - let output = match output { - Ok(o) => o, - Err(e) => { - eprintln!("Failed to get changed files: {e:?}"); - crate::exit!(1); - } - }; - - let output = t!(String::from_utf8(output.stdout)); + .run(builder) + .stdout(); for (tool, submodule) in STABLE_TOOLS.iter().chain(NIGHTLY_TOOLS.iter()) { let changed = output.lines().any(|l| l.starts_with('M') && l.ends_with(submodule)); @@ -186,8 +178,8 @@ impl Step for ToolStateCheck { crate::exit!(1); } - check_changed_files(&toolstates); - checkout_toolstate_repo(); + check_changed_files(builder, &toolstates); + checkout_toolstate_repo(builder); let old_toolstate = read_old_toolstate(); for (tool, _) in STABLE_TOOLS.iter() { @@ -231,7 +223,7 @@ impl Step for ToolStateCheck { } if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() { - commit_toolstate_change(&toolstates); + commit_toolstate_change(builder, &toolstates); } } @@ -315,55 +307,34 @@ fn toolstate_repo() -> String { const TOOLSTATE_DIR: &str = "rust-toolstate"; /// Checks out the toolstate repo into `TOOLSTATE_DIR`. -fn checkout_toolstate_repo() { +fn checkout_toolstate_repo(builder: &Builder<'_>) { if let Ok(token) = env::var("TOOLSTATE_REPO_ACCESS_TOKEN") { - prepare_toolstate_config(&token); + prepare_toolstate_config(builder, &token); } if Path::new(TOOLSTATE_DIR).exists() { eprintln!("Cleaning old toolstate directory..."); t!(fs::remove_dir_all(TOOLSTATE_DIR)); } - let status = helpers::git(None) + helpers::git(None) .arg("clone") .arg("--depth=1") .arg(toolstate_repo()) .arg(TOOLSTATE_DIR) - .as_command_mut() - .status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git clone unsuccessful (status: {status:?})"); - } + .run(builder); } /// Sets up config and authentication for modifying the toolstate repo. -fn prepare_toolstate_config(token: &str) { - fn git_config(key: &str, value: &str) { - let status = helpers::git(None) - .arg("config") - .arg("--global") - .arg(key) - .arg(value) - .as_command_mut() - .status(); - let success = match status { - Ok(s) => s.success(), - Err(_) => false, - }; - if !success { - panic!("git config key={key} value={value} failed (status: {status:?})"); - } +fn prepare_toolstate_config(builder: &Builder<'_>, token: &str) { + fn git_config(builder: &Builder<'_>, key: &str, value: &str) { + helpers::git(None).arg("config").arg("--global").arg(key).arg(value).run(builder); } // If changing anything here, then please check that `src/ci/publish_toolstate.sh` is up to date // as well. - git_config("user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); - git_config("user.name", "Rust Toolstate Update"); - git_config("credential.helper", "store"); + git_config(builder, "user.email", "7378925+rust-toolstate-update@users.noreply.github.com"); + git_config(builder, "user.name", "Rust Toolstate Update"); + git_config(builder, "credential.helper", "store"); let credential = format!("https://{token}:x-oauth-basic@github.com\n",); let git_credential_path = PathBuf::from(t!(env::var("HOME"))).join(".git-credentials"); @@ -403,55 +374,51 @@ fn read_old_toolstate() -> Vec<RepoState> { /// /// * See <https://help.github.com/articles/about-commit-email-addresses/> /// if a private email by GitHub is wanted. -fn commit_toolstate_change(current_toolstate: &ToolstateData) { +fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) { let message = format!("({} CI update)", OS.expect("linux/windows only")); let mut success = false; for _ in 1..=5 { // Upload the test results (the new commit-to-toolstate mapping) to the toolstate repo. // This does *not* change the "current toolstate"; that only happens post-landing // via `src/ci/docker/publish_toolstate.sh`. - publish_test_results(current_toolstate); + publish_test_results(builder, current_toolstate); // `git commit` failing means nothing to commit. - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("commit") .arg("-a") .arg("-m") .arg(&message) - .as_command_mut() - .status()); - if !status.success() { + .run(builder); + if !status.is_success() { success = true; break; } - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + let status = helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .allow_failure() .arg("push") .arg("origin") .arg("master") - .as_command_mut() - .status()); + .run(builder); // If we successfully push, exit. - if status.success() { + if status.is_success() { success = true; break; } eprintln!("Sleeping for 3 seconds before retrying push"); std::thread::sleep(std::time::Duration::from_secs(3)); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("fetch") .arg("origin") .arg("master") - .as_command_mut() - .status()); - assert!(status.success()); - let status = t!(helpers::git(Some(Path::new(TOOLSTATE_DIR))) + .run(builder); + helpers::git(Some(Path::new(TOOLSTATE_DIR))) .arg("reset") .arg("--hard") .arg("origin/master") - .as_command_mut() - .status()); - assert!(status.success()); + .run(builder); } if !success { @@ -464,9 +431,8 @@ fn commit_toolstate_change(current_toolstate: &ToolstateData) { /// These results will later be promoted to `latest.json` by the /// `publish_toolstate.py` script if the PR passes all tests and is merged to /// master. -fn publish_test_results(current_toolstate: &ToolstateData) { - let commit = t!(helpers::git(None).arg("rev-parse").arg("HEAD").as_command_mut().output()); - let commit = t!(String::from_utf8(commit.stdout)); +fn publish_test_results(builder: &Builder<'_>, current_toolstate: &ToolstateData) { + let commit = helpers::git(None).capture().arg("rev-parse").arg("HEAD").run(builder).stdout(); let toolstate_serialized = t!(serde_json::to_string(¤t_toolstate)); diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index f033905e9f6..6d6df650b14 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -473,9 +473,41 @@ impl StepDescription { return; } - // Handle all PathSets. + let mut path_lookup: Vec<(PathBuf, bool)> = + paths.clone().into_iter().map(|p| (p, false)).collect(); + + // List of `(usize, &StepDescription, Vec<PathSet>)` where `usize` is the closest index of a path + // compared to the given CLI paths. So we can respect to the CLI order by using this value to sort + // the steps. + let mut steps_to_run = vec![]; + for (desc, should_run) in v.iter().zip(&should_runs) { let pathsets = should_run.pathset_for_paths_removing_matches(&mut paths, desc.kind); + + // This value is used for sorting the step execution order. + // By default, `usize::MAX` is used as the index for steps to assign them the lowest priority. + // + // If we resolve the step's path from the given CLI input, this value will be updated with + // the step's actual index. + let mut closest_index = usize::MAX; + + // Find the closest index from the original list of paths given by the CLI input. + for (index, (path, is_used)) in path_lookup.iter_mut().enumerate() { + if !*is_used && !paths.contains(path) { + closest_index = index; + *is_used = true; + break; + } + } + + steps_to_run.push((closest_index, desc, pathsets)); + } + + // Sort the steps before running them to respect the CLI order. + steps_to_run.sort_by_key(|(index, _, _)| *index); + + // Handle all PathSets. + for (_index, desc, pathsets) in steps_to_run { if !pathsets.is_empty() { desc.maybe_run(builder, pathsets); } @@ -2001,6 +2033,7 @@ impl<'a> Builder<'a> { // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // of the individual lints are satisfied. rustflags.arg("-Wkeyword_idents_2024"); + rustflags.arg("-Wunsafe_op_in_unsafe_fn"); } if self.config.rust_frame_pointers { @@ -2108,7 +2141,7 @@ impl<'a> Builder<'a> { // Try to use a sysroot-relative bindir, in case it was configured absolutely. cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative()); - self.ci_env.force_coloring_in_ci(cargo.as_command_mut()); + cargo.force_coloring_in_ci(self.ci_env); // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d01a910e815..56a8528d0a1 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -706,7 +706,7 @@ download-rustc = false let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now); let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build)); - let llvm_config_file = t!(File::open(llvm_config)); + let llvm_config_file = t!(File::options().write(true).open(llvm_config)); t!(llvm_config_file.set_times(file_times)); diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 60b137dd4e5..a77c20067e6 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -23,7 +23,7 @@ use std::fmt::Display; use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::Command; use std::str; use std::sync::OnceLock; use std::time::SystemTime; @@ -36,7 +36,7 @@ use utils::channel::GitInfo; use utils::helpers::hex_encode; use crate::core::builder; -use crate::core::builder::Kind; +use crate::core::builder::{Builder, Kind}; use crate::core::config::{flags, LldMode}; use crate::core::config::{DryRun, Target}; use crate::core::config::{LlvmLibunwind, TargetSelection}; @@ -489,18 +489,29 @@ impl Build { return; } - let submodule_git = || helpers::git(Some(&absolute_path)); + // Submodule updating actually happens during in the dry run mode. We need to make sure that + // all the git commands below are actually executed, because some follow-up code + // in bootstrap might depend on the submodules being checked out. Furthermore, not all + // the command executions below work with an empty output (produced during dry run). + // Therefore, all commands below are marked with `run_always()`, so that they also run in + // dry run mode. + let submodule_git = || { + let mut cmd = helpers::git(Some(&absolute_path)).capture_stdout(); + cmd.run_always(); + cmd + }; // Determine commit checked out in submodule. - let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut()); + let checked_out_hash = submodule_git().args(["rev-parse", "HEAD"]).run(self).stdout(); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. - let recorded = output( - helpers::git(Some(&self.src)) - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .as_command_mut(), - ); + let recorded = helpers::git(Some(&self.src)) + .capture_stdout() + .run_always() + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .run(self) + .stdout(); let actual_hash = recorded .split_whitespace() .nth(2) @@ -513,6 +524,7 @@ impl Build { println!("Updating submodule {}", relative_path.display()); helpers::git(Some(&self.src)) + .run_always() .args(["submodule", "-q", "sync"]) .arg(relative_path) .run(self); @@ -521,21 +533,17 @@ impl Build { let update = |progress: bool| { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. - let current_branch = { - let output = helpers::git(Some(&self.src)) - .args(["symbolic-ref", "--short", "HEAD"]) - .as_command_mut() - .stderr(Stdio::inherit()) - .output(); - let output = t!(output); - if output.status.success() { - Some(String::from_utf8(output.stdout).unwrap().trim().to_owned()) - } else { - None - } - }; + let current_branch = helpers::git(Some(&self.src)) + .capture_stdout() + .allow_failure() + .run_always() + .args(["symbolic-ref", "--short", "HEAD"]) + .run(self) + .stdout_if_ok() + .map(|s| s.trim().to_owned()); - let mut git = helpers::git(Some(&self.src)); + let mut git = helpers::git(Some(&self.src)).allow_failure(); + git.run_always(); if let Some(branch) = current_branch { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. @@ -549,8 +557,7 @@ impl Build { git.arg(relative_path); git }; - // NOTE: doesn't use `try_run` because this shouldn't print an error if it fails. - if !update(true).as_command_mut().status().map_or(false, |status| status.success()) { + if !update(true).run(self).is_success() { update(false).run(self); } @@ -1946,22 +1953,28 @@ fn envify(s: &str) -> String { /// /// In case of errors during `git` command execution (e.g., in tarball sources), default values /// are used to prevent panics. -pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String { +pub fn generate_smart_stamp_hash( + builder: &Builder<'_>, + dir: &Path, + additional_input: &str, +) -> String { let diff = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("diff") - .as_command_mut() - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let status = helpers::git(Some(dir)) + .capture_stdout() + .allow_failure() .arg("status") .arg("--porcelain") .arg("-z") .arg("--untracked-files=normal") - .as_command_mut() - .output() - .map(|o| String::from_utf8(o.stdout).unwrap_or_default()) + .run(builder) + .stdout_if_ok() .unwrap_or_default(); let mut hasher = sha2::Sha256::new(); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index ccab25e55a9..6a7c5c0f9b7 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -200,4 +200,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "`llvm.lld` is enabled by default for the dist profile. If set to false, `lld` will not be included in the dist build.", }, + ChangeInfo { + change_id: 127913, + severity: ChangeSeverity::Warning, + summary: "`debug-logging` option has been removed from the default `tools` profile.", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index b0530164997..a60c0084f3d 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -1,4 +1,5 @@ use crate::Build; +use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; use std::ffi::OsStr; use std::fmt::{Debug, Formatter}; @@ -171,6 +172,18 @@ impl BootstrapCommand { pub fn get_created_location(&self) -> std::panic::Location<'static> { self.drop_bomb.get_created_location() } + + /// If in a CI environment, forces the command to run with colors. + pub fn force_coloring_in_ci(&mut self, ci_env: CiEnv) { + if ci_env != CiEnv::None { + // Due to use of stamp/docker, the output stream of bootstrap is not + // a TTY in CI, so coloring is by-default turned off. + // The explicit `TERM=xterm` environment is needed for + // `--color always` to actually work. This env var was lost when + // compiling through the Makefile. Very strange. + self.env("TERM", "xterm").args(["--color", "always"]); + } + } } impl Debug for BootstrapCommand { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 15133e441b4..3c82fa189be 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -338,13 +338,13 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource /// directory to the linker flags, otherwise there will be linker errors about the profiler runtime /// missing. This function returns the path to that directory. -pub fn get_clang_cl_resource_dir(clang_cl_path: &str) -> PathBuf { +pub fn get_clang_cl_resource_dir(builder: &Builder<'_>, clang_cl_path: &str) -> PathBuf { // Similar to how LLVM does it, to find clang's library runtime directory: // - we ask `clang-cl` to locate the `clang_rt.builtins` lib. - let mut builtins_locator = Command::new(clang_cl_path); + let mut builtins_locator = command(clang_cl_path); builtins_locator.args(["/clang:-print-libgcc-file-name", "/clang:--rtlib=compiler-rt"]); - let clang_rt_builtins = output(&mut builtins_locator); + let clang_rt_builtins = builtins_locator.capture_stdout().run(builder).stdout(); let clang_rt_builtins = Path::new(clang_rt_builtins.trim()); assert!( clang_rt_builtins.exists(), diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index f5fc94273c9..9378c35127f 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -369,13 +369,13 @@ impl<'a> Tarball<'a> { // gets the same timestamp. if self.builder.rust_info().is_managed_git_subrepository() { // %ct means committer date - let timestamp = helpers::output( - helpers::git(Some(&self.builder.src)) - .arg("log") - .arg("-1") - .arg("--format=%ct") - .as_command_mut(), - ); + let timestamp = helpers::git(Some(&self.builder.src)) + .capture_stdout() + .arg("log") + .arg("-1") + .arg("--format=%ct") + .run(self.builder) + .stdout(); cmd.args(["--override-file-mtime", timestamp.trim()]); } diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index e3cb396b782..962484593b4 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -112,6 +112,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,wasm32-wasip1 ENV TARGETS=$TARGETS,wasm32-wasip1-threads +ENV TARGETS=$TARGETS,wasm32-wasip2 ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 0d9c21c4487..571378774be 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -37,6 +37,7 @@ RUN sh /scripts/sccache.sh COPY host-x86_64/mingw-check/reuse-requirements.txt /tmp/ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-requirements.txt +COPY host-x86_64/mingw-check/check-default-config-profiles.sh /scripts/ COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ @@ -46,6 +47,7 @@ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 # We disable optimized compiler built-ins because that requires a C toolchain for the target. # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. ENV SCRIPT python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ + /scripts/check-default-config-profiles.sh && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py clippy bootstrap -Dwarnings && \ python3 ../x.py clippy compiler library -Aclippy::all -Dclippy::correctness && \ diff --git a/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh b/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh new file mode 100755 index 00000000000..d706927d6d9 --- /dev/null +++ b/src/ci/docker/host-x86_64/mingw-check/check-default-config-profiles.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Runs bootstrap (in dry-run mode) with each default config profile to ensure they are not broken. + +set -euo pipefail + +config_dir="../src/bootstrap/defaults" + +# Loop through each configuration file in the directory +for config_file in "$config_dir"/*.toml; +do + python3 ../x.py check --config $config_file --dry-run +done diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 53b4583166d..a5a5acc333b 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -8,6 +8,10 @@ X_PY="$1" # Try to test the toolstate-tracked tools and store the build/test success in the TOOLSTATE_FILE. +# Pre-build the compiler and the library first to output a better error message when the build +# itself fails (see https://github.com/rust-lang/rust/issues/127869 for context). +python3 "$X_PY" build --stage 2 compiler rustdoc + set +e python3 "$X_PY" test --stage 2 --no-fail-fast \ src/doc/book \ diff --git a/src/doc/book b/src/doc/book -Subproject f1e49bf7a8ea6c31ce016a52b8a4f6e1ffcfbc6 +Subproject 67fa536768013d9d5a13f3a06790521d511ef71 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 941db8b3df45fd46cd87b50a5c86714b91dcde9 +Subproject 5454de3d12b9ccc6375b629cf7ccda8264640aa diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject b10c6acaf0f43481f6600e95d4b5013446e29f7 +Subproject 019f3928d8b939ec71b63722dcc2e4633015644 diff --git a/src/doc/reference b/src/doc/reference -Subproject 1ae3deebc3ac16e276b6558e01420f8e605def0 +Subproject e2f0bdc4031866734661dcdb548184bde1450ba diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 658c6c27cb975b92227936024816986c2d3716f +Subproject 89aecb6951b77bc746da73df8c9f2b2ceaad494 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject d6e3a32a557db5902e714604def8015d6bb7e0f +Subproject 0c4d55cb59fe440d1a630e4e5774d043968edb3 diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index cd10168bc1c..cb43feca758 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -410,13 +410,16 @@ See also the [`no-prepopulate-passes`](#no-prepopulate-passes) flag. By default, `rustc` prefers to statically link dependencies. This option will indicate that dynamic linking should be used if possible if both a static and -dynamic versions of a library are available. There is an internal algorithm -for determining whether or not it is possible to statically or dynamically -link with a dependency. For example, `cdylib` crate types may only use static -linkage. This flag takes one of the following values: +dynamic versions of a library are available. -* `y`, `yes`, `on`, `true` or no value: use dynamic linking. -* `n`, `no`, `off` or `false`: use static linking (the default). +There is [an internal algorithm](https://github.com/rust-lang/rust/blob/master/compiler/rustc_metadata/src/dependency_format.rs) +for determining whether or not it is possible to statically or dynamically link +with a dependency. + +This flag takes one of the following values: + +* `y`, `yes`, `on`, `true` or no value: prefer dynamic linking. +* `n`, `no`, `off` or `false`: prefer static linking (the default). ## profile-generate diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index dce50ebf29c..f42b9cb5978 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -117,8 +117,7 @@ fn baz() {} In various cases, the default Rust style specifies to sort things. If not otherwise specified, such sorting should be "version sorting", which ensures that (for instance) `x8` comes before `x16` even though the character `1` comes -before the character `8`. (If not otherwise specified, version-sorting is -lexicographical.) +before the character `8`. For the purposes of the Rust style, to compare two strings for version-sorting: @@ -132,12 +131,13 @@ For the purposes of the Rust style, to compare two strings for version-sorting: these strings, treat the chunks as equal (moving on to the next chunk) but remember which string had more leading zeroes. - To compare two chunks if both are not numeric, compare them by Unicode - character lexicographically, except that `_` (underscore) sorts immediately - after ` ` (space) but before any other character. (This treats underscore as - a word separator, as commonly used in identifiers.) - - If the use of version sorting specifies further modifiers, such as sorting - non-lowercase before lowercase, apply those modifiers to the lexicographic - sort in this step. + character lexicographically, with two exceptions: + - `_` (underscore) sorts immediately after ` ` (space) but before any other + character. (This treats underscore as a word separator, as commonly used in + identifiers.) + - Unless otherwise specified, version-sorting should sort non-lowercase + characters (characters that can start an `UpperCamelCase` identifier) + before lowercase characters. - If the comparison reaches the end of the string and considers each pair of chunks equal: - If one of the numeric comparisons noted the earliest point at which one @@ -157,7 +157,17 @@ leading zeroes. As an example, version-sorting will sort the following strings in the order given: -- `_ZYWX` +- `_ZYXW` +- `_abcd` +- `A2` +- `ABCD` +- `Z_YXW` +- `ZY_XW` +- `ZY_XW` +- `ZYXW` +- `ZYXW_` +- `a1` +- `abcd` - `u_zzz` - `u8` - `u16` @@ -190,11 +200,7 @@ given: - `x86_64` - `x86_128` - `x87` -- `Z_YWX` -- `ZY_WX` -- `ZYW_X` -- `ZYWX` -- `ZYWX_` +- `zyxw` ### [Module-level items](items.md) diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index c0628691b77..8e1b1d80fb6 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -489,10 +489,8 @@ foo::{ A *group* of imports is a set of imports on the same or sequential lines. One or more blank lines or other items (e.g., a function) separate groups of imports. -Within a group of imports, imports must be version-sorted, except that -non-lowercase characters (characters that can start an `UpperCamelCase` -identifier) must be sorted before lowercase characters. Groups of imports must -not be merged or re-ordered. +Within a group of imports, imports must be version-sorted. Groups of imports +must not be merged or re-ordered. E.g., input: @@ -520,9 +518,7 @@ re-ordering. ### Ordering list import Names in a list import must be version-sorted, except that: -- `self` and `super` always come first if present, -- non-lowercase characters (characters that can start an `UpperCamelCase` - identifier) must be sorted before lowercase characters, and +- `self` and `super` always come first if present, and - groups and glob imports always come last if present. This applies recursively. For example, `a::*` comes before `b::a` but `a::b` diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 3d7ead99282..599e1e8102c 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -266,6 +266,7 @@ def get_known_directive_names(): # To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put # it into a common file which is included in rust code and parsed here. # FIXME: This setup is temporary until we figure out how to improve this situation. +# See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. KNOWN_DIRECTIVE_NAMES = get_known_directive_names() LINE_PATTERN = re.compile(r''' diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a0e28d2f55c..e3c4602212c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -285,10 +285,17 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> } pub(crate) fn clean_const<'tcx>( - constant: &hir::ConstArg<'_>, + constant: &hir::ConstArg<'tcx>, _cx: &mut DocContext<'tcx>, ) -> Constant { - Constant { kind: ConstantKind::Anonymous { body: constant.value.body } } + match &constant.kind { + hir::ConstArgKind::Path(qpath) => { + Constant { kind: ConstantKind::Path { path: qpath_to_string(&qpath).into() } } + } + hir::ConstArgKind::Anon(anon) => { + Constant { kind: ConstantKind::Anonymous { body: anon.body } } + } + } } pub(crate) fn clean_middle_const<'tcx>( @@ -431,7 +438,7 @@ fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Te match term { hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)), hir::Term::Const(c) => Term::Constant(clean_middle_const( - ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, c.def_id)), + ty::Binder::dummy(ty::Const::from_const_arg(cx.tcx, c, ty::FeedConstTy::No)), cx, )), } @@ -633,8 +640,9 @@ fn clean_generic_param<'tcx>( param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), - default: default - .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), + default: default.map(|ct| { + Box::new(ty::Const::from_const_arg(cx.tcx, ct, ty::FeedConstTy::No).to_string()) + }), synthetic, }, ), @@ -1820,7 +1828,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::Array(ty, ref length) => { let length = match length { hir::ArrayLen::Infer(..) => "_".to_string(), - hir::ArrayLen::Body(anon_const) => { + hir::ArrayLen::Body(const_arg) => { // NOTE(min_const_generics): We can't use `const_eval_poly` for constants // as we currently do not supply the parent generics to anonymous constants // but do allow `ConstKind::Param`. @@ -1828,9 +1836,18 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T // `const_eval_poly` tries to first substitute generic parameters which // results in an ICE while manually constructing the constant and using `eval` // does nothing for `ConstKind::Param`. - let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id); - let param_env = cx.tcx.param_env(anon_const.def_id); - print_const(cx, ct.normalize(cx.tcx, param_env)) + let ct = ty::Const::from_const_arg(cx.tcx, const_arg, ty::FeedConstTy::No); + let ct = if let hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) = + const_arg.kind + { + // Only anon consts can implicitly capture params. + // FIXME: is this correct behavior? + let param_env = cx.tcx.param_env(*def_id); + ct.normalize(cx.tcx, param_env) + } else { + ct + }; + print_const(cx, ct) } }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a31adc9949a..37099531596 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2395,6 +2395,9 @@ pub(crate) enum ConstantKind { /// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified /// by a DefId. So this field must be different from `Extern`. TyConst { expr: Box<str> }, + /// A constant that is just a path (i.e., referring to a const param, free const, etc.). + // FIXME: this is an unfortunate representation. rustdoc's logic around consts needs to be improved. + Path { path: Box<str> }, /// A constant (expression) that's not an item or associated item. These are usually found /// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also /// used to define explicit discriminant values for enum variants. @@ -2423,6 +2426,7 @@ impl ConstantKind { pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String { match *self { ConstantKind::TyConst { ref expr } => expr.to_string(), + ConstantKind::Path { ref path } => path.to_string(), ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id), ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { rendered_const(tcx, tcx.hir().body(body), tcx.hir().body_owner_def_id(body)) @@ -2432,7 +2436,9 @@ impl ConstantKind { pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> { match *self { - ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None, + ConstantKind::TyConst { .. } + | ConstantKind::Path { .. } + | ConstantKind::Anonymous { .. } => None, ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => { print_evaluated_const(tcx, def_id, true, true) } @@ -2441,7 +2447,9 @@ impl ConstantKind { pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool { match *self { - ConstantKind::TyConst { .. } | ConstantKind::Extern { .. } => false, + ConstantKind::TyConst { .. } + | ConstantKind::Extern { .. } + | ConstantKind::Path { .. } => false, ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { is_literal_expr(tcx, body.hir_id) } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4c0ba75d261..28ed94432c8 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -15,6 +15,7 @@ --desktop-sidebar-width: 200px; --src-sidebar-width: 300px; --desktop-sidebar-z-index: 100; + --sidebar-elems-left-padding: 24px; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -559,8 +560,11 @@ ul.block, .block li { .sidebar > h2 a { display: block; padding: 0.25rem; /* 4px */ - margin-left: -0.25rem; margin-right: 0.25rem; + /* extend click target to far edge of screen (mile wide bar) */ + border-left: solid var(--sidebar-elems-left-padding) transparent; + margin-left: calc(-0.25rem - var(--sidebar-elems-left-padding)); + background-clip: border-box; } .sidebar h2 { @@ -578,7 +582,7 @@ ul.block, .block li { .sidebar-elems, .sidebar > .version, .sidebar > h2 { - padding-left: 24px; + padding-left: var(--sidebar-elems-left-padding); } .sidebar a { @@ -632,13 +636,55 @@ ul.block, .block li { .sidebar-crate .logo-container { /* The logo is expected to have 8px "slop" along its edges, so we can optically center it. */ - margin: 0 -16px 0 -16px; + margin: 0 calc(-16px - var(--sidebar-elems-left-padding)); + padding: 0 var(--sidebar-elems-left-padding); text-align: center; } +.sidebar-crate .logo-container img { + /* When in a horizontal logo lockup, the highlight color of the crate name menu item + extends underneath the actual logo (in a vertical lockup, that background highlight + extends to the left edge of the screen). + + To prevent a weird-looking colored band from appearing under the logo, cover it up + with the sidebar's background. Additionally, the crate name extends slightly above + the logo, so that its highlight has a bit of space to let the ascenders breath while + also having those ascenders meet exactly with the top of the logo. + + In ANSI art, make it look like this: + | ┌─────┐ + | (R) │ std │ + | └─────┘ + + Not like this (which would happen without the z-index): + | ┌────────┐ + | (│ std │ + | └────────┘ + + Not like this (which would happen without the background): + | ┌────────┐ + | (R) std │ + | └────────┘ + + Nor like this (which would happen without the negative margin): + | ─────────┐ + | (R) │ std │ + | └─────┘ + */ + margin-top: -16px; + border-top: solid 16px transparent; + box-sizing: content-box; + position: relative; + background-clip: border-box; + z-index: 1; +} + .sidebar-crate h2 a { display: block; - margin: 0 calc(-24px + 0.25rem) 0 -0.2rem; + /* extend click target to far edge of screen (mile wide bar) */ + border-left: solid var(--sidebar-elems-left-padding) transparent; + background-clip: border-box; + margin: 0 calc(-24px + 0.25rem) 0 calc(-0.2rem - var(--sidebar-elems-left-padding)); /* Align the sidebar crate link with the search bar, which have different font sizes. @@ -2127,6 +2173,14 @@ in src-script.js and main.js padding: 2px 4px; box-shadow: 0 0 4px var(--main-background-color); } + + .item-table > li > .item-name { + width: 33%; + } + .item-table > li > div { + padding-bottom: 5px; + word-break: break-all; + } } @media print { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 64c35660778..9506bc9ed22 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -529,11 +529,13 @@ function preLoadCss(cssUrl) { } const link = document.createElement("a"); link.href = path; - if (path === current_page) { - link.className = "current"; - } link.textContent = name; const li = document.createElement("li"); + // Don't "optimize" this to just use `path`. + // We want the browser to normalize this into an absolute URL. + if (link.href === current_page) { + li.classList.add("current"); + } li.appendChild(link); ul.appendChild(li); } diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 233fed4151c..6d79c7c83ad 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -1,5 +1,3 @@ -use std::process::Command; - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum CiEnv { /// Not a CI environment. @@ -21,18 +19,6 @@ impl CiEnv { pub fn is_ci() -> bool { Self::current() != CiEnv::None } - - /// If in a CI environment, forces the command to run with colors. - pub fn force_coloring_in_ci(self, cmd: &mut Command) { - if self != CiEnv::None { - // Due to use of stamp/docker, the output stream of bootstrap is not - // a TTY in CI, so coloring is by-default turned off. - // The explicit `TERM=xterm` environment is needed for - // `--color always` to actually work. This env var was lost when - // compiling through the Makefile. Very strange. - cmd.env("TERM", "xterm").args(&["--color", "always"]); - } - } } pub mod gha { diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 154fdac39ae9629954e19e9986fd2cf2cdd8d96 +Subproject a2b58c3dad4d554ba01ed6c45c41ff85390560f diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index c9bfc9c85d9..d94b0cce948 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -106,13 +106,12 @@ fn might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { /// /// This is a fail-safe to a case where even the `is_from_proc_macro` is unable to determain the /// correct result. - fn repeat_expr_might_be_expanded<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { - let ExprKind::Repeat(_, ArrayLen::Body(anon_const)) = expr.kind else { + fn repeat_expr_might_be_expanded<'tcx>(expr: &Expr<'tcx>) -> bool { + let ExprKind::Repeat(_, ArrayLen::Body(len_ct)) = expr.kind else { return false; }; - let len_span = cx.tcx.def_span(anon_const.def_id); - !expr.span.contains(len_span) + !expr.span.contains(len_ct.span()) } - expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(cx, expr) + expr.span.from_expansion() || is_from_proc_macro(cx, expr) || repeat_expr_might_be_expanded(expr) } diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 09225ac3246..6f5505e8a63 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -235,7 +235,7 @@ impl<'tcx> NonCopyConst<'tcx> { fn is_value_unfrozen_raw( cx: &LateContext<'tcx>, - result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>, + result: Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>, ty: Ty<'tcx>, ) -> bool { result.map_or_else( diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs index 462084e96a8..db8c63892b8 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::has_repr_attr; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Const; +use rustc_middle::ty::{Const, FeedConstTy}; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -53,14 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { } } -fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool { +fn is_struct_with_trailing_zero_sized_array<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool { if let ItemKind::Struct(data, _) = &item.kind // First check if last field is an array && let Some(last_field) = data.fields().last() && let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind // Then check if that array is zero-sized - && let length = Const::from_anon_const(cx.tcx, length.def_id) + && let length = Const::from_const_arg(cx.tcx, length, FeedConstTy::No) && let length = length.try_eval_target_usize(cx.tcx, cx.param_env) && let Some(length) = length { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e9d69407df8..316c1f32d3a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -5,10 +5,9 @@ use clippy_utils::{get_attr, higher}; use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, PatKind, - QPath, StmtKind, TyKind, + self as hir, ArrayLen, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, + ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -270,6 +269,21 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } } + fn const_arg(&self, const_arg: &Binding<&ConstArg<'_>>) { + match const_arg.value.kind { + ConstArgKind::Path(ref qpath) => { + bind!(self, qpath); + chain!(self, "let ConstArgKind::Path(ref {qpath}) = {const_arg}.kind"); + self.qpath(qpath); + }, + ConstArgKind::Anon(anon_const) => { + bind!(self, anon_const); + chain!(self, "let ConstArgKind::Anon({anon_const}) = {const_arg}.kind"); + self.body(field!(anon_const.body)); + }, + } + } + fn lit(&self, lit: &Binding<&Lit>) { let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node"); macro_rules! kind { @@ -602,10 +616,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(value); match length.value { ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"), - ArrayLen::Body(anon_const) => { - bind!(self, anon_const); - chain!(self, "let ArrayLen::Body({anon_const}) = {length}"); - self.body(field!(anon_const.body)); + ArrayLen::Body(const_arg) => { + bind!(self, const_arg); + chain!(self, "let ArrayLen::Body({const_arg}) = {length}"); + self.const_arg(const_arg); }, } }, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 8706cec5d38..6c6a237a8b1 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::MatchSource::TryDesugar; use rustc_hir::{ - ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, - GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, - PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, + ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, + ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, + LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -227,7 +227,7 @@ impl HirEqInterExpr<'_, '_, '_> { pub fn eq_array_length(&mut self, left: ArrayLen<'_>, right: ArrayLen<'_>) -> bool { match (left, right) { (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true, - (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body), + (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_const_arg(l_ct, r_ct), (_, _) => false, } } @@ -411,7 +411,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool { match (left, right) { - (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body), + (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_const_arg(l, r), (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt), (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty), (GenericArg::Infer(l_inf), GenericArg::Infer(r_inf)) => self.eq_ty(&l_inf.to_ty(), &r_inf.to_ty()), @@ -419,6 +419,17 @@ impl HirEqInterExpr<'_, '_, '_> { } } + fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool { + match (&left.kind, &right.kind) { + (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), + (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), + // Use explicit match for now since ConstArg is undergoing flux. + (ConstArgKind::Path(..), ConstArgKind::Anon(..)) | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) => { + false + }, + } + } + fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool { left.res == right.res } @@ -1123,7 +1134,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_array_length(&mut self, length: ArrayLen<'_>) { match length { ArrayLen::Infer(..) => {}, - ArrayLen::Body(anon_const) => self.hash_body(anon_const.body), + ArrayLen::Body(ct) => self.hash_const_arg(ct), } } @@ -1134,12 +1145,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.maybe_typeck_results = old_maybe_typeck_results; } + fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) { + match &const_arg.kind { + ConstArgKind::Path(path) => self.hash_qpath(path), + ConstArgKind::Anon(anon) => self.hash_body(anon.body), + } + } + fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) { for arg in arg_list { match *arg { GenericArg::Lifetime(l) => self.hash_lifetime(l), GenericArg::Type(ty) => self.hash_ty(ty), - GenericArg::Const(ref ca) => self.hash_body(ca.value.body), + GenericArg::Const(ref ca) => self.hash_const_arg(ca), GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()), } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index bdb3b5e45c4..8c33c34fa1c 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -102,11 +102,11 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstContext, - Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, - ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, - PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, - TyKind, UnOp, + self as hir, def, Arm, ArrayLen, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, + ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, + ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, + Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, + TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -904,7 +904,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), ExprKind::Repeat(x, ArrayLen::Body(len)) => { - if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + if let ConstArgKind::Anon(anon_const) = len.kind + && let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind && let LitKind::Int(v, _) = const_lit.node && v <= 32 && is_default_equivalent(cx, x) @@ -933,7 +934,8 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: & }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String), ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec), ExprKind::Repeat(_, ArrayLen::Body(len)) => { - if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind + if let ConstArgKind::Anon(anon_const) = len.kind + && let ExprKind::Lit(const_lit) = cx.tcx.hir().body(anon_const.body).value.kind && let LitKind::Int(v, _) = const_lit.node { return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec); diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout index c2a369610cc..d9e3f864f12 100644 --- a/src/tools/clippy/tests/ui/author/repeat.stdout +++ b/src/tools/clippy/tests/ui/author/repeat.stdout @@ -1,7 +1,8 @@ if let ExprKind::Repeat(value, length) = expr.kind && let ExprKind::Lit(ref lit) = value.kind && let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node - && let ArrayLen::Body(anon_const) = length + && let ArrayLen::Body(const_arg) = length + && let ConstArgKind::Anon(anon_const) = const_arg.kind && expr1 = &cx.tcx.hir().body(anon_const.body).value && let ExprKind::Lit(ref lit1) = expr1.kind && let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr index 3dd5c9561fd..7fbd8462fdc 100644 --- a/src/tools/clippy/tests/ui/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr @@ -193,5 +193,11 @@ error: this ident consists of a single char LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ -error: aborting due to 32 previous errors +error: this ident consists of a single char + --> tests/ui/min_ident_chars.rs:93:41 + | +LL | struct Array<T, const N: usize>([T; N]); + | ^ + +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr index 410e80f2528..3c7577dd003 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 7f5d4f4b416..3afb5e27547 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -723,12 +723,13 @@ pub fn line_directive<'line>( } } -// To prevent duplicating the list of commmands between `compiletest` and `htmldocck`, we put -// it into a common file which is included in rust code and parsed here. +// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`, +// we put it into a common file which is included in rust code and parsed here. // FIXME: This setup is temporary until we figure out how to improve this situation. +// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. include!("command-list.rs"); -const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[ +const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[ "count", "!count", "files", @@ -747,6 +748,9 @@ const KNOWN_RUSTDOC_DIRECTIVE_NAMES: &[&str] = &[ "!snapshot", ]; +const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] = + &["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"]; + /// The broken-down contents of a line containing a test header directive, /// which [`iter_header`] passes to its callback function. /// @@ -783,7 +787,7 @@ pub(crate) struct CheckDirectiveResult<'ln> { pub(crate) fn check_directive<'a>( directive_ln: &'a str, - is_rustdoc: bool, + mode: Mode, original_line: &str, ) -> CheckDirectiveResult<'a> { let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, "")); @@ -791,9 +795,18 @@ pub(crate) fn check_directive<'a>( let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post); let is_known = |s: &str| { KNOWN_DIRECTIVE_NAMES.contains(&s) - || (is_rustdoc - && original_line.starts_with("//@") - && KNOWN_RUSTDOC_DIRECTIVE_NAMES.contains(&s)) + || match mode { + Mode::Rustdoc | Mode::RustdocJson => { + original_line.starts_with("//@") + && match mode { + Mode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, + Mode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES, + _ => unreachable!(), + } + .contains(&s) + } + _ => false, + } }; let trailing_directive = { // 1. is the directive name followed by a space? (to exclude `:`) @@ -875,7 +888,7 @@ fn iter_header( let directive_ln = non_revisioned_directive_line.trim(); let CheckDirectiveResult { is_known_directive, trailing_directive, .. } = - check_directive(directive_ln, mode == Mode::Rustdoc, ln); + check_directive(directive_ln, mode, ln); if !is_known_directive { *poisoned = true; @@ -928,7 +941,7 @@ fn iter_header( let rest = rest.trim_start(); let CheckDirectiveResult { is_known_directive, directive_name, .. } = - check_directive(rest, mode == Mode::Rustdoc, ln); + check_directive(rest, mode, ln); if is_known_directive { *poisoned = true; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1a4101e4de8..01228869617 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -94,6 +94,8 @@ fn get_lib_name(lib: &str, aux_type: AuxType) -> Option<String> { format!("{}.dll", lib) } else if cfg!(target_vendor = "apple") { format!("lib{}.dylib", lib) + } else if cfg!(target_os = "aix") { + format!("lib{}.a", lib) } else { format!("lib{}.so", lib) }), diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs index fd21e7a86b0..90fce2b675a 100644 --- a/src/tools/generate-windows-sys/src/main.rs +++ b/src/tools/generate-windows-sys/src/main.rs @@ -4,6 +4,24 @@ use std::fs; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; +/// 32-bit ARM is not supported by Microsoft so ARM types are not generated. +/// Therefore we need to inject a few types to make the bindings work. +const ARM32_SHIM: &str = r#" +#[cfg(target_arch = "arm")] +#[repr(C)] +pub struct WSADATA { + pub wVersion: u16, + pub wHighVersion: u16, + pub szDescription: [u8; 257], + pub szSystemStatus: [u8; 129], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: PSTR, +} +#[cfg(target_arch = "arm")] +pub enum CONTEXT {} +"#; + fn main() -> Result<(), Box<dyn Error>> { let mut path: PathBuf = env::args_os().nth(1).expect("a path to the rust repository is required").into(); @@ -16,6 +34,7 @@ fn main() -> Result<(), Box<dyn Error>> { println!("{info}"); let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?; + f.write_all(ARM32_SHIM.as_bytes())?; writeln!(&mut f, "// ignore-tidy-filelength")?; writeln!(&mut f, "use super::windows_targets;")?; diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 429c6151796..de94990b53e 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -66,14 +66,17 @@ impl CommandKind { }; if !count { - print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno); + print_err(&format!("Incorrect number of arguments to `{}`", self), lineno); return false; } if let CommandKind::Count = self { if args[1].parse::<usize>().is_err() { print_err( - &format!("Second argument to @count must be a valid usize (got `{}`)", args[1]), + &format!( + "Second argument to `count` must be a valid usize (got `{}`)", + args[1] + ), lineno, ); return false; @@ -101,7 +104,8 @@ static LINE_PATTERN: OnceLock<Regex> = OnceLock::new(); fn line_pattern() -> Regex { RegexBuilder::new( r#" - \s(?P<invalid>!?)@(?P<negated>!?) + //@\s+ + (?P<negated>!?) (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*) (?P<args>.*)$ "#, @@ -116,6 +120,10 @@ fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) } +// FIXME: This setup is temporary until we figure out how to improve this situation. +// See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. +include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs")); + /// Get a list of commands from a file. Does the work of ensuring the commands /// are syntactically valid. fn get_commands(template: &str) -> Result<Vec<Command>, ()> { @@ -132,36 +140,22 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> { }; let negated = cap.name("negated").unwrap().as_str() == "!"; - let cmd = cap.name("cmd").unwrap().as_str(); - let cmd = match cmd { + let cmd = match cap.name("cmd").unwrap().as_str() { "has" => CommandKind::Has, "count" => CommandKind::Count, "is" => CommandKind::Is, "ismany" => CommandKind::IsMany, "set" => CommandKind::Set, - _ => { - print_err(&format!("Unrecognized command name `@{}`", cmd), lineno); + // FIXME: See the comment above the `include!(...)`. + cmd if KNOWN_DIRECTIVE_NAMES.contains(&cmd) => continue, + cmd => { + print_err(&format!("Unrecognized command name `{cmd}`"), lineno); errors = true; continue; } }; - if let Some(m) = cap.name("invalid") { - if m.as_str() == "!" { - print_err( - &format!( - "`!@{0}{1}`, (help: try with `@!{1}`)", - if negated { "!" } else { "" }, - cmd, - ), - lineno, - ); - errors = true; - continue; - } - } - let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str())); let args = match args { @@ -197,19 +191,19 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { let result = match command.kind { CommandKind::Has => { match command.args.len() { - // @has <jsonpath> = check path exists + // `has <jsonpath>`: Check that `jsonpath` exists. 1 => { let val = cache.value(); let results = select(val, &command.args[0]).unwrap(); !results.is_empty() } - // @has <jsonpath> <value> = check *any* item matched by path equals value + // `has <jsonpath> <value>`: Check *any* item matched by `jsonpath` equals `value`. 2 => { let val = cache.value().clone(); let results = select(&val, &command.args[0]).unwrap(); let pat = string_to_value(&command.args[1], cache); let has = results.contains(&pat.as_ref()); - // Give better error for when @has check fails + // Give better error for when `has` check fails. if !command.negated && !has { return Err(CkError::FailedCheck( format!( @@ -227,8 +221,9 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { _ => unreachable!(), } } + // `ismany <path> <jsonpath> <value...>` CommandKind::IsMany => { - // @ismany <path> <jsonpath> <value>... + assert!(!command.negated, "`ismany` may not be negated"); let (query, values) = if let [query, values @ ..] = &command.args[..] { (query, values) } else { @@ -236,7 +231,6 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { }; let val = cache.value(); let got_values = select(val, &query).unwrap(); - assert!(!command.negated, "`@!ismany` is not supported"); // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality @@ -265,8 +259,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { } true } + // `count <jsonpath> <count>`: Check that `jsonpath` matches exactly `count` times. CommandKind::Count => { - // @count <jsonpath> <count> = Check that the jsonpath matches exactly [count] times assert_eq!(command.args.len(), 2); let expected: usize = command.args[1].parse().unwrap(); let val = cache.value(); @@ -287,8 +281,8 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { eq } } + // `has <jsonpath> <value>`: Check` *exactly one* item matched by `jsonpath`, and it equals `value`. CommandKind::Is => { - // @has <jsonpath> <value> = check *exactly one* item matched by path, and it equals value assert_eq!(command.args.len(), 2); let val = cache.value().clone(); let results = select(&val, &command.args[0]).unwrap(); @@ -308,8 +302,9 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { is } } + // `set <name> = <jsonpath>` CommandKind::Set => { - // @set <name> = <jsonpath> + assert!(!command.negated, "`set` may not be negated"); assert_eq!(command.args.len(), 3); assert_eq!(command.args[1], "=", "Expected an `=`"); let val = cache.value().clone(); @@ -317,7 +312,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { assert_eq!( results.len(), 1, - "Expected 1 match for `{}` (because of @set): matched to {:?}", + "Expected 1 match for `{}` (because of `set`): matched to {:?}", command.args[2], results ); @@ -330,7 +325,7 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { } _ => { panic!( - "Got multiple results in `@set` for `{}`: {:?}", + "Got multiple results in `set` for `{}`: {:?}", &command.args[2], results, ); } @@ -341,18 +336,14 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { if result == command.negated { if command.negated { Err(CkError::FailedCheck( - format!( - "`@!{} {}` matched when it shouldn't", - command.kind, - command.args.join(" ") - ), + format!("`!{} {}` matched when it shouldn't", command.kind, command.args.join(" ")), command, )) } else { // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed Err(CkError::FailedCheck( format!( - "`@{} {}` didn't match when it should", + "`{} {}` didn't match when it should", command.kind, command.args.join(" ") ), diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2c29af8b935..b09d4f11f68 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5c8488605624d67b272953bc21d41db60dbd5654 +9057c3ffec44926d5e149dc13ff3ce1613b69cce diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs index 1d6b6777032..85d7582d112 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs @@ -59,8 +59,10 @@ impl Baz for i32 { } fn main() { - let baz: &dyn Baz = &1; - let baz_fake: *const dyn Bar = unsafe { std::mem::transmute(baz) }; - let _err = baz_fake as *const dyn Foo; - //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected + unsafe { + let baz: &dyn Baz = &1; + let baz_fake: *const dyn Bar = std::mem::transmute(baz); + let _err = baz_fake as *const dyn Foo; + //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected + } } diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr index 6a2415cf57e..87b1361c3e5 100644 --- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC | -LL | let _err = baz_fake as *const dyn Foo; - | ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected +LL | let _err = baz_fake as *const dyn Foo; + | ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected | = 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 diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 969552dec84..b3913732839 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -9,7 +9,5 @@ object = "0.34.0" similar = "2.5.0" wasmparser = "0.118.2" regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace -gimli = "0.28.1" -ar = "0.9.0" - +gimli = "0.31.0" build_helper = { path = "../build_helper" } diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs new file mode 100644 index 00000000000..bc6ec7566e5 --- /dev/null +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -0,0 +1,57 @@ +//! A collection of helpers to construct artifact names, such as names of dynamic or static +//! librarys which are target-dependent. + +// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings! + +use crate::targets::is_msvc; + +/// Construct the static library name based on the target. +#[must_use] +pub fn static_lib_name(name: &str) -> String { + // See tools.mk (irrelevant lines omitted): + // + // ```makefile + // ifeq ($(UNAME),Darwin) + // STATICLIB = $(TMPDIR)/lib$(1).a + // else + // ifdef IS_WINDOWS + // ifdef IS_MSVC + // STATICLIB = $(TMPDIR)/$(1).lib + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // else + // STATICLIB = $(TMPDIR)/lib$(1).a + // endif + // endif + // ``` + assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); + + if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } +} + +/// Construct the dynamic library name based on the target. +#[must_use] +pub fn dynamic_lib_name(name: &str) -> String { + assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); + + format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION) +} + +/// Construct the dynamic library extension based on the target. +#[must_use] +pub fn dynamic_lib_extension() -> &'static str { + std::env::consts::DLL_EXTENSION +} + +/// Construct the name of a rust library (rlib). +#[must_use] +pub fn rust_lib_name(name: &str) -> String { + format!("lib{name}.rlib") +} + +/// Construct the binary (executable) name based on the target. +#[must_use] +pub fn bin_name(name: &str) -> String { + format!("{name}{}", std::env::consts::EXE_SUFFIX) +} diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs new file mode 100644 index 00000000000..4b5b349431d --- /dev/null +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -0,0 +1,73 @@ +//! Collection of assertions and assertion-related helpers. + +use std::panic; +use std::path::Path; + +use crate::fs; + +/// Assert that `actual` is equal to `expected`. +#[track_caller] +pub fn assert_equals<A: AsRef<str>, E: AsRef<str>>(actual: A, expected: E) { + let actual = actual.as_ref(); + let expected = expected.as_ref(); + if actual != expected { + eprintln!("=== ACTUAL TEXT ==="); + eprintln!("{}", actual); + eprintln!("=== EXPECTED ==="); + eprintln!("{}", expected); + panic!("expected text was not found in actual text"); + } +} + +/// Assert that `haystack` contains `needle`. +#[track_caller] +pub fn assert_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + if !haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + +/// Assert that `haystack` does not contain `needle`. +#[track_caller] +pub fn assert_not_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + if haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} + +/// Assert that all files in `dir1` exist and have the same content in `dir2` +pub fn assert_dirs_are_equal(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) { + let dir2 = dir2.as_ref(); + fs::read_dir_entries(dir1, |entry_path| { + let entry_name = entry_path.file_name().unwrap(); + if entry_path.is_dir() { + assert_dirs_are_equal(&entry_path, &dir2.join(entry_name)); + } else { + let path2 = dir2.join(entry_name); + let file1 = fs::read(&entry_path); + let file2 = fs::read(&path2); + + // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display. + // Why not using String? Because there might be minified files or even potentially + // binary ones, so that would display useless output. + assert!( + file1 == file2, + "`{}` and `{}` have different content", + entry_path.display(), + path2.display(), + ); + } + }); +} diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 5017a4b88da..47376c401bb 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -5,7 +5,9 @@ use std::panic; use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; -use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output}; +use crate::util::handle_failed_output; +use crate::{assert_contains, assert_equals, assert_not_contains}; + use build_helper::drop_bomb::DropBomb; /// This is a custom command wrapper that simplifies working with commands and makes it easier to diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index ad989b74e4d..ac662331606 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -1,10 +1,12 @@ +use std::path::{Path, PathBuf}; + use regex::Regex; use similar::TextDiff; -use std::path::{Path, PathBuf}; -use crate::fs_wrapper; use build_helper::drop_bomb::DropBomb; +use crate::fs; + #[cfg(test)] mod tests; @@ -43,7 +45,7 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = fs_wrapper::read_to_string(path); + let content = fs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.expected_file = Some(path.into()); @@ -62,7 +64,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = fs_wrapper::read_to_string(path); + let content = fs::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -116,7 +118,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - fs_wrapper::write(expected_file, actual); + fs::write(expected_file, actual); return; } } @@ -138,7 +140,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - fs_wrapper::write(expected_file, actual); + fs::write(expected_file, actual); return; } } diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs new file mode 100644 index 00000000000..f52524e7d54 --- /dev/null +++ b/src/tools/run-make-support/src/env.rs @@ -0,0 +1,19 @@ +use std::ffi::OsString; + +#[track_caller] +#[must_use] +pub fn env_var(name: &str) -> String { + match std::env::var(name) { + Ok(v) => v, + Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), + } +} + +#[track_caller] +#[must_use] +pub fn env_var_os(name: &str) -> OsString { + match std::env::var_os(name) { + Some(v) => v, + None => panic!("failed to retrieve environment variable {name:?}"), + } +} diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs new file mode 100644 index 00000000000..35b2bf75c95 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/c_build.rs @@ -0,0 +1,27 @@ +use std::path::PathBuf; + +use crate::artifact_names::static_lib_name; +use crate::external_deps::cc::cc; +use crate::external_deps::llvm::llvm_ar; +use crate::path_helpers::path; +use crate::targets::is_msvc; + +/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name. +#[track_caller] +pub fn build_native_static_lib(lib_name: &str) -> PathBuf { + let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") }; + let src = format!("{lib_name}.c"); + let lib_path = static_lib_name(lib_name); + if is_msvc() { + cc().arg("-c").out_exe(&obj_file).input(src).run(); + } else { + cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run(); + }; + let obj_file = if is_msvc() { + PathBuf::from(format!("{lib_name}.obj")) + } else { + PathBuf::from(format!("{lib_name}.o")) + }; + llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run(); + path(lib_path) +} diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs index 31b9e8a23b8..840bfa0d2b4 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/external_deps/cc.rs @@ -1,7 +1,10 @@ use std::path::Path; use crate::command::Command; -use crate::{bin_name, cygpath_windows, env_var, is_msvc, is_windows, uname}; +use crate::{env_var, is_msvc, is_windows, uname}; + +// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency? +use super::cygpath::get_windows_path; /// Construct a new platform-specific C compiler invocation. /// @@ -20,7 +23,7 @@ pub struct Cc { cmd: Command, } -crate::impl_common_helpers!(Cc); +crate::macros::impl_common_helpers!(Cc); impl Cc { /// Construct a new platform-specific C compiler invocation. @@ -68,9 +71,14 @@ impl Cc { // endif // ``` + let mut path = std::path::PathBuf::from(name); + if is_msvc() { - let fe_path = cygpath_windows(bin_name(name)); - let fo_path = cygpath_windows(format!("{name}.obj")); + path.set_extension("exe"); + let fe_path = get_windows_path(&path); + path.set_extension(""); + path.set_extension("obj"); + let fo_path = get_windows_path(path); self.cmd.arg(format!("-Fe:{fe_path}")); self.cmd.arg(format!("-Fo:{fo_path}")); } else { diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs index c23e41ebe21..2b0712541cd 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/external_deps/clang.rs @@ -16,7 +16,7 @@ pub struct Clang { cmd: Command, } -crate::impl_common_helpers!(Clang); +crate::macros::impl_common_helpers!(Clang); impl Clang { /// Construct a new `clang` invocation. `clang` is not always available for all targets. diff --git a/src/tools/run-make-support/src/external_deps/cygpath.rs b/src/tools/run-make-support/src/external_deps/cygpath.rs new file mode 100644 index 00000000000..07d8e840a63 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/cygpath.rs @@ -0,0 +1,35 @@ +use std::panic; +use std::path::Path; + +use crate::command::Command; +use crate::util::handle_failed_output; + +/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is +/// available on the platform! +/// +/// # FIXME +/// +/// FIXME(jieyouxu): we should consider not depending on `cygpath`. +/// +/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style +/// > pathnames and vice versa. +/// > +/// > [irrelevant entries omitted...] +/// > +/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)` +/// > +/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*. +#[track_caller] +#[must_use] +pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String { + let caller = panic::Location::caller(); + let mut cygpath = Command::new("cygpath"); + cygpath.arg("-w"); + cygpath.arg(path.as_ref()); + let output = cygpath.run(); + if !output.status().success() { + handle_failed_output(&cygpath, output, caller.line()); + } + // cygpath -w can attach a newline + output.stdout_utf8().trim().to_string() +} diff --git a/src/tools/run-make-support/src/external_deps/htmldocck.rs b/src/tools/run-make-support/src/external_deps/htmldocck.rs new file mode 100644 index 00000000000..afd0711ee04 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/htmldocck.rs @@ -0,0 +1,14 @@ +use crate::command::Command; +use crate::source_root; + +use super::python::python_command; + +/// `htmldocck` is a python script which is used for rustdoc test suites, it is assumed to be +/// available at `$SOURCE_ROOT/src/etc/htmldocck.py`. +#[track_caller] +#[must_use] +pub fn htmldocck() -> Command { + let mut python = python_command(); + python.arg(source_root().join("src/etc/htmldocck.py")); + python +} diff --git a/src/tools/run-make-support/src/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index 4c9e9a53230..5e8ad7ed312 100644 --- a/src/tools/run-make-support/src/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -1,6 +1,7 @@ use std::path::{Path, PathBuf}; -use crate::{env_var, Command}; +use crate::command::Command; +use crate::env::env_var; /// Construct a new `llvm-readobj` invocation with the `GNU` output style. /// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`. @@ -29,6 +30,12 @@ pub fn llvm_objdump() -> LlvmObjdump { LlvmObjdump::new() } +/// Construct a new `llvm-ar` invocation. This assumes that `llvm-ar` is available +/// at `$LLVM_BIN_DIR/llvm-ar`. +pub fn llvm_ar() -> LlvmAr { + LlvmAr::new() +} + /// A `llvm-readobj` invocation builder. #[derive(Debug)] #[must_use] @@ -57,10 +64,18 @@ pub struct LlvmObjdump { cmd: Command, } -crate::impl_common_helpers!(LlvmReadobj); -crate::impl_common_helpers!(LlvmProfdata); -crate::impl_common_helpers!(LlvmFilecheck); -crate::impl_common_helpers!(LlvmObjdump); +/// A `llvm-ar` invocation builder. +#[derive(Debug)] +#[must_use] +pub struct LlvmAr { + cmd: Command, +} + +crate::macros::impl_common_helpers!(LlvmReadobj); +crate::macros::impl_common_helpers!(LlvmProfdata); +crate::macros::impl_common_helpers!(LlvmFilecheck); +crate::macros::impl_common_helpers!(LlvmObjdump); +crate::macros::impl_common_helpers!(LlvmAr); /// Generate the path to the bin directory of LLVM. #[must_use] @@ -204,3 +219,26 @@ impl LlvmObjdump { self } } + +impl LlvmAr { + /// Construct a new `llvm-ar` invocation. This assumes that `llvm-ar` is available + /// at `$LLVM_BIN_DIR/llvm-ar`. + pub fn new() -> Self { + let llvm_ar = llvm_bin_dir().join("llvm-ar"); + let cmd = Command::new(llvm_ar); + Self { cmd } + } + + pub fn obj_to_ar(&mut self) -> &mut Self { + self.cmd.arg("rcus"); + self + } + + /// Provide an output, then an input file. Bundled in one function, as llvm-ar has + /// no "--output"-style flag. + pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self { + self.cmd.arg(out.as_ref()); + self.cmd.arg(input.as_ref()); + self + } +} diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs new file mode 100644 index 00000000000..a2dc426f3f2 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -0,0 +1,14 @@ +//! This module contains external tool dependencies that we assume are available in the environment, +//! such as `cc` or `python`. + +pub mod c_build; +pub mod cc; +pub mod clang; +pub mod htmldocck; +pub mod llvm; +pub mod python; +pub mod rustc; +pub mod rustdoc; + +// Library-internal external dependency. +mod cygpath; diff --git a/src/tools/run-make-support/src/external_deps/python.rs b/src/tools/run-make-support/src/external_deps/python.rs new file mode 100644 index 00000000000..fb885069371 --- /dev/null +++ b/src/tools/run-make-support/src/external_deps/python.rs @@ -0,0 +1,11 @@ +use crate::command::Command; +use crate::env::env_var; + +/// Obtain path of python as provided by the `PYTHON` environment variable. It is up to the caller +/// to document and check if the python version is compatible with its intended usage. +#[track_caller] +#[must_use] +pub fn python_command() -> Command { + let python_path = env_var("PYTHON"); + Command::new(python_path) +} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index ae200d51431..71d28dd9675 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -1,8 +1,10 @@ -use command::Command; use std::ffi::{OsStr, OsString}; use std::path::Path; -use crate::{command, cwd, env_var, set_host_rpath}; +use crate::command::Command; +use crate::env::env_var; +use crate::path_helpers::cwd; +use crate::util::set_host_rpath; /// Construct a new `rustc` invocation. This will automatically set the library /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. @@ -31,7 +33,7 @@ pub struct Rustc { cmd: Command, } -crate::impl_common_helpers!(Rustc); +crate::macros::impl_common_helpers!(Rustc); #[track_caller] fn setup_common() -> Command { @@ -242,6 +244,19 @@ impl Rustc { self } + /// Add a directory to the library search path with a restriction, where `kind` is a dependency + /// type. Equivalent to `-L KIND=PATH` in rustc. + pub fn specific_library_search_path<P: AsRef<Path>>( + &mut self, + kind: &str, + path: P, + ) -> &mut Self { + assert!(["dependency", "native", "all", "framework", "crate"].contains(&kind)); + let path = path.as_ref().to_string_lossy(); + self.cmd.arg(format!("-L{kind}={path}")); + self + } + /// Override the system root. Equivalent to `--sysroot` in rustc. pub fn sysroot<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { self.cmd.arg("--sysroot"); diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs index 2be962ad888..96c2218a563 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs @@ -2,7 +2,8 @@ use std::ffi::OsStr; use std::path::Path; use crate::command::Command; -use crate::{env_var, env_var_os, set_host_rpath}; +use crate::env::{env_var, env_var_os}; +use crate::util::set_host_rpath; /// Construct a plain `rustdoc` invocation with no flags set. #[track_caller] @@ -22,7 +23,7 @@ pub struct Rustdoc { cmd: Command, } -crate::impl_common_helpers!(Rustdoc); +crate::macros::impl_common_helpers!(Rustdoc); #[track_caller] fn setup_common() -> Command { diff --git a/src/tools/run-make-support/src/fs_wrapper.rs b/src/tools/run-make-support/src/fs.rs index 0f0d6f6618c..f346e983aea 100644 --- a/src/tools/run-make-support/src/fs_wrapper.rs +++ b/src/tools/run-make-support/src/fs.rs @@ -1,17 +1,82 @@ -use std::fs; +use std::io; use std::path::Path; +// FIXME(jieyouxu): modify create_symlink to panic on windows. + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "windows")] +pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. +#[cfg(target_family = "unix")] +pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) { + if link.as_ref().exists() { + std::fs::remove_dir(link.as_ref()).unwrap(); + } + std::os::unix::fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( + "failed to create symlink {:?} for {:?}", + link.as_ref().display(), + original.as_ref().display(), + )); +} + +/// Copy a directory into another. +pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) { + fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> { + let dst = dst.as_ref(); + if !dst.is_dir() { + std::fs::create_dir_all(&dst)?; + } + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.join(entry.file_name()))?; + } + } + Ok(()) + } + + if let Err(e) = copy_dir_all_inner(&src, &dst) { + // Trying to give more context about what exactly caused the failure + panic!( + "failed to copy `{}` to `{}`: {:?}", + src.as_ref().display(), + dst.as_ref().display(), + e + ); + } +} + +/// Helper for reading entries in a given directory. +pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) { + for entry in read_dir(dir) { + callback(&entry.unwrap().path()); + } +} + /// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message. #[track_caller] pub fn remove_file<P: AsRef<Path>>(path: P) { - fs::remove_file(path.as_ref()) + std::fs::remove_file(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be removed", path.as_ref().display())); } /// A wrapper around [`std::fs::copy`] which includes the file path in the panic message. #[track_caller] pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) { - fs::copy(from.as_ref(), to.as_ref()).expect(&format!( + std::fs::copy(from.as_ref(), to.as_ref()).expect(&format!( "the file \"{}\" could not be copied over to \"{}\"", from.as_ref().display(), to.as_ref().display(), @@ -21,21 +86,21 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) { /// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message. #[track_caller] pub fn create_file<P: AsRef<Path>>(path: P) { - fs::File::create(path.as_ref()) + std::fs::File::create(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display())); } /// A wrapper around [`std::fs::read`] which includes the file path in the panic message. #[track_caller] pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> { - fs::read(path.as_ref()) + std::fs::read(path.as_ref()) .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display())) } /// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message. #[track_caller] pub fn read_to_string<P: AsRef<Path>>(path: P) -> String { - fs::read_to_string(path.as_ref()).expect(&format!( + std::fs::read_to_string(path.as_ref()).expect(&format!( "the file in path \"{}\" could not be read into a String", path.as_ref().display() )) @@ -43,15 +108,15 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> String { /// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message. #[track_caller] -pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir { - fs::read_dir(path.as_ref()) +pub fn read_dir<P: AsRef<Path>>(path: P) -> std::fs::ReadDir { + std::fs::read_dir(path.as_ref()) .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display())) } /// A wrapper around [`std::fs::write`] which includes the file path in the panic message. #[track_caller] pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) { - fs::write(path.as_ref(), contents.as_ref()).expect(&format!( + std::fs::write(path.as_ref(), contents.as_ref()).expect(&format!( "the file in path \"{}\" could not be written to", path.as_ref().display() )); @@ -60,7 +125,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) { /// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message. #[track_caller] pub fn remove_dir_all<P: AsRef<Path>>(path: P) { - fs::remove_dir_all(path.as_ref()).expect(&format!( + std::fs::remove_dir_all(path.as_ref()).expect(&format!( "the directory in path \"{}\" could not be removed alongside all its contents", path.as_ref().display(), )); @@ -69,7 +134,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) { /// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message. #[track_caller] pub fn create_dir<P: AsRef<Path>>(path: P) { - fs::create_dir(path.as_ref()).expect(&format!( + std::fs::create_dir(path.as_ref()).expect(&format!( "the directory in path \"{}\" could not be created", path.as_ref().display() )); @@ -78,7 +143,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) { /// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message. #[track_caller] pub fn create_dir_all<P: AsRef<Path>>(path: P) { - fs::create_dir_all(path.as_ref()).expect(&format!( + std::fs::create_dir_all(path.as_ref()).expect(&format!( "the directory (and all its parents) in path \"{}\" could not be created", path.as_ref().display() )); @@ -86,8 +151,8 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) { /// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message. #[track_caller] -pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata { - fs::metadata(path.as_ref()).expect(&format!( +pub fn metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata { + std::fs::metadata(path.as_ref()).expect(&format!( "the file's metadata in path \"{}\" could not be read", path.as_ref().display() )) @@ -96,7 +161,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata { /// A wrapper around [`std::fs::rename`] which includes the file path in the panic message. #[track_caller] pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) { - fs::rename(from.as_ref(), to.as_ref()).expect(&format!( + std::fs::rename(from.as_ref(), to.as_ref()).expect(&format!( "the file \"{}\" could not be moved over to \"{}\"", from.as_ref().display(), to.as_ref().display(), @@ -105,8 +170,8 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) { /// A wrapper around [`std::fs::set_permissions`] which includes the file path in the panic message. #[track_caller] -pub fn set_permissions<P: AsRef<Path>>(path: P, perm: fs::Permissions) { - fs::set_permissions(path.as_ref(), perm).expect(&format!( +pub fn set_permissions<P: AsRef<Path>>(path: P, perm: std::fs::Permissions) { + std::fs::set_permissions(path.as_ref(), perm).expect(&format!( "the file's permissions in path \"{}\" could not be changed", path.as_ref().display() )); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e5f1ce1bf34..e6a45f57de6 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -3,644 +3,84 @@ //! notably is built via cargo: this means that if your test wants some non-trivial utility, such //! as `object` or `wasmparser`, they can be re-exported and be made available through this library. -pub mod cc; -pub mod clang; mod command; +mod macros; +mod util; + +pub mod artifact_names; +pub mod assertion_helpers; pub mod diff; -pub mod fs_wrapper; -pub mod llvm; +pub mod env; +pub mod external_deps; +pub mod path_helpers; pub mod run; -pub mod rustc; -pub mod rustdoc; +pub mod scoped_run; +pub mod string; +pub mod targets; + +mod fs; -use std::env; -use std::ffi::OsString; -use std::fs; -use std::io; -use std::panic; -use std::path::{Path, PathBuf}; +/// [`std::fs`] wrappers and assorted filesystem-related helpers. Public to tests as `rfs` to not be +/// confused with [`std::fs`]. +pub mod rfs { + pub use crate::fs::*; +} +// Re-exports of third-party library crates. pub use bstr; pub use gimli; pub use object; pub use regex; pub use wasmparser; +// Re-exports of external dependencies. +pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc}; + +// These rely on external dependencies. +pub use c_build::build_native_static_lib; pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; -pub use diff::{diff, Diff}; +pub use htmldocck::htmldocck; pub use llvm::{ - llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmFilecheck, LlvmObjdump, - LlvmProfdata, LlvmReadobj, + llvm_ar, llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmFilecheck, + LlvmObjdump, LlvmProfdata, LlvmReadobj, }; -pub use run::{cmd, run, run_fail, run_with_args}; +pub use python::python_command; pub use rustc::{aux_build, bare_rustc, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -#[track_caller] -#[must_use] -pub fn env_var(name: &str) -> String { - match env::var(name) { - Ok(v) => v, - Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), - } -} - -#[track_caller] -#[must_use] -pub fn env_var_os(name: &str) -> OsString { - match env::var_os(name) { - Some(v) => v, - None => panic!("failed to retrieve environment variable {name:?}"), - } -} - -/// `TARGET` -#[must_use] -pub fn target() -> String { - env_var("TARGET") -} - -/// `AR` -#[track_caller] -pub fn ar(inputs: &[impl AsRef<Path>], output_path: impl AsRef<Path>) { - let output = fs::File::create(&output_path).expect(&format!( - "the file in path \"{}\" could not be created", - output_path.as_ref().display() - )); - let mut builder = ar::Builder::new(output); - for input in inputs { - builder.append_path(input).unwrap(); - } -} - -/// Check if target is windows-like. -#[must_use] -pub fn is_windows() -> bool { - target().contains("windows") -} - -/// Check if target uses msvc. -#[must_use] -pub fn is_msvc() -> bool { - target().contains("msvc") -} - -/// Check if target uses macOS. -#[must_use] -pub fn is_darwin() -> bool { - target().contains("darwin") -} - -#[track_caller] -#[must_use] -pub fn python_command() -> Command { - let python_path = env_var("PYTHON"); - Command::new(python_path) -} - -#[track_caller] -#[must_use] -pub fn htmldocck() -> Command { - let mut python = python_command(); - python.arg(source_root().join("src/etc/htmldocck.py")); - python -} - -/// Returns the path for a local test file. -pub fn path<P: AsRef<Path>>(p: P) -> PathBuf { - cwd().join(p.as_ref()) -} - -/// Path to the root rust-lang/rust source checkout. -#[must_use] -pub fn source_root() -> PathBuf { - env_var("SOURCE_ROOT").into() -} - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "windows")] -pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::windows::fs; - fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - -/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix. -#[cfg(target_family = "unix")] -pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) { - if link.as_ref().exists() { - std::fs::remove_dir(link.as_ref()).unwrap(); - } - use std::os::unix::fs; - fs::symlink(original.as_ref(), link.as_ref()).expect(&format!( - "failed to create symlink {:?} for {:?}", - link.as_ref().display(), - original.as_ref().display(), - )); -} - -/// Construct the static library name based on the platform. -#[must_use] -pub fn static_lib_name(name: &str) -> String { - // See tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifeq ($(UNAME),Darwin) - // STATICLIB = $(TMPDIR)/lib$(1).a - // else - // ifdef IS_WINDOWS - // ifdef IS_MSVC - // STATICLIB = $(TMPDIR)/$(1).lib - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // else - // STATICLIB = $(TMPDIR)/lib$(1).a - // endif - // endif - // ``` - assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace"); - - if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } -} - -/// Construct the dynamic library name based on the platform. -#[must_use] -pub fn dynamic_lib_name(name: &str) -> String { - // See tools.mk (irrelevant lines omitted): - // - // ```makefile - // ifeq ($(UNAME),Darwin) - // DYLIB = $(TMPDIR)/lib$(1).dylib - // else - // ifdef IS_WINDOWS - // DYLIB = $(TMPDIR)/$(1).dll - // else - // DYLIB = $(TMPDIR)/lib$(1).so - // endif - // endif - // ``` - assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace"); - - let extension = dynamic_lib_extension(); - if is_darwin() { - format!("lib{name}.{extension}") - } else if is_windows() { - format!("{name}.{extension}") - } else { - format!("lib{name}.{extension}") - } -} - -#[must_use] -pub fn dynamic_lib_extension() -> &'static str { - if is_darwin() { - "dylib" - } else if is_windows() { - "dll" - } else { - "so" - } -} - -/// Generate the name a rust library (rlib) would have. -#[must_use] -pub fn rust_lib_name(name: &str) -> String { - format!("lib{name}.rlib") -} - -/// Construct the binary name based on platform. -#[must_use] -pub fn bin_name(name: &str) -> String { - if is_windows() { format!("{name}.exe") } else { name.to_string() } -} - -/// Return the current working directory. -#[must_use] -pub fn cwd() -> PathBuf { - env::current_dir().unwrap() -} - -// FIXME(Oneirical): This will no longer be required after compiletest receives the ability -// to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 -/// Ensure that the path P is read-only while the test runs, and restore original permissions -/// at the end so compiletest can clean up. -/// This will panic on Windows if the path is a directory (as it would otherwise do nothing) -#[track_caller] -pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>( - path: P, - closure: F, -) { - let path = path.as_ref(); - if is_windows() && path.is_dir() { - eprintln!("This helper function cannot be used on Windows to make directories readonly."); - eprintln!( - "See the official documentation: - https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" - ); - panic!("`test_while_readonly` on directory detected while on Windows."); - } - let metadata = fs_wrapper::metadata(&path); - let original_perms = metadata.permissions(); - - let mut new_perms = original_perms.clone(); - new_perms.set_readonly(true); - fs_wrapper::set_permissions(&path, new_perms); - - let success = std::panic::catch_unwind(closure); - - fs_wrapper::set_permissions(&path, original_perms); - success.unwrap(); -} - -/// Browse the directory `path` non-recursively and return all files which respect the parameters -/// outlined by `closure`. -#[track_caller] -pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>( - path: P, - filter: F, -) -> Vec<PathBuf> { - let mut matching_files = Vec::new(); - for entry in fs_wrapper::read_dir(path) { - let entry = entry.expect("failed to read directory entry."); - let path = entry.path(); - - if path.is_file() && filter(&path) { - matching_files.push(path); - } - } - matching_files -} - -/// Returns true if the filename at `path` starts with `prefix`. -pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) -} - -/// Returns true if the filename at `path` has the extension `extension`. -pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool { - path.as_ref().extension().is_some_and(|ext| ext == extension) -} - -/// Returns true if the filename at `path` does not contain `expected`. -pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool { - !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) -} - -/// Returns true if the filename at `path` is not in `expected`. -pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool { - let expected = expected.as_ref(); - path.as_ref() - .file_name() - .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) -} - -/// Returns true if the filename at `path` ends with `suffix`. -pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool { - path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) -} - -/// Gathers all files in the current working directory that have the extension `ext`, and counts -/// the number of lines within that contain a match with the regex pattern `re`. -pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { - let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); - - let mut count = 0; - for file in fetched_files { - let content = fs_wrapper::read_to_string(file); - count += content.lines().filter(|line| re.is_match(&line)).count(); - } - - count -} - -/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is -/// available on the platform! -#[track_caller] -#[must_use] -pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String { - let caller = panic::Location::caller(); - let mut cygpath = Command::new("cygpath"); - cygpath.arg("-w"); - cygpath.arg(path.as_ref()); - let output = cygpath.run(); - if !output.status().success() { - handle_failed_output(&cygpath, output, caller.line()); - } - // cygpath -w can attach a newline - output.stdout_utf8().trim().to_string() -} - -/// Run `uname`. This assumes that `uname` is available on the platform! -#[track_caller] -#[must_use] -pub fn uname() -> String { - let caller = panic::Location::caller(); - let mut uname = Command::new("uname"); - let output = uname.run(); - if !output.status().success() { - handle_failed_output(&uname, output, caller.line()); - } - output.stdout_utf8() -} - -fn handle_failed_output(cmd: &Command, output: CompletedProcess, caller_line_number: u32) -> ! { - if output.status().success() { - eprintln!("command unexpectedly succeeded at line {caller_line_number}"); - } else { - eprintln!("command failed at line {caller_line_number}"); - } - eprintln!("{cmd:?}"); - eprintln!("output status: `{}`", output.status()); - eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); - eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); - std::process::exit(1) -} - -/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. -pub fn set_host_rpath(cmd: &mut Command) { - let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); - cmd.env(&ld_lib_path_envvar, { - let mut paths = vec![]; - paths.push(cwd()); - paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); - for p in env::split_paths(&env_var(&ld_lib_path_envvar)) { - paths.push(p.to_path_buf()); - } - env::join_paths(paths.iter()).unwrap() - }); -} - -/// Read the contents of a file that cannot simply be read by -/// read_to_string, due to invalid utf8 data, then assert that it contains `expected`. -#[track_caller] -pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); - let expected = expected.as_ref(); - if !String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was not found in file"); - } -} - -/// Read the contents of a file that cannot simply be read by -/// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`. -#[track_caller] -pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) { - let buffer = fs_wrapper::read(path.as_ref()); - let expected = expected.as_ref(); - if String::from_utf8_lossy(&buffer).contains(expected) { - eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&buffer)); - eprintln!("=== SPECIFIED TEXT ==="); - eprintln!("{}", expected); - panic!("specified text was unexpectedly found in file"); - } -} - -/// Copy a directory into another. -pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) { - fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> { - let dst = dst.as_ref(); - if !dst.is_dir() { - std::fs::create_dir_all(&dst)?; - } - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.join(entry.file_name()))?; - } - } - Ok(()) - } - - if let Err(e) = copy_dir_all_inner(&src, &dst) { - // Trying to give more context about what exactly caused the failure - panic!( - "failed to copy `{}` to `{}`: {:?}", - src.as_ref().display(), - dst.as_ref().display(), - e - ); - } -} - -/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise. -pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) { - let dir2 = dir2.as_ref(); - read_dir(dir1, |entry_path| { - let entry_name = entry_path.file_name().unwrap(); - if entry_path.is_dir() { - recursive_diff(&entry_path, &dir2.join(entry_name)); - } else { - let path2 = dir2.join(entry_name); - let file1 = fs_wrapper::read(&entry_path); - let file2 = fs_wrapper::read(&path2); - - // We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display. - // Why not using String? Because there might be minified files or even potentially - // binary ones, so that would display useless output. - assert!( - file1 == file2, - "`{}` and `{}` have different content", - entry_path.display(), - path2.display(), - ); - } - }); -} - -pub fn read_dir<F: FnMut(&Path)>(dir: impl AsRef<Path>, mut callback: F) { - for entry in fs_wrapper::read_dir(dir) { - callback(&entry.unwrap().path()); - } -} - -/// Check that `actual` is equal to `expected`. Panic otherwise. -#[track_caller] -pub fn assert_equals<S1: AsRef<str>, S2: AsRef<str>>(actual: S1, expected: S2) { - let actual = actual.as_ref(); - let expected = expected.as_ref(); - if actual != expected { - eprintln!("=== ACTUAL TEXT ==="); - eprintln!("{}", actual); - eprintln!("=== EXPECTED ==="); - eprintln!("{}", expected); - panic!("expected text was not found in actual text"); - } -} - -/// Check that `haystack` contains `needle`. Panic otherwise. -#[track_caller] -pub fn assert_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) { - let haystack = haystack.as_ref(); - let needle = needle.as_ref(); - if !haystack.contains(needle) { - eprintln!("=== HAYSTACK ==="); - eprintln!("{}", haystack); - eprintln!("=== NEEDLE ==="); - eprintln!("{}", needle); - panic!("needle was not found in haystack"); - } -} - -/// Check that `haystack` does not contain `needle`. Panic otherwise. -#[track_caller] -pub fn assert_not_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) { - let haystack = haystack.as_ref(); - let needle = needle.as_ref(); - if haystack.contains(needle) { - eprintln!("=== HAYSTACK ==="); - eprintln!("{}", haystack); - eprintln!("=== NEEDLE ==="); - eprintln!("{}", needle); - panic!("needle was unexpectedly found in haystack"); - } -} - -/// This function is designed for running commands in a temporary directory -/// that is cleared after the function ends. +/// [`diff`][mod@diff] is implemented in terms of the [similar] library. /// -/// What this function does: -/// 1) Creates a temporary directory (`tmpdir`) -/// 2) Copies all files from the current directory to `tmpdir` -/// 3) Changes the current working directory to `tmpdir` -/// 4) Calls `callback` -/// 5) Switches working directory back to the original one -/// 6) Removes `tmpdir` -pub fn run_in_tmpdir<F: FnOnce()>(callback: F) { - let original_dir = cwd(); - let tmpdir = original_dir.join("../temporary-directory"); - copy_dir_all(".", &tmpdir); - - env::set_current_dir(&tmpdir).unwrap(); - callback(); - env::set_current_dir(original_dir).unwrap(); - fs::remove_dir_all(tmpdir).unwrap(); -} - -/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct -/// containing a `cmd: Command` field. The provided helpers are: -/// -/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended -/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add -/// new specific helper methods over relying on these generic argument providers. -/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to -/// methods of the same name on [`Command`]. -/// 3. Output and execution: `run` and `run_fail` are provided. These are -/// higher-level convenience methods which wait for the command to finish running and assert -/// that the command successfully ran or failed as expected. They return -/// [`CompletedProcess`], which can be used to assert the stdout/stderr/exit code of the executed -/// process. -/// -/// Example usage: -/// -/// ```ignore (illustrative) -/// struct CommandWrapper { cmd: Command } // <- required `cmd` field -/// -/// crate::impl_common_helpers!(CommandWrapper); -/// -/// impl CommandWrapper { -/// // ... additional specific helper methods -/// } -/// ``` -macro_rules! impl_common_helpers { - ($wrapper: ident) => { - impl $wrapper { - /// Specify an environment variable. - pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self - where - K: AsRef<::std::ffi::OsStr>, - V: AsRef<::std::ffi::OsStr>, - { - self.cmd.env(key, value); - self - } - - /// Remove an environmental variable. - pub fn env_remove<K>(&mut self, key: K) -> &mut Self - where - K: AsRef<::std::ffi::OsStr>, - { - self.cmd.env_remove(key); - self - } +/// [similar]: https://github.com/mitsuhiko/similar +pub use diff::{diff, Diff}; - /// Generic command argument provider. Prefer specific helper methods if possible. - /// Note that for some executables, arguments might be platform specific. For C/C++ - /// compilers, arguments might be platform *and* compiler specific. - pub fn arg<S>(&mut self, arg: S) -> &mut Self - where - S: AsRef<::std::ffi::OsStr>, - { - self.cmd.arg(arg); - self - } +/// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers. +pub use env::{env_var, env_var_os}; - /// Generic command arguments provider. Prefer specific helper methods if possible. - /// Note that for some executables, arguments might be platform specific. For C/C++ - /// compilers, arguments might be platform *and* compiler specific. - pub fn args<V, S>(&mut self, args: V) -> &mut Self - where - V: AsRef<[S]>, - S: AsRef<::std::ffi::OsStr>, - { - self.cmd.args(args.as_ref()); - self - } +/// Convenience helpers for running binaries and other commands. +pub use run::{cmd, run, run_fail, run_with_args}; - /// Inspect what the underlying [`Command`] is up to the - /// current construction. - pub fn inspect<I>(&mut self, inspector: I) -> &mut Self - where - I: FnOnce(&::std::process::Command), - { - self.cmd.inspect(inspector); - self - } +/// Helpers for checking target information. +pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname}; - /// Run the constructed command and assert that it is successfully run. - #[track_caller] - pub fn run(&mut self) -> crate::command::CompletedProcess { - self.cmd.run() - } +/// Helpers for building names of output artifacts that are potentially target-specific. +pub use artifact_names::{ + bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name, +}; - /// Run the constructed command and assert that it does not successfully run. - #[track_caller] - pub fn run_fail(&mut self) -> crate::command::CompletedProcess { - self.cmd.run_fail() - } +/// Path-related helpers. +pub use path_helpers::{ + cwd, filename_not_in_denylist, has_extension, has_prefix, has_suffix, not_contains, path, + shallow_find_files, source_root, +}; - /// Run the command but do not check its exit status. - /// Only use if you explicitly don't care about the exit status. - /// Prefer to use [`Self::run`] and [`Self::run_fail`] - /// whenever possible. - #[track_caller] - pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { - self.cmd.run_unchecked() - } +/// Helpers for scoped test execution where certain properties are attempted to be maintained. +pub use scoped_run::{run_in_tmpdir, test_while_readonly}; - /// Set the path where the command will be run. - pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self { - self.cmd.current_dir(path); - self - } - } - }; -} +pub use assertion_helpers::{ + assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains, +}; -use crate::command::{Command, CompletedProcess}; -pub(crate) use impl_common_helpers; +pub use string::{ + count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains, +}; diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs new file mode 100644 index 00000000000..f7fe4f54223 --- /dev/null +++ b/src/tools/run-make-support/src/macros.rs @@ -0,0 +1,113 @@ +/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct +/// containing a `cmd: Command` field. The provided helpers are: +/// +/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended +/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add +/// new specific helper methods over relying on these generic argument providers. +/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to +/// methods of the same name on [`Command`]. +/// 3. Output and execution: `run` and `run_fail` are provided. These are higher-level convenience +/// methods which wait for the command to finish running and assert that the command successfully +/// ran or failed as expected. They return [`CompletedProcess`], which can be used to assert the +/// stdout/stderr/exit code of the executed process. +/// +/// Example usage: +/// +/// ```ignore (illustrative) +/// struct CommandWrapper { cmd: Command } // <- required `cmd` field +/// +/// crate::macros::impl_common_helpers!(CommandWrapper); +/// +/// impl CommandWrapper { +/// // ... additional specific helper methods +/// } +/// ``` +/// +/// [`Command`]: crate::command::Command +/// [`CompletedProcess`]: crate::command::CompletedProcess +macro_rules! impl_common_helpers { + ($wrapper: ident) => { + impl $wrapper { + /// Specify an environment variable. + pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + V: AsRef<::std::ffi::OsStr>, + { + self.cmd.env(key, value); + self + } + + /// Remove an environmental variable. + pub fn env_remove<K>(&mut self, key: K) -> &mut Self + where + K: AsRef<::std::ffi::OsStr>, + { + self.cmd.env_remove(key); + self + } + + /// Generic command argument provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn arg<S>(&mut self, arg: S) -> &mut Self + where + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Prefer specific helper methods if possible. + /// Note that for some executables, arguments might be platform specific. For C/C++ + /// compilers, arguments might be platform *and* compiler specific. + pub fn args<V, S>(&mut self, args: V) -> &mut Self + where + V: AsRef<[S]>, + S: AsRef<::std::ffi::OsStr>, + { + self.cmd.args(args.as_ref()); + self + } + + /// Inspect what the underlying [`Command`] is up to the + /// current construction. + pub fn inspect<I>(&mut self, inspector: I) -> &mut Self + where + I: FnOnce(&::std::process::Command), + { + self.cmd.inspect(inspector); + self + } + + /// Run the constructed command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> crate::command::CompletedProcess { + self.cmd.run() + } + + /// Run the constructed command and assert that it does not successfully run. + #[track_caller] + pub fn run_fail(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_fail() + } + + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_unchecked() + } + + /// Set the path where the command will be run. + pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self { + self.cmd.current_dir(path); + self + } + } + }; +} + +pub(crate) use impl_common_helpers; diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs new file mode 100644 index 00000000000..f37ea8dfef8 --- /dev/null +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -0,0 +1,80 @@ +//! Collection of path-related helpers. + +use std::path::{Path, PathBuf}; + +use crate::env::env_var; + +/// Return the current working directory. +/// +/// This forwards to [`std::env::current_dir`], please see its docs regarding platform-specific +/// behavior. +#[must_use] +pub fn cwd() -> PathBuf { + std::env::current_dir().unwrap() +} + +/// Construct a `PathBuf` relative to the current working directory by joining `cwd()` with the +/// relative path. This is mostly a convenience helper so the test writer does not need to write +/// `PathBuf::from(path_like_string)`. +/// +/// # Example +/// +/// ```rust +/// let p = path("support_file.txt"); +/// ``` +pub fn path<P: AsRef<Path>>(p: P) -> PathBuf { + cwd().join(p.as_ref()) +} + +/// Path to the root `rust-lang/rust` source checkout. +#[must_use] +pub fn source_root() -> PathBuf { + env_var("SOURCE_ROOT").into() +} + +/// Browse the directory `path` non-recursively and return all files which respect the parameters +/// outlined by `closure`. +#[track_caller] +pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>( + path: P, + filter: F, +) -> Vec<PathBuf> { + let mut matching_files = Vec::new(); + for entry in std::fs::read_dir(path).unwrap() { + let entry = entry.expect("failed to read directory entry."); + let path = entry.path(); + + if path.is_file() && filter(&path) { + matching_files.push(path); + } + } + matching_files +} + +/// Returns true if the filename at `path` does not contain `expected`. +pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool { + !path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected)) +} + +/// Returns true if the filename at `path` is not in `expected`. +pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool { + let expected = expected.as_ref(); + path.as_ref() + .file_name() + .is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned())) +} + +/// Returns true if the filename at `path` starts with `prefix`. +pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix)) +} + +/// Returns true if the filename at `path` has the extension `extension`. +pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool { + path.as_ref().extension().is_some_and(|ext| ext == extension) +} + +/// Returns true if the filename at `path` ends with `suffix`. +pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool { + path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix)) +} diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 54730bb7de7..17f8ce34f19 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -4,9 +4,8 @@ use std::panic; use std::path::{Path, PathBuf}; use crate::command::{Command, CompletedProcess}; -use crate::{cwd, env_var, is_windows, set_host_rpath}; - -use super::handle_failed_output; +use crate::util::{handle_failed_output, set_host_rpath}; +use crate::{cwd, env_var, is_windows}; #[track_caller] fn run_common(name: &str, args: Option<&[&str]>) -> Command { diff --git a/src/tools/run-make-support/src/scoped_run.rs b/src/tools/run-make-support/src/scoped_run.rs new file mode 100644 index 00000000000..074a83922c5 --- /dev/null +++ b/src/tools/run-make-support/src/scoped_run.rs @@ -0,0 +1,69 @@ +//! Collection of helpers that try to maintain certain properties while running a test closure. + +use std::path::Path; + +use crate::fs; +use crate::path_helpers::cwd; +use crate::targets::is_windows; + +/// Ensure that the path P is read-only while the test runs, and restore original permissions at the +/// end so compiletest can clean up. This will panic on Windows if the path is a directory (as it +/// would otherwise do nothing) +/// +/// # Pitfalls +/// +/// - Some CI runners are ran as root which may bypass read-only permission restrictions. Unclear +/// exactly when such scenarios occur. +/// +/// # FIXME +/// +/// FIXME(Oneirical): This will no longer be required after compiletest receives the ability to +/// manipulate read-only files. See <https://github.com/rust-lang/rust/issues/126334>. +#[track_caller] +pub fn test_while_readonly<P, F>(path: P, closure: F) +where + P: AsRef<Path>, + F: FnOnce() + std::panic::UnwindSafe, +{ + let path = path.as_ref(); + if is_windows() && path.is_dir() { + eprintln!("This helper function cannot be used on Windows to make directories readonly."); + eprintln!( + "See the official documentation: + https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" + ); + panic!("`test_while_readonly` on directory detected while on Windows."); + } + let metadata = fs::metadata(&path); + let original_perms = metadata.permissions(); + + let mut new_perms = original_perms.clone(); + new_perms.set_readonly(true); + fs::set_permissions(&path, new_perms); + + let success = std::panic::catch_unwind(closure); + + fs::set_permissions(&path, original_perms); + success.unwrap(); +} + +/// This function is designed for running commands in a temporary directory that is cleared after +/// the function ends. +/// +/// What this function does: +/// 1. Creates a temporary directory (`tmpdir`) +/// 2. Copies all files from the current directory to `tmpdir` +/// 3. Changes the current working directory to `tmpdir` +/// 4. Calls `callback` +/// 5. Switches working directory back to the original one +/// 6. Removes `tmpdir` +pub fn run_in_tmpdir<F: FnOnce()>(callback: F) { + let original_dir = cwd(); + let tmpdir = original_dir.join("../temporary-directory"); + fs::copy_dir_all(".", &tmpdir); + + std::env::set_current_dir(&tmpdir).unwrap(); + callback(); + std::env::set_current_dir(original_dir).unwrap(); + fs::remove_dir_all(tmpdir); +} diff --git a/src/tools/run-make-support/src/string.rs b/src/tools/run-make-support/src/string.rs new file mode 100644 index 00000000000..a79004b8ec6 --- /dev/null +++ b/src/tools/run-make-support/src/string.rs @@ -0,0 +1,50 @@ +use std::path::Path; + +use crate::fs; +use crate::path_helpers::{cwd, has_extension, shallow_find_files}; + +/// Gathers all files in the current working directory that have the extension `ext`, and counts +/// the number of lines within that contain a match with the regex pattern `re`. +pub fn count_regex_matches_in_files_with_extension(re: ®ex::Regex, ext: &str) -> usize { + let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext)); + + let mut count = 0; + for file in fetched_files { + let content = fs::read_to_string(file); + count += content.lines().filter(|line| re.is_match(&line)).count(); + } + + count +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert +/// that it contains `expected`. +#[track_caller] +pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) { + let buffer = fs::read(path.as_ref()); + let expected = expected.as_ref(); + if !String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was not found in file"); + } +} + +/// Read the contents of a file that cannot simply be read by +/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert +/// that it does not contain `expected`. +#[track_caller] +pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) { + let buffer = fs::read(path.as_ref()); + let expected = expected.as_ref(); + if String::from_utf8_lossy(&buffer).contains(expected) { + eprintln!("=== FILE CONTENTS (LOSSY) ==="); + eprintln!("{}", String::from_utf8_lossy(&buffer)); + eprintln!("=== SPECIFIED TEXT ==="); + eprintln!("{}", expected); + panic!("specified text was unexpectedly found in file"); + } +} diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs new file mode 100644 index 00000000000..5dcb0b83430 --- /dev/null +++ b/src/tools/run-make-support/src/targets.rs @@ -0,0 +1,49 @@ +use std::panic; + +use crate::command::Command; +use crate::env_var; +use crate::util::handle_failed_output; + +/// `TARGET` +#[must_use] +pub fn target() -> String { + env_var("TARGET") +} + +/// Check if target is windows-like. +#[must_use] +pub fn is_windows() -> bool { + target().contains("windows") +} + +/// Check if target uses msvc. +#[must_use] +pub fn is_msvc() -> bool { + target().contains("msvc") +} + +/// Check if target uses macOS. +#[must_use] +pub fn is_darwin() -> bool { + target().contains("darwin") +} + +/// Check if `component` is within `LLVM_COMPONENTS` +#[must_use] +pub fn llvm_components_contain(component: &str) -> bool { + // `LLVM_COMPONENTS` is a space-separated list of words + env_var("LLVM_COMPONENTS").split_whitespace().find(|s| s == &component).is_some() +} + +/// Run `uname`. This assumes that `uname` is available on the platform! +#[track_caller] +#[must_use] +pub fn uname() -> String { + let caller = panic::Location::caller(); + let mut uname = Command::new("uname"); + let output = uname.run(); + if !output.status().success() { + handle_failed_output(&uname, output, caller.line()); + } + output.stdout_utf8() +} diff --git a/src/tools/run-make-support/src/util.rs b/src/tools/run-make-support/src/util.rs new file mode 100644 index 00000000000..703e3ad1c6c --- /dev/null +++ b/src/tools/run-make-support/src/util.rs @@ -0,0 +1,39 @@ +use std::path::PathBuf; + +use crate::command::{Command, CompletedProcess}; +use crate::env::env_var; +use crate::path_helpers::cwd; + +/// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the +/// executed command, failure location, output status and stdout/stderr, and abort the process with +/// exit code `1`. +pub(crate) fn handle_failed_output( + cmd: &Command, + output: CompletedProcess, + caller_line_number: u32, +) -> ! { + if output.status().success() { + eprintln!("command unexpectedly succeeded at line {caller_line_number}"); + } else { + eprintln!("command failed at line {caller_line_number}"); + } + eprintln!("{cmd:?}"); + eprintln!("output status: `{}`", output.status()); + eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); + eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); + std::process::exit(1) +} + +/// Set the runtime library path as needed for running the host rustc/rustdoc/etc. +pub(crate) fn set_host_rpath(cmd: &mut Command) { + let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(cwd()); + paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); + for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) { + paths.push(p.to_path_buf()); + } + std::env::join_paths(paths.iter()).unwrap() + }); +} diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml index 11014338d72..e11d6e15d10 100644 --- a/src/tools/rust-analyzer/.github/workflows/release.yaml +++ b/src/tools/rust-analyzer/.github/workflows/release.yaml @@ -132,7 +132,7 @@ jobs: run: target/${{ matrix.target }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std - name: Upload artifacts - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: dist-${{ matrix.target }} path: ./dist @@ -177,7 +177,7 @@ jobs: - run: rm -rf editors/code/server - name: Upload artifacts - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 with: name: dist-x86_64-unknown-linux-musl path: ./dist @@ -206,39 +206,39 @@ jobs: - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV - run: 'echo "HEAD_SHA: $HEAD_SHA"' - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-aarch64-apple-darwin path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-x86_64-apple-darwin path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-x86_64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-x86_64-unknown-linux-musl path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-aarch64-unknown-linux-gnu path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-arm-unknown-linux-gnueabihf path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-x86_64-pc-windows-msvc path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-i686-pc-windows-msvc path: dist - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v4 with: name: dist-aarch64-pc-windows-msvc path: dist diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 57d43dad3fd..e9ebe26f42c 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -167,9 +167,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chalk-derive" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92a0aedc4ac2adc5c0b7dc9ec38c5c816284ad28da6d4ecd01873b9683f54972" +checksum = "9426c8fd0fe61c3da880b801d3b510524df17843a8f9ec1f5b9cec24fb7412df" dependencies = [ "proc-macro2", "quote", @@ -179,9 +179,9 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119" +checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093" dependencies = [ "bitflags 2.5.0", "chalk-derive", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae4ba8ce5bd2e1b59f1f79495bc8704db09a8285e51cc5ddf01d9baee1bf447d" +checksum = "129dc03458f71cfb9c3cd621c9c68166a94e87b85b16ccd29af015d7ff9a1c61" dependencies = [ "chalk-derive", "chalk-ir", @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.97.0" +version = "0.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ec1b3b7f7b1ec38f099ef39c2bc3ea29335be1b8316d114baff46d96d131e9" +checksum = "d7e8a8c1e928f98cdf227b868416ef21dcd8cc3c61b347576d783713444d41c8" dependencies = [ "chalk-derive", "chalk-ir", @@ -221,11 +221,6 @@ name = "countme" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" -dependencies = [ - "dashmap", - "once_cell", - "rustc-hash", -] [[package]] name = "cov-mark" @@ -548,10 +543,10 @@ dependencies = [ "limit", "mbe", "once_cell", - "profile", "ra-ap-rustc_abi", "ra-ap-rustc_parse_format", "rustc-hash", + "rustc_apfloat", "smallvec", "span", "stdx", @@ -616,9 +611,10 @@ dependencies = [ "oorandom", "project-model", "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.53.0", + "ra-ap-rustc_index", "ra-ap-rustc_pattern_analysis", "rustc-hash", + "rustc_apfloat", "scoped-tls", "smallvec", "span", @@ -664,6 +660,7 @@ dependencies = [ "profile", "pulldown-cmark", "pulldown-cmark-to-cmark", + "rustc_apfloat", "smallvec", "span", "stdx", @@ -809,7 +806,6 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", - "serde", ] [[package]] @@ -1046,6 +1042,7 @@ checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" name = "mbe" version = "0.0.0" dependencies = [ + "arrayvec", "cov-mark", "parser", "rustc-hash", @@ -1250,7 +1247,6 @@ dependencies = [ "expect-test", "limit", "ra-ap-rustc_lexer", - "sourcegen", "stdx", "tracing", ] @@ -1328,18 +1324,14 @@ dependencies = [ "base-db", "indexmap", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap2", - "object 0.33.0", "paths", "rustc-hash", "serde", "serde_json", - "snap", "span", "stdx", "text-size", "tracing", - "triomphe", "tt", ] @@ -1357,6 +1349,7 @@ dependencies = [ "proc-macro-api", "proc-macro-test", "ra-ap-rustc_lexer", + "snap", "span", "stdx", "tt", @@ -1403,13 +1396,9 @@ name = "profile" version = "0.0.0" dependencies = [ "cfg-if", - "countme", - "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc", - "once_cell", "perf-event", "tikv-jemalloc-ctl", - "tracing", "windows-sys 0.52.0", ] @@ -1492,46 +1481,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46" dependencies = [ "bitflags 2.5.0", - "ra-ap-rustc_index 0.53.0", + "ra-ap-rustc_index", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20" -dependencies = [ - "arrayvec", - "ra-ap-rustc_index_macros 0.44.0", - "smallvec", -] - -[[package]] -name = "ra-ap-rustc_index" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9" dependencies = [ "arrayvec", - "ra-ap-rustc_index_macros 0.53.0", + "ra-ap-rustc_index_macros", "smallvec", ] [[package]] name = "ra-ap-rustc_index_macros" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8782aaf3a113837c533dfb1c45df91cd17e1fdd1d2f9a20c2e0d1976025c4f1f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "ra-ap-rustc_index_macros" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1" @@ -1558,17 +1524,17 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135" dependencies = [ - "ra-ap-rustc_index 0.53.0", + "ra-ap-rustc_index", "ra-ap-rustc_lexer", ] [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.44.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334" +checksum = "34768e1faf88c31f2e9ad57b48318a52b507dafac0cddbf01b5d63bfc0b0a365" dependencies = [ - "ra-ap-rustc_index 0.44.0", + "ra-ap-rustc_index", "rustc-hash", "rustc_apfloat", "smallvec", @@ -1685,7 +1651,6 @@ dependencies = [ "ide", "ide-db", "ide-ssr", - "indexmap", "itertools", "load-cargo", "lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1708,7 +1673,6 @@ dependencies = [ "semver", "serde", "serde_json", - "sourcegen", "stdx", "syntax", "test-fixture", @@ -1908,13 +1872,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] -name = "sourcegen" -version = "0.0.0" -dependencies = [ - "xshell", -] - -[[package]] name = "span" version = "0.0.0" dependencies = [ @@ -1985,6 +1942,7 @@ dependencies = [ "rayon", "rowan", "rustc-hash", + "rustc_apfloat", "smol_str", "stdx", "test-utils", @@ -2251,6 +2209,7 @@ dependencies = [ name = "tt" version = "0.0.0" dependencies = [ + "arrayvec", "smol_str", "stdx", "text-size", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 583c7bbe338..d4c3b7a3bfb 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -10,9 +10,7 @@ license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] [profile.dev] -# Disabling debug info speeds up builds a bunch, -# and we don't rely on it for debugging that much. -debug = 0 +debug = 1 [profile.dev.package] # These speed up local tests. @@ -89,10 +87,9 @@ ra-ap-rustc_lexer = { version = "0.53.0", default-features = false } ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false } ra-ap-rustc_index = { version = "0.53.0", default-features = false } ra-ap-rustc_abi = { version = "0.53.0", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.53.0", default-features = false } # local crates that aren't published to crates.io. These should not have versions. -sourcegen = { path = "./crates/sourcegen" } test-fixture = { path = "./crates/test-fixture" } test-utils = { path = "./crates/test-utils" } @@ -107,10 +104,10 @@ arrayvec = "0.7.4" bitflags = "2.4.1" cargo_metadata = "0.18.1" camino = "1.1.6" -chalk-solve = { version = "0.97.0", default-features = false } -chalk-ir = "0.97.0" -chalk-recursive = { version = "0.97.0", default-features = false } -chalk-derive = "0.97.0" +chalk-solve = { version = "0.98.0", default-features = false } +chalk-ir = "0.98.0" +chalk-recursive = { version = "0.98.0", default-features = false } +chalk-derive = "0.98.0" crossbeam-channel = "0.5.8" dissimilar = "1.0.7" dot = "0.1.4" @@ -122,6 +119,8 @@ hashbrown = { version = "0.14", features = [ indexmap = "2.1.0" itertools = "0.12.0" libc = "0.2.150" +libloading = "0.8.0" +memmap2 = "0.5.4" nohash-hasher = "0.2.0" oorandom = "11.1.3" object = { version = "0.33.0", default-features = false, features = [ @@ -145,6 +144,7 @@ smallvec = { version = "1.10.0", features = [ "const_generics", ] } smol_str = "0.2.1" +snap = "1.1.0" text-size = "1.1.1" tracing = "0.1.40" tracing-tree = "0.3.0" @@ -158,6 +158,7 @@ url = "2.3.1" xshell = "0.2.5" + # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=5.5.3", features = ["raw-api"] } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index f5165ea8a7b..96fbbc317d4 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,7 +1,5 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod change; mod input; diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 9a365889e6a..8b30286a0a8 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -1,7 +1,5 @@ //! cfg defines conditional compiling options, `cfg` attribute parser and evaluator -#![warn(rust_2018_idioms, unused_lifetimes)] - mod cfg_expr; mod dnf; #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index 4584400e66f..778def5d2be 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -6,8 +6,6 @@ // addition to `cargo check`. Either split it into 3 crates (one for test, one for check // and one common utilities) or change its name and docs to reflect the current state. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{fmt, io, process::Command, time::Duration}; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; @@ -428,6 +426,8 @@ impl FlycheckActor { } } + cmd.arg("--keep-going"); + options.apply_on_command(&mut cmd); (cmd, options.extra_args.clone()) } diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index 41c59ea0d93..8ac2d003137 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -28,6 +28,7 @@ tracing.workspace = true smallvec.workspace = true hashbrown.workspace = true triomphe.workspace = true +rustc_apfloat = "0.2.0" ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true @@ -37,7 +38,6 @@ stdx.workspace = true intern.workspace = true base-db.workspace = true syntax.workspace = true -profile.workspace = true hir-expand.workspace = true mbe.workspace = true cfg.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index faba9050fc4..be7068c807a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -15,8 +15,8 @@ use span::AstIdMap; use stdx::never; use syntax::{ ast::{ - self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName, - RangeItem, SlicePatComponents, + self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs, + HasLoopBody, HasName, RangeItem, SlicePatComponents, }, AstNode, AstPtr, AstToken as _, SyntaxNodePtr, }; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs index 61b2481978e..f9e55559dab 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/builtin_type.rs @@ -30,8 +30,10 @@ pub enum BuiltinUint { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum BuiltinFloat { + F16, F32, F64, + F128, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -65,8 +67,10 @@ impl BuiltinType { (name![u64], BuiltinType::Uint(BuiltinUint::U64)), (name![u128], BuiltinType::Uint(BuiltinUint::U128)), + (name![f16], BuiltinType::Float(BuiltinFloat::F16)), (name![f32], BuiltinType::Float(BuiltinFloat::F32)), (name![f64], BuiltinType::Float(BuiltinFloat::F64)), + (name![f128], BuiltinType::Float(BuiltinFloat::F128)), ]; pub fn by_name(name: &Name) -> Option<Self> { @@ -97,8 +101,10 @@ impl AsName for BuiltinType { BuiltinUint::U128 => name![u128], }, BuiltinType::Float(it) => match it { + BuiltinFloat::F16 => name![f16], BuiltinFloat::F32 => name![f32], BuiltinFloat::F64 => name![f64], + BuiltinFloat::F128 => name![f128], }, } } @@ -155,8 +161,10 @@ impl BuiltinUint { impl BuiltinFloat { pub fn from_suffix(suffix: &str) -> Option<BuiltinFloat> { let res = match suffix { + "f16" => BuiltinFloat::F16, "f32" => BuiltinFloat::F32, "f64" => BuiltinFloat::F64, + "f128" => BuiltinFloat::F128, _ => return None, }; Some(res) @@ -192,8 +200,10 @@ impl fmt::Display for BuiltinUint { impl fmt::Display for BuiltinFloat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { + BuiltinFloat::F16 => "f16", BuiltinFloat::F32 => "f32", BuiltinFloat::F64 => "f64", + BuiltinFloat::F128 => "f128", }) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs index 106109eb184..0438278ca27 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs @@ -214,8 +214,8 @@ impl ChildBySource for GenericDefId { } let generic_params = db.generic_params(*self); - let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); - let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); + let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); + let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); // For traits the first type index is `Self`, skip it. if let GenericDefId::TraitId(_) = *self { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 43381636721..55043fdc4b0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -323,7 +323,7 @@ impl TraitAliasData { pub struct ImplData { pub target_trait: Option<Interned<TraitRef>>, pub self_ty: Interned<TypeRef>, - pub items: Vec<AssocItemId>, + pub items: Box<[AssocItemId]>, pub is_negative: bool, pub is_unsafe: bool, // box it as the vec is usually empty anyways @@ -637,10 +637,6 @@ impl<'a> AssocItemCollector<'a> { attr, ) { Ok(ResolvedAttr::Macro(call_id)) => { - // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.expand_proc_attr_macros() { - continue 'attrs; - } let loc = self.db.lookup_intern_macro_call(call_id); if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind { // If there's no expander for the proc macro (e.g. the diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 61fed71218e..0eb9e7d30b2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -80,9 +80,11 @@ pub trait InternDatabase: SourceDatabase { #[salsa::query_group(DefDatabaseStorage)] pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDatabase> { + /// Whether to expand procedural macros during name resolution. #[salsa::input] fn expand_proc_attr_macros(&self) -> bool; + /// Computes an [`ItemTree`] for the given file or macro expansion. #[salsa::invoke(ItemTree::file_item_tree_query)] fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; @@ -96,6 +98,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba #[salsa::invoke(DefMap::block_def_map_query)] fn block_def_map(&self, block: BlockId) -> Arc<DefMap>; + /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution. fn macro_def(&self, m: MacroId) -> MacroDefId; // region:data @@ -190,6 +193,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba #[salsa::invoke(Attrs::fields_attrs_query)] fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; + // should this really be a query? #[salsa::invoke(crate::attr::fields_attrs_source_map)] fn fields_attrs_source_map( &self, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 58a1872ef25..9a3c0495414 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -183,6 +183,8 @@ fn find_path_for_module( let kind = if name_already_occupied_in_type_ns { cov_mark::hit!(ambiguous_crate_start); PathKind::Abs + } else if ctx.cfg.prefer_absolute { + PathKind::Abs } else { PathKind::Plain }; @@ -564,7 +566,13 @@ mod tests { /// item the `path` refers to returns that same path when called from the /// module the cursor is in. #[track_caller] - fn check_found_path_(ra_fixture: &str, path: &str, prefer_prelude: bool, expect: Expect) { + fn check_found_path_( + ra_fixture: &str, + path: &str, + prefer_prelude: bool, + prefer_absolute: bool, + expect: Expect, + ) { let (db, pos) = TestDB::with_position(ra_fixture); let module = db.module_at_position(pos); let parsed_path_file = @@ -604,7 +612,7 @@ mod tests { module, prefix, ignore_local_imports, - ImportPathConfig { prefer_no_std: false, prefer_prelude }, + ImportPathConfig { prefer_no_std: false, prefer_prelude, prefer_absolute }, ); format_to!( res, @@ -619,11 +627,15 @@ mod tests { } fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) { - check_found_path_(ra_fixture, path, false, expect); + check_found_path_(ra_fixture, path, false, false, expect); } fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) { - check_found_path_(ra_fixture, path, true, expect); + check_found_path_(ra_fixture, path, true, false, expect); + } + + fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) { + check_found_path_(ra_fixture, path, false, true, expect); } #[test] @@ -871,6 +883,39 @@ pub mod ast { } #[test] + fn partially_imported_with_prefer_absolute() { + cov_mark::check!(partially_imported); + // Similar to partially_imported test case above, but with prefer_absolute enabled. + // Even if the actual imported item is in external crate, if the path to that item + // is starting from the imported name, then the path should not start from "::". + // i.e. The first line in the expected output should not start from "::". + check_found_path_absolute( + r#" +//- /main.rs crate:main deps:syntax + +use syntax::ast; +$0 + +//- /lib.rs crate:syntax +pub mod ast { + pub enum ModuleItem { + A, B, C, + } +} + "#, + "syntax::ast::ModuleItem", + expect![[r#" + Plain (imports ✔): ast::ModuleItem + Plain (imports ✖): ::syntax::ast::ModuleItem + ByCrate(imports ✔): crate::ast::ModuleItem + ByCrate(imports ✖): ::syntax::ast::ModuleItem + BySelf (imports ✔): self::ast::ModuleItem + BySelf (imports ✖): ::syntax::ast::ModuleItem + "#]], + ); + } + + #[test] fn same_crate_reexport() { check_found_path( r#" @@ -1770,6 +1815,43 @@ pub mod foo { } #[test] + fn respects_absolute_setting() { + let ra_fixture = r#" +//- /main.rs crate:main deps:krate +$0 +//- /krate.rs crate:krate +pub mod foo { + pub struct Foo; +} +"#; + check_found_path( + ra_fixture, + "krate::foo::Foo", + expect![[r#" + Plain (imports ✔): krate::foo::Foo + Plain (imports ✖): krate::foo::Foo + ByCrate(imports ✔): krate::foo::Foo + ByCrate(imports ✖): krate::foo::Foo + BySelf (imports ✔): krate::foo::Foo + BySelf (imports ✖): krate::foo::Foo + "#]], + ); + + check_found_path_absolute( + ra_fixture, + "krate::foo::Foo", + expect![[r#" + Plain (imports ✔): ::krate::foo::Foo + Plain (imports ✖): ::krate::foo::Foo + ByCrate(imports ✔): ::krate::foo::Foo + ByCrate(imports ✖): ::krate::foo::Foo + BySelf (imports ✔): ::krate::foo::Foo + BySelf (imports ✖): ::krate::foo::Foo + "#]], + ); + } + + #[test] fn respect_segment_length() { check_found_path( r#" diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index b9f8082391f..ebaaef66db6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -28,6 +28,7 @@ use crate::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; +/// The index of the self param in the generic of the non-parent definition. const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> = LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); @@ -158,9 +159,9 @@ pub enum GenericParamDataRef<'a> { /// Data about the generic parameters of a function, struct, impl, etc. #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct GenericParams { - pub type_or_consts: Arena<TypeOrConstParamData>, - pub lifetimes: Arena<LifetimeParamData>, - pub where_predicates: Box<[WherePredicate]>, + type_or_consts: Arena<TypeOrConstParamData>, + lifetimes: Arena<LifetimeParamData>, + where_predicates: Box<[WherePredicate]>, } impl ops::Index<LocalTypeOrConstParamId> for GenericParams { @@ -205,6 +206,219 @@ pub enum WherePredicateTypeTarget { TypeOrConstParam(LocalTypeOrConstParamId), } +impl GenericParams { + /// Number of Generic parameters (type_or_consts + lifetimes) + #[inline] + pub fn len(&self) -> usize { + self.type_or_consts.len() + self.lifetimes.len() + } + + #[inline] + pub fn len_lifetimes(&self) -> usize { + self.lifetimes.len() + } + + #[inline] + pub fn len_type_or_consts(&self) -> usize { + self.type_or_consts.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { + self.where_predicates.iter() + } + + /// Iterator of type_or_consts field + #[inline] + pub fn iter_type_or_consts( + &self, + ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> { + self.type_or_consts.iter() + } + + /// Iterator of lifetimes field + #[inline] + pub fn iter_lt( + &self, + ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> { + self.lifetimes.iter() + } + + pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> { + self.type_or_consts.iter().find_map(|(id, p)| { + if p.name().as_ref() == Some(&name) && p.type_param().is_some() { + Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) + } else { + None + } + }) + } + + pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> { + self.type_or_consts.iter().find_map(|(id, p)| { + if p.name().as_ref() == Some(&name) && p.const_param().is_some() { + Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) + } else { + None + } + }) + } + + #[inline] + pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { + if self.type_or_consts.is_empty() { + return None; + } + matches!( + self.type_or_consts[SELF_PARAM_ID_IN_SELF], + TypeOrConstParamData::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }) + ) + .then(|| SELF_PARAM_ID_IN_SELF) + } + + pub fn find_lifetime_by_name( + &self, + name: &Name, + parent: GenericDefId, + ) -> Option<LifetimeParamId> { + self.lifetimes.iter().find_map(|(id, p)| { + if &p.name == name { + Some(LifetimeParamId { local_id: id, parent }) + } else { + None + } + }) + } + + pub(crate) fn generic_params_query( + db: &dyn DefDatabase, + def: GenericDefId, + ) -> Interned<GenericParams> { + let _p = tracing::info_span!("generic_params_query").entered(); + + let krate = def.krate(db); + let cfg_options = db.crate_graph(); + let cfg_options = &cfg_options[krate].cfg_options; + + // Returns the generic parameters that are enabled under the current `#[cfg]` options + let enabled_params = + |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| { + let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); + let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); + let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); + + // In the common case, no parameters will by disabled by `#[cfg]` attributes. + // Therefore, make a first pass to check if all parameters are enabled and, if so, + // clone the `Interned<GenericParams>` instead of recreating an identical copy. + let all_type_or_consts_enabled = + params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx))); + let all_lifetimes_enabled = + params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx))); + + if all_type_or_consts_enabled && all_lifetimes_enabled { + params.clone() + } else { + Interned::new(GenericParams { + type_or_consts: all_type_or_consts_enabled + .then(|| params.type_or_consts.clone()) + .unwrap_or_else(|| { + params + .type_or_consts + .iter() + .filter(|&(idx, _)| enabled(attr_owner_ct(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + lifetimes: all_lifetimes_enabled + .then(|| params.lifetimes.clone()) + .unwrap_or_else(|| { + params + .lifetimes + .iter() + .filter(|&(idx, _)| enabled(attr_owner_lt(idx))) + .map(|(_, param)| param.clone()) + .collect() + }), + where_predicates: params.where_predicates.clone(), + }) + } + }; + fn id_to_generics<Id: GenericsItemTreeNode>( + db: &dyn DefDatabase, + id: impl for<'db> Lookup< + Database<'db> = dyn DefDatabase + 'db, + Data = impl ItemTreeLoc<Id = Id>, + >, + enabled_params: impl Fn( + &Interned<GenericParams>, + &ItemTree, + GenericModItem, + ) -> Interned<GenericParams>, + ) -> Interned<GenericParams> + where + FileItemTreeId<Id>: Into<GenericModItem>, + { + let id = id.lookup(db).item_tree_id(); + let tree = id.item_tree(db); + let item = &tree[id.value]; + enabled_params(item.generic_params(), &tree, id.value.into()) + } + + match def { + GenericDefId::FunctionId(id) => { + let loc = id.lookup(db); + let tree = loc.id.item_tree(db); + let item = &tree[loc.id.value]; + + let enabled_params = + enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into()); + + let module = loc.container.module(db); + let func_data = db.function_data(id); + if func_data.params.is_empty() { + enabled_params + } else { + let mut generic_params = GenericParamsCollector { + type_or_consts: enabled_params.type_or_consts.clone(), + lifetimes: enabled_params.lifetimes.clone(), + where_predicates: enabled_params.where_predicates.clone().into(), + }; + + // Don't create an `Expander` if not needed since this + // could cause a reparse after the `ItemTree` has been created due to the spanmap. + let mut expander = Lazy::new(|| { + (module.def_map(db), Expander::new(db, loc.id.file_id(), module)) + }); + for param in func_data.params.iter() { + generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); + } + Interned::new(generic_params.finish()) + } + } + GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params), + GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params), + GenericDefId::ConstId(_) => Interned::new(GenericParams { + type_or_consts: Default::default(), + lifetimes: Default::default(), + where_predicates: Default::default(), + }), + } + } +} + #[derive(Clone, Default)] pub(crate) struct GenericParamsCollector { pub(crate) type_or_consts: Arena<TypeOrConstParamData>, @@ -441,202 +655,3 @@ impl GenericParamsCollector { } } } - -impl GenericParams { - /// Number of Generic parameters (type_or_consts + lifetimes) - #[inline] - pub fn len(&self) -> usize { - self.type_or_consts.len() + self.lifetimes.len() - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Iterator of type_or_consts field - #[inline] - pub fn iter_type_or_consts( - &self, - ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> { - self.type_or_consts.iter() - } - - /// Iterator of lifetimes field - #[inline] - pub fn iter_lt( - &self, - ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> { - self.lifetimes.iter() - } - - pub(crate) fn generic_params_query( - db: &dyn DefDatabase, - def: GenericDefId, - ) -> Interned<GenericParams> { - let _p = tracing::info_span!("generic_params_query").entered(); - - let krate = def.module(db).krate; - let cfg_options = db.crate_graph(); - let cfg_options = &cfg_options[krate].cfg_options; - - // Returns the generic parameters that are enabled under the current `#[cfg]` options - let enabled_params = - |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| { - let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options); - let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param); - let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param); - - // In the common case, no parameters will by disabled by `#[cfg]` attributes. - // Therefore, make a first pass to check if all parameters are enabled and, if so, - // clone the `Interned<GenericParams>` instead of recreating an identical copy. - let all_type_or_consts_enabled = - params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx))); - let all_lifetimes_enabled = - params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx))); - - if all_type_or_consts_enabled && all_lifetimes_enabled { - params.clone() - } else { - Interned::new(GenericParams { - type_or_consts: all_type_or_consts_enabled - .then(|| params.type_or_consts.clone()) - .unwrap_or_else(|| { - params - .type_or_consts - .iter() - .filter(|&(idx, _)| enabled(attr_owner_ct(idx))) - .map(|(_, param)| param.clone()) - .collect() - }), - lifetimes: all_lifetimes_enabled - .then(|| params.lifetimes.clone()) - .unwrap_or_else(|| { - params - .lifetimes - .iter() - .filter(|&(idx, _)| enabled(attr_owner_lt(idx))) - .map(|(_, param)| param.clone()) - .collect() - }), - where_predicates: params.where_predicates.clone(), - }) - } - }; - fn id_to_generics<Id: GenericsItemTreeNode>( - db: &dyn DefDatabase, - id: impl for<'db> Lookup< - Database<'db> = dyn DefDatabase + 'db, - Data = impl ItemTreeLoc<Id = Id>, - >, - enabled_params: impl Fn( - &Interned<GenericParams>, - &ItemTree, - GenericModItem, - ) -> Interned<GenericParams>, - ) -> Interned<GenericParams> - where - FileItemTreeId<Id>: Into<GenericModItem>, - { - let id = id.lookup(db).item_tree_id(); - let tree = id.item_tree(db); - let item = &tree[id.value]; - enabled_params(item.generic_params(), &tree, id.value.into()) - } - - match def { - GenericDefId::FunctionId(id) => { - let loc = id.lookup(db); - let tree = loc.id.item_tree(db); - let item = &tree[loc.id.value]; - - let enabled_params = - enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into()); - - let module = loc.container.module(db); - let func_data = db.function_data(id); - if func_data.params.is_empty() { - enabled_params - } else { - let mut generic_params = GenericParamsCollector { - type_or_consts: enabled_params.type_or_consts.clone(), - lifetimes: enabled_params.lifetimes.clone(), - where_predicates: enabled_params.where_predicates.clone().into(), - }; - - // Don't create an `Expander` if not needed since this - // could cause a reparse after the `ItemTree` has been created due to the spanmap. - let mut expander = Lazy::new(|| { - (module.def_map(db), Expander::new(db, loc.id.file_id(), module)) - }); - for param in func_data.params.iter() { - generic_params.fill_implicit_impl_trait_args(db, &mut expander, param); - } - Interned::new(generic_params.finish()) - } - } - GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params), - GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params), - GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params), - GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params), - GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params), - GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params), - GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params), - GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => { - Interned::new(GenericParams { - type_or_consts: Default::default(), - lifetimes: Default::default(), - where_predicates: Default::default(), - }) - } - } - } - - pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> { - self.type_or_consts.iter().find_map(|(id, p)| { - if p.name().as_ref() == Some(&name) && p.type_param().is_some() { - Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) - } else { - None - } - }) - } - - pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> { - self.type_or_consts.iter().find_map(|(id, p)| { - if p.name().as_ref() == Some(&name) && p.const_param().is_some() { - Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent })) - } else { - None - } - }) - } - - pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { - if self.type_or_consts.is_empty() { - return None; - } - matches!( - self.type_or_consts[SELF_PARAM_ID_IN_SELF], - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| SELF_PARAM_ID_IN_SELF) - } - - pub fn find_lifetime_by_name( - &self, - name: &Name, - parent: GenericDefId, - ) -> Option<LifetimeParamId> { - self.lifetimes.iter().find_map(|(id, p)| { - if &p.name == name { - Some(LifetimeParamId { local_id: id, parent }) - } else { - None - } - }) - } -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index fd6f4a3d089..d306f9be657 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -20,6 +20,7 @@ use std::fmt; use hir_expand::name::Name; use intern::Interned; use la_arena::{Idx, RawIdx}; +use rustc_apfloat::ieee::{Half as f16, Quad as f128}; use smallvec::SmallVec; use syntax::ast; @@ -56,29 +57,38 @@ pub struct Label { } pub type LabelId = Idx<Label>; -// We convert float values into bits and that's how we don't need to deal with f32 and f64. -// For PartialEq, bits comparison should work, as ordering is not important +// We leave float values as a string to avoid double rounding. +// For PartialEq, string comparison should work, as ordering is not important // https://github.com/rust-lang/rust-analyzer/issues/12380#issuecomment-1137284360 -#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)] -pub struct FloatTypeWrapper(u64); +#[derive(Default, Debug, Clone, Eq, PartialEq)] +pub struct FloatTypeWrapper(Box<str>); +// FIXME(#17451): Use builtin types once stabilised. impl FloatTypeWrapper { - pub fn new(value: f64) -> Self { - Self(value.to_bits()) + pub fn new(value: String) -> Self { + Self(value.into()) } - pub fn into_f64(self) -> f64 { - f64::from_bits(self.0) + pub fn to_f128(&self) -> f128 { + self.0.parse().unwrap_or_default() } - pub fn into_f32(self) -> f32 { - f64::from_bits(self.0) as f32 + pub fn to_f64(&self) -> f64 { + self.0.parse().unwrap_or_default() + } + + pub fn to_f32(&self) -> f32 { + self.0.parse().unwrap_or_default() + } + + pub fn to_f16(&self) -> f16 { + self.0.parse().unwrap_or_default() } } impl fmt::Display for FloatTypeWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", f64::from_bits(self.0)) + f.write_str(&self.0) } } @@ -91,7 +101,7 @@ pub enum Literal { Bool(bool), Int(i128, Option<BuiltinInt>), Uint(u128, Option<BuiltinUint>), - // Here we are using a wrapper around float because f32 and f64 do not implement Eq, so they + // Here we are using a wrapper around float because float primitives do not implement Eq, so they // could not be used directly here, to understand how the wrapper works go to definition of // FloatTypeWrapper Float(FloatTypeWrapper, Option<BuiltinFloat>), @@ -120,10 +130,7 @@ impl From<ast::LiteralKind> for Literal { match ast_lit_kind { LiteralKind::IntNumber(lit) => { if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { - Literal::Float( - FloatTypeWrapper::new(lit.float_value().unwrap_or(Default::default())), - builtin, - ) + Literal::Float(FloatTypeWrapper::new(lit.value_string()), builtin) } else if let builtin @ Some(_) = lit.suffix().and_then(BuiltinUint::from_suffix) { Literal::Uint(lit.value().unwrap_or(0), builtin) } else { @@ -133,7 +140,7 @@ impl From<ast::LiteralKind> for Literal { } LiteralKind::FloatNumber(lit) => { let ty = lit.suffix().and_then(BuiltinFloat::from_suffix); - Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty) + Literal::Float(FloatTypeWrapper::new(lit.value_string()), ty) } LiteralKind::ByteString(bs) => { let text = bs.value().map_or_else(|_| Default::default(), Box::from); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index ec207a7f965..7272ed98ceb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -10,7 +10,7 @@ use hir_expand::{ AstId, }; use intern::Interned; -use syntax::ast::{self, HasName, IsString}; +use syntax::ast::{self, HasGenericArgs, HasName, IsString}; use crate::{ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, @@ -245,7 +245,13 @@ impl TypeRef { // for types are close enough for our purposes to the inner type for now... ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()), ast::Type::ImplTraitType(inner) => { - TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) + if ctx.outer_impl_trait() { + // Disallow nested impl traits + TypeRef::Error + } else { + let _guard = ctx.outer_impl_trait_scope(true); + TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) + } } ast::Type::DynTraitType(inner) => { TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 9c7dfa05b0e..d86c0667a0b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -8,7 +8,6 @@ use hir_expand::{attrs::AttrId, db::ExpandDatabase, name::Name, AstId, MacroCall use itertools::Itertools; use la_arena::Idx; use once_cell::sync::Lazy; -use profile::Count; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; use stdx::format_to; @@ -65,8 +64,6 @@ pub struct ImportId { #[derive(Debug, Default, PartialEq, Eq)] pub struct ItemScope { - _c: Count<Self>, - /// Defs visible in this scope. This includes `declarations`, but also /// imports. The imports belong to this module and can be resolved by using them on /// the `use_imports_*` fields. @@ -722,7 +719,6 @@ impl ItemScope { pub(crate) fn shrink_to_fit(&mut self) { // Exhaustive match to require handling new fields. let Self { - _c: _, types, values, macros, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index c3b7a78301d..7650dfe9f37 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -48,6 +48,7 @@ use either::Either; use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile}; use intern::Interned; use la_arena::{Arena, Idx, IdxRange, RawIdx}; +use once_cell::sync::OnceCell; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::{AstIdNode, FileAstId, SyntaxContextId}; @@ -100,6 +101,7 @@ pub struct ItemTree { impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> { let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); + static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new(); let syntax = db.parse_or_expand(file_id); @@ -131,18 +133,47 @@ impl ItemTree { if let Some(attrs) = top_attrs { item_tree.attrs.insert(AttrOwner::TopLevel, attrs); } - item_tree.shrink_to_fit(); - Arc::new(item_tree) + if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + { + EMPTY + .get_or_init(|| { + Arc::new(ItemTree { + top_level: SmallVec::new_const(), + attrs: FxHashMap::default(), + data: None, + }) + }) + .clone() + } else { + item_tree.shrink_to_fit(); + Arc::new(item_tree) + } } pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> { + let _p = tracing::info_span!("block_item_tree_query", ?block).entered(); + static EMPTY: OnceCell<Arc<ItemTree>> = OnceCell::new(); + let loc = block.lookup(db); let block = loc.ast_id.to_node(db.upcast()); let ctx = lower::Ctx::new(db, loc.ast_id.file_id); let mut item_tree = ctx.lower_block(&block); - item_tree.shrink_to_fit(); - Arc::new(item_tree) + if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty() + { + EMPTY + .get_or_init(|| { + Arc::new(ItemTree { + top_level: SmallVec::new_const(), + attrs: FxHashMap::default(), + data: None, + }) + }) + .clone() + } else { + item_tree.shrink_to_fit(); + Arc::new(item_tree) + } } /// Returns an iterator over all items located at the top level of the `HirFileId` this @@ -585,24 +616,30 @@ impl Index<RawVisibilityId> for ItemTree { type Output = RawVisibility; fn index(&self, index: RawVisibilityId) -> &Self::Output { static VIS_PUB: RawVisibility = RawVisibility::Public; - static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::SELF), - VisibilityExplicitness::Implicit, - ); - static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::SELF), - VisibilityExplicitness::Explicit, - ); - static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::Crate), - VisibilityExplicitness::Explicit, - ); + static VIS_PRIV_IMPLICIT: OnceCell<RawVisibility> = OnceCell::new(); + static VIS_PRIV_EXPLICIT: OnceCell<RawVisibility> = OnceCell::new(); + static VIS_PUB_CRATE: OnceCell<RawVisibility> = OnceCell::new(); match index { - RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT, - RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT, + RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| { + RawVisibility::Module( + Interned::new(ModPath::from_kind(PathKind::SELF)), + VisibilityExplicitness::Implicit, + ) + }), + RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| { + RawVisibility::Module( + Interned::new(ModPath::from_kind(PathKind::SELF)), + VisibilityExplicitness::Explicit, + ) + }), RawVisibilityId::PUB => &VIS_PUB, - RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE, + RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| { + RawVisibility::Module( + Interned::new(ModPath::from_kind(PathKind::Crate)), + VisibilityExplicitness::Explicit, + ) + }), _ => &self.data().vis.arena[Idx::from_raw(index.0.into())], } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 2803678a330..6283ae23b52 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -532,7 +532,7 @@ impl Printer<'_> { w!(self, "<"); let mut first = true; - for (idx, lt) in params.lifetimes.iter() { + for (idx, lt) in params.iter_lt() { if !first { w!(self, ", "); } @@ -540,7 +540,7 @@ impl Printer<'_> { self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " "); w!(self, "{}", lt.name.display(self.db.upcast())); } - for (idx, x) in params.type_or_consts.iter() { + for (idx, x) in params.iter_type_or_consts() { if !first { w!(self, ", "); } @@ -570,13 +570,13 @@ impl Printer<'_> { } fn print_where_clause(&mut self, params: &GenericParams) -> bool { - if params.where_predicates.is_empty() { + if params.where_predicates().next().is_none() { return false; } w!(self, "\nwhere"); self.indented(|this| { - for (i, pred) in params.where_predicates.iter().enumerate() { + for (i, pred) in params.where_predicates().enumerate() { if i != 0 { wln!(this, ","); } @@ -607,12 +607,10 @@ impl Printer<'_> { match target { WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), - WherePredicateTypeTarget::TypeOrConstParam(id) => { - match ¶ms.type_or_consts[*id].name() { - Some(name) => w!(this, "{}", name.display(self.db.upcast())), - None => w!(this, "_anon_{}", id.into_raw()), - } - } + WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { + Some(name) => w!(this, "{}", name.display(self.db.upcast())), + None => w!(this, "_anon_{}", id.into_raw()), + }, } w!(this, ": "); this.print_type_bounds(std::slice::from_ref(bound)); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index f6fe0c618a2..fc026a14d44 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -7,7 +7,6 @@ //! Note that `hir_def` is a work in progress, so not all of the above is //! actually true. -#![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] @@ -117,6 +116,8 @@ pub struct ImportPathConfig { pub prefer_no_std: bool, /// If true, prefer import paths containing a prelude module. pub prefer_prelude: bool, + /// If true, prefer abs path (starting with `::`) where it is available. + pub prefer_absolute: bool, } #[derive(Debug)] @@ -689,7 +690,7 @@ pub enum TypeOwnerId { } impl TypeOwnerId { - fn as_generic_def_id(self) -> Option<GenericDefId> { + fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> { Some(match self { TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it), TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it), @@ -698,7 +699,9 @@ impl TypeOwnerId { TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it), TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it), - TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), + TypeOwnerId::EnumVariantId(it) => { + GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent)) + } TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None, }) } @@ -740,7 +743,6 @@ impl From<GenericDefId> for TypeOwnerId { GenericDefId::TraitAliasId(it) => it.into(), GenericDefId::TypeAliasId(it) => it.into(), GenericDefId::ImplId(it) => it.into(), - GenericDefId::EnumVariantId(it) => it.into(), GenericDefId::ConstId(it) => it.into(), } } @@ -849,8 +851,8 @@ impl GeneralConstId { pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> { match self { GeneralConstId::ConstId(it) => Some(it.into()), - GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(), - GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(), + GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db), + GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db), } } @@ -888,12 +890,12 @@ impl From<EnumVariantId> for DefWithBodyId { } impl DefWithBodyId { - pub fn as_generic_def_id(self) -> Option<GenericDefId> { + pub fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> { match self { DefWithBodyId::FunctionId(f) => Some(f.into()), DefWithBodyId::StaticId(_) => None, DefWithBodyId::ConstId(c) => Some(c.into()), - DefWithBodyId::VariantId(c) => Some(c.into()), + DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()), // FIXME: stable rust doesn't allow generics in constants, but we should // use `TypeOwnerId::as_generic_def_id` when it does. DefWithBodyId::InTypeConstId(_) => None, @@ -921,10 +923,6 @@ pub enum GenericDefId { TraitAliasId(TraitAliasId), TypeAliasId(TypeAliasId), ImplId(ImplId), - // enum variants cannot have generics themselves, but their parent enums - // can, and this makes some code easier to write - // FIXME: Try to remove this as that will reduce the amount of query slots generated per enum? - EnumVariantId(EnumVariantId), // consts can have type parameters from their parents (i.e. associated consts of traits) ConstId(ConstId), } @@ -935,7 +933,6 @@ impl_from!( TraitAliasId, TypeAliasId, ImplId, - EnumVariantId, ConstId for GenericDefId ); @@ -967,7 +964,6 @@ impl GenericDefId { GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), - GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None), } } @@ -982,6 +978,14 @@ impl GenericDefId { _ => None, } } + + pub fn from_callable(db: &dyn DefDatabase, def: CallableDefId) -> GenericDefId { + match def { + CallableDefId::FunctionId(f) => f.into(), + CallableDefId::StructId(s) => s.into(), + CallableDefId::EnumVariantId(e) => e.lookup(db).parent.into(), + } + } } impl From<AssocItemId> for GenericDefId { @@ -995,6 +999,36 @@ impl From<AssocItemId> for GenericDefId { } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum CallableDefId { + FunctionId(FunctionId), + StructId(StructId), + EnumVariantId(EnumVariantId), +} + +impl InternValueTrivial for CallableDefId {} + +impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); +impl From<CallableDefId> for ModuleDefId { + fn from(def: CallableDefId) -> ModuleDefId { + match def { + CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f), + CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)), + CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e), + } + } +} + +impl CallableDefId { + pub fn krate(self, db: &dyn DefDatabase) -> CrateId { + match self { + CallableDefId::FunctionId(f) => f.krate(db), + CallableDefId::StructId(s) => s.krate(db), + CallableDefId::EnumVariantId(e) => e.krate(db), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum AttrDefId { ModuleId(ModuleId), FieldId(FieldId), @@ -1310,7 +1344,6 @@ impl HasModule for GenericDefId { GenericDefId::TraitAliasId(it) => it.module(db), GenericDefId::TypeAliasId(it) => it.module(db), GenericDefId::ImplId(it) => it.module(db), - GenericDefId::EnumVariantId(it) => it.module(db), GenericDefId::ConstId(it) => it.module(db), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index ecd8d79f20b..e4786a1dd40 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -18,6 +18,26 @@ pub struct LowerCtx<'a> { span_map: OnceCell<SpanMap>, ast_id_map: OnceCell<Arc<AstIdMap>>, impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>, + // Prevent nested impl traits like `impl Foo<impl Bar>`. + outer_impl_trait: RefCell<bool>, +} + +pub(crate) struct OuterImplTraitGuard<'a> { + ctx: &'a LowerCtx<'a>, + old: bool, +} + +impl<'a> OuterImplTraitGuard<'a> { + fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self { + let old = ctx.outer_impl_trait.replace(impl_trait); + Self { ctx, old } + } +} + +impl<'a> Drop for OuterImplTraitGuard<'a> { + fn drop(&mut self) { + self.ctx.outer_impl_trait.replace(self.old); + } } impl<'a> LowerCtx<'a> { @@ -28,6 +48,7 @@ impl<'a> LowerCtx<'a> { span_map: OnceCell::new(), ast_id_map: OnceCell::new(), impl_trait_bounds: RefCell::new(Vec::new()), + outer_impl_trait: RefCell::default(), } } @@ -42,6 +63,7 @@ impl<'a> LowerCtx<'a> { span_map, ast_id_map: OnceCell::new(), impl_trait_bounds: RefCell::new(Vec::new()), + outer_impl_trait: RefCell::default(), } } @@ -67,4 +89,12 @@ impl<'a> LowerCtx<'a> { pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> { self.impl_trait_bounds.take() } + + pub(crate) fn outer_impl_trait(&self) -> bool { + *self.outer_impl_trait.borrow() + } + + pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> { + OuterImplTraitGuard::new(self, impl_trait) + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs index fb5797d6e53..c365a603d2a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -36,6 +36,7 @@ macro_rules! m { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } @@ -50,6 +51,7 @@ macro_rules! m { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } @@ -58,6 +60,7 @@ fn f() { let _ = 'c'; let _ = 1000; let _ = 12E+99_f64; + let _ = 45E+1234_f128; let _ = "rust1"; let _ = -92; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 162b6429c34..8e7ef48112f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -103,12 +103,13 @@ const PREDEFINED_TOOLS: &[SmolStr] = &[ /// is computed by the `block_def_map` query. #[derive(Debug, PartialEq, Eq)] pub struct DefMap { + /// The crate this `DefMap` belongs to. + krate: CrateId, /// When this is a block def map, this will hold the block id of the block and module that /// contains this block. block: Option<BlockInfo>, /// The modules and their data declared in this crate. pub modules: Arena<ModuleData>, - krate: CrateId, /// The prelude module for this crate. This either comes from an import /// marked with the `prelude_import` attribute, or (in the normal case) from /// a dependency (`std` or `core`). @@ -124,6 +125,7 @@ pub struct DefMap { /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// attributes. + // FIXME: Figure out a better way for the IDE layer to resolve these? derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>, /// The diagnostics that need to be emitted for this crate. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 6d2eb71549e..b5045efb621 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -83,7 +83,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let name = Name::new_text_dont_use(it.name.clone()); ( name, - if it.disabled { + if !db.expand_proc_attr_macros() { + CustomProcMacroExpander::dummy() + } else if it.disabled { CustomProcMacroExpander::disabled() } else { CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new( @@ -1331,16 +1333,6 @@ impl DefCollector<'_> { let call_id = call_id(); if let MacroDefKind::ProcMacro(_, exp, _) = def.kind { - // If proc attribute macro expansion is disabled, skip expanding it here - if !self.db.expand_proc_attr_macros() { - self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( - directive.module_id, - self.db.lookup_intern_macro_call(call_id).kind, - def.krate, - )); - return recollect_without(self); - } - // If there's no expander for the proc macro (e.g. // because proc macros are disabled, or building the // proc macro crate failed), report this and skip diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs index 523a4c107b3..4ab53d20b57 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs @@ -17,16 +17,47 @@ use crate::{ #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { - UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> }, - UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, - UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> }, - UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, - UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, - UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, - UnimplementedBuiltinMacro { ast: AstId<ast::Macro> }, - InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize }, - MalformedDerive { ast: AstId<ast::Adt>, id: usize }, - MacroDefError { ast: AstId<ast::Macro>, message: String }, + UnresolvedModule { + ast: AstId<ast::Module>, + candidates: Box<[String]>, + }, + UnresolvedExternCrate { + ast: AstId<ast::ExternCrate>, + }, + UnresolvedImport { + id: ItemTreeId<item_tree::Use>, + index: Idx<ast::UseTree>, + }, + UnconfiguredCode { + ast: ErasedAstId, + cfg: CfgExpr, + opts: CfgOptions, + }, + /// A proc-macro that is lacking an expander, this might be due to build scripts not yet having + /// run or proc-macro expansion being disabled. + UnresolvedProcMacro { + ast: MacroCallKind, + krate: CrateId, + }, + UnresolvedMacroCall { + ast: MacroCallKind, + path: ModPath, + }, + UnimplementedBuiltinMacro { + ast: AstId<ast::Macro>, + }, + InvalidDeriveTarget { + ast: AstId<ast::Item>, + id: usize, + }, + MalformedDerive { + ast: AstId<ast::Adt>, + id: usize, + }, + MacroDefError { + ast: AstId<ast::Macro>, + message: String, + }, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -92,10 +123,6 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } } } - // FIXME: Whats the difference between this and unresolved_macro_call - // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc - // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this - // struct loses all that information! pub fn unresolved_proc_macro( container: LocalModuleId, ast: MacroCallKind, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 2b555b3998a..cee9e055459 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -9,7 +9,7 @@ use hir_expand::{ name::{name, AsName}, }; use intern::Interned; -use syntax::ast::{self, AstNode, HasTypeBounds}; +use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds}; use crate::{ path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind}, @@ -202,6 +202,8 @@ pub(super) fn lower_generic_args( continue; } if let Some(name_ref) = assoc_type_arg.name_ref() { + // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed + let _guard = lower_ctx.outer_impl_trait_scope(false); let name = name_ref.as_name(); let args = assoc_type_arg .generic_arg_list() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 9794963203b..e5c1f93bbde 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -596,7 +596,7 @@ impl Resolver { Scope::GenericParams { params, def } => Some((params, def)), _ => None, }) - .flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def))) + .flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def))) } pub fn generic_def(&self) -> Option<GenericDefId> { @@ -758,10 +758,10 @@ impl Scope { } Scope::GenericParams { params, def: parent } => { let parent = *parent; - for (local_id, param) in params.type_or_consts.iter() { + for (local_id, param) in params.iter_type_or_consts() { if let Some(name) = ¶m.name() { let id = TypeOrConstParamId { parent, local_id }; - let data = &db.generic_params(parent).type_or_consts[local_id]; + let data = &db.generic_params(parent)[local_id]; acc.add( name, ScopeDef::GenericParam(match data { @@ -775,7 +775,7 @@ impl Scope { ); } } - for (local_id, param) in params.lifetimes.iter() { + for (local_id, param) in params.iter_lt() { let id = LifetimeParamId { parent, local_id }; acc.add(¶m.name, ScopeDef::GenericParam(id.into())) } @@ -1164,7 +1164,6 @@ impl HasResolver for GenericDefId { GenericDefId::TraitAliasId(inner) => inner.resolver(db), GenericDefId::TypeAliasId(inner) => inner.resolver(db), GenericDefId::ImplId(inner) => inner.resolver(db), - GenericDefId::EnumVariantId(inner) => inner.resolver(db), GenericDefId::ConstId(inner) => inner.resolver(db), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index 2b1da8c34e1..a0d2079e0d4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -64,7 +64,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId { db: &dyn DefDatabase, ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> { let generic_params = db.generic_params(*self); - let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx); + let mut idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); @@ -103,7 +103,7 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId { db: &dyn DefDatabase, ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> { let generic_params = db.generic_params(*self); - let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx); + let idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); let (file_id, generic_params_list) = self.file_id_and_params_of(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index e08718fc836..11d91513f12 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -2,6 +2,7 @@ use std::iter; +use intern::Interned; use la_arena::ArenaMap; use span::SyntaxContextId; use syntax::ast; @@ -20,14 +21,17 @@ use crate::{ pub enum RawVisibility { /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is /// equivalent to `pub(self)`. - Module(ModPath, VisibilityExplicitness), + Module(Interned<ModPath>, VisibilityExplicitness), /// `pub`. Public, } impl RawVisibility { - pub(crate) const fn private() -> RawVisibility { - RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit) + pub(crate) fn private() -> RawVisibility { + RawVisibility::Module( + Interned::new(ModPath::from_kind(PathKind::SELF)), + VisibilityExplicitness::Implicit, + ) } pub(crate) fn from_ast( @@ -60,7 +64,7 @@ impl RawVisibility { ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF), ast::VisibilityKind::Pub => return RawVisibility::Public, }; - RawVisibility::Module(path, VisibilityExplicitness::Explicit) + RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit) } pub fn resolve( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index 1a3dd0e7ddb..08491db3726 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -25,7 +25,8 @@ impl ChangeWithProcMacros { pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) { self.source_change.apply(db); - if let Some(proc_macros) = self.proc_macros { + if let Some(mut proc_macros) = self.proc_macros { + proc_macros.shrink_to_fit(); db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH); } if let Some(target_data_layouts) = self.target_data_layouts { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 7c3bf995b12..29408902f16 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -172,15 +172,30 @@ impl DeclarativeMacroExpander { ), ast::Macro::MacroDef(macro_def) => ( match macro_def.body() { - Some(arg) => { - let tt = mbe::syntax_node_to_token_tree( - arg.syntax(), + Some(body) => { + let span = + map.span_for_range(macro_def.macro_token().unwrap().text_range()); + let args = macro_def.args().map(|args| { + mbe::syntax_node_to_token_tree( + args.syntax(), + map.as_ref(), + span, + DocCommentDesugarMode::Mbe, + ) + }); + let body = mbe::syntax_node_to_token_tree( + body.syntax(), map.as_ref(), - map.span_for_range(macro_def.macro_token().unwrap().text_range()), + span, DocCommentDesugarMode::Mbe, ); - mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars) + mbe::DeclarativeMacro::parse_macro2( + args.as_ref(), + &body, + edition, + new_meta_vars, + ) } None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected( "expected a token tree".into(), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 743fac50f4e..fc9fa93268e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -1,4 +1,6 @@ //! Things to wrap other things in file ids. +use std::borrow::Borrow; + use either::Either; use span::{ AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr, @@ -76,6 +78,13 @@ impl<FileKind: Copy, T> InFileWrapper<FileKind, T> { pub fn as_ref(&self) -> InFileWrapper<FileKind, &T> { self.with_value(&self.value) } + + pub fn borrow<U>(&self) -> InFileWrapper<FileKind, &U> + where + T: Borrow<U>, + { + self.with_value(self.value.borrow()) + } } impl<FileKind: Copy, T: Clone> InFileWrapper<FileKind, &T> { @@ -156,14 +165,61 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> { } // region:specific impls +impl<SN: Borrow<SyntaxNode>> InRealFile<SN> { + pub fn file_range(&self) -> FileRange { + FileRange { file_id: self.file_id, range: self.value.borrow().text_range() } + } +} + +impl<SN: Borrow<SyntaxNode>> InFile<SN> { + pub fn parent_ancestors_with_macros( + self, + db: &dyn db::ExpandDatabase, + ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ { + let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() { + Some(parent) => Some(node.with_value(parent)), + None => db + .lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id) + .to_node_item(db) + .syntax() + .cloned() + .map(|node| node.parent()) + .transpose(), + }; + std::iter::successors(succ(&self.borrow().cloned()), succ) + } + + pub fn ancestors_with_macros( + self, + db: &dyn db::ExpandDatabase, + ) -> impl Iterator<Item = InFile<SyntaxNode>> + '_ { + let succ = move |node: &InFile<SyntaxNode>| match node.value.parent() { + Some(parent) => Some(node.with_value(parent)), + None => db + .lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id) + .to_node_item(db) + .syntax() + .cloned() + .map(|node| node.parent()) + .transpose(), + }; + std::iter::successors(Some(self.borrow().cloned()), succ) + } + + pub fn kind(&self) -> parser::SyntaxKind { + self.value.borrow().kind() + } + + pub fn text_range(&self) -> TextRange { + self.value.borrow().text_range() + } -impl InFile<&SyntaxNode> { /// Falls back to the macro call range if the node cannot be mapped up fully. /// /// For attributes and derives, this will point back to the attribute only. /// For the entire item use [`InFile::original_file_range_full`]. pub fn original_file_range_rooted(self, db: &dyn db::ExpandDatabase) -> FileRange { - self.map(SyntaxNode::text_range).original_node_file_range_rooted(db) + self.borrow().map(SyntaxNode::text_range).original_node_file_range_rooted(db) } /// Falls back to the macro call range if the node cannot be mapped up fully. @@ -171,15 +227,7 @@ impl InFile<&SyntaxNode> { self, db: &dyn db::ExpandDatabase, ) -> FileRange { - self.map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db) - } - - /// Attempts to map the syntax node back up its macro calls. - pub fn original_file_range_opt( - self, - db: &dyn db::ExpandDatabase, - ) -> Option<(FileRange, SyntaxContextId)> { - self.map(SyntaxNode::text_range).original_node_file_range_opt(db) + self.borrow().map(SyntaxNode::text_range).original_node_file_range_with_macro_call_body(db) } pub fn original_syntax_node_rooted( @@ -190,16 +238,19 @@ impl InFile<&SyntaxNode> { // as we don't have node inputs otherwise and therefore can't find an `N` node in the input let file_id = match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => { - return Some(InRealFile { file_id, value: self.value.clone() }) + return Some(InRealFile { file_id, value: self.value.borrow().clone() }) } HirFileIdRepr::MacroFile(m) if m.is_attr_macro(db) => m, _ => return None, }; - let FileRange { file_id, range } = - map_node_range_up_rooted(db, &db.expansion_span_map(file_id), self.value.text_range())?; + let FileRange { file_id, range } = map_node_range_up_rooted( + db, + &db.expansion_span_map(file_id), + self.value.borrow().text_range(), + )?; - let kind = self.value.kind(); + let kind = self.kind(); let value = db .parse(file_id) .syntax_node() @@ -211,6 +262,16 @@ impl InFile<&SyntaxNode> { } } +impl InFile<&SyntaxNode> { + /// Attempts to map the syntax node back up its macro calls. + pub fn original_file_range_opt( + self, + db: &dyn db::ExpandDatabase, + ) -> Option<(FileRange, SyntaxContextId)> { + self.borrow().map(SyntaxNode::text_range).original_node_file_range_opt(db) + } +} + impl InMacroFile<SyntaxToken> { pub fn upmap_once( self, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index a7150cf3087..e7c34e51e85 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -4,7 +4,6 @@ //! tree originates not from the text of some `FileId`, but from some macro //! expansion. #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#![warn(rust_2018_idioms, unused_lifetimes)] pub mod attrs; pub mod builtin_attr_macro; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 8f74bffc2b9..fe754bc8249 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -275,8 +275,10 @@ pub mod known { u32, u64, u128, + f16, f32, f64, + f128, bool, char, str, diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index a83ee9824e2..b6c33683ff6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -33,6 +33,7 @@ triomphe.workspace = true nohash-hasher.workspace = true typed-arena = "2.0.1" indexmap.workspace = true +rustc_apfloat = "0.2.0" ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 52411f94ad0..76d9c60f6f9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -63,7 +63,14 @@ impl<D> TyBuilder<D> { } fn build_internal(self) -> (D, Substitution) { - assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds); + assert_eq!( + self.vec.len(), + self.param_kinds.len(), + "{} args received, {} expected ({:?})", + self.vec.len(), + self.param_kinds.len(), + &self.param_kinds + ); for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) { self.assert_match_kind(a, e); } @@ -252,8 +259,9 @@ impl TyBuilder<()> { /// This method prepopulates the builder with placeholder substitution of `parent`, so you /// should only push exactly 3 `GenericArg`s before building. pub fn subst_for_coroutine(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> { - let parent_subst = - parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db)); + let parent_subst = parent + .as_generic_def_id(db.upcast()) + .map(|p| generics(db.upcast(), p).placeholder_subst(db)); // These represent resume type, yield type, and return type of coroutine. let params = std::iter::repeat(ParamKind::Type).take(3).collect(); TyBuilder::new((), params, parent_subst) @@ -266,7 +274,7 @@ impl TyBuilder<()> { ) -> Substitution { let sig_ty = sig_ty.cast(Interner); let self_subst = iter::once(&sig_ty); - let Some(parent) = parent.as_generic_def_id() else { + let Some(parent) = parent.as_generic_def_id(db.upcast()) else { return Substitution::from_iter(Interner, self_subst); }; Substitution::from_iter( @@ -296,7 +304,8 @@ impl TyBuilder<hir_def::AdtId> { ) -> Self { // Note that we're building ADT, so we never have parent generic parameters. let defaults = db.generic_defaults(self.data.into()); - for default_ty in defaults.iter().skip(self.vec.len()) { + + for default_ty in &defaults[self.vec.len()..] { // NOTE(skip_binders): we only check if the arg type is error type. if let Some(x) = default_ty.skip_binders().ty(Interner) { if x.is_unknown() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index debae1fe123..3ac8cbaaf8b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -13,7 +13,8 @@ use hir_def::{ data::adt::StructFlags, hir::Movability, lang_item::{LangItem, LangItemTarget}, - AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId, + AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, + TypeAliasId, VariantId, }; use hir_expand::name::name; @@ -28,9 +29,9 @@ use crate::{ to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, utils::ClosureSubst, - wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, - Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, - TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, + wrap_empty_binders, AliasEq, AliasTy, BoundVar, DebruijnIndex, FnDefId, Interner, ProjectionTy, + ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, + TyExt, TyKind, WhereClause, }; pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; @@ -102,7 +103,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { &self, fn_def_id: chalk_ir::FnDefId<Interner>, ) -> Arc<rust_ir::FnDefDatum<Interner>> { - self.db.fn_def_datum(self.krate, fn_def_id) + self.db.fn_def_datum(fn_def_id) } fn impls_for_trait( @@ -912,16 +913,13 @@ fn type_alias_associated_ty_value( Arc::new(value) } -pub(crate) fn fn_def_datum_query( - db: &dyn HirDatabase, - _krate: CrateId, - fn_def_id: FnDefId, -) -> Arc<FnDefDatum> { +pub(crate) fn fn_def_datum_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Arc<FnDefDatum> { let callable_def: CallableDefId = from_chalk(db, fn_def_id); - let generic_params = generics(db.upcast(), callable_def.into()); + let generic_def = GenericDefId::from_callable(db.upcast(), callable_def); + let generic_params = generics(db.upcast(), generic_def); let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders(); let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); + let where_clauses = convert_where_clauses(db, generic_def, &bound_vars); let bound = rust_ir::FnDefDatumBound { // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway inputs_and_output: chalk_ir::Binders::empty( @@ -948,7 +946,8 @@ pub(crate) fn fn_def_datum_query( pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances { let callable_def: CallableDefId = from_chalk(db, fn_def_id); - let generic_params = generics(db.upcast(), callable_def.into()); + let generic_params = + generics(db.upcast(), GenericDefId::from_callable(db.upcast(), callable_def)); Variances::from_iter( Interner, std::iter::repeat(chalk_ir::Variance::Invariant).take(generic_params.len()), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 4279c756519..5765262b08b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -119,8 +119,10 @@ impl TyExt for Ty { TyKind::Scalar(Scalar::Bool) => Some(BuiltinType::Bool), TyKind::Scalar(Scalar::Char) => Some(BuiltinType::Char), TyKind::Scalar(Scalar::Float(fty)) => Some(BuiltinType::Float(match fty { + FloatTy::F128 => BuiltinFloat::F128, FloatTy::F64 => BuiltinFloat::F64, FloatTy::F32 => BuiltinFloat::F32, + FloatTy::F16 => BuiltinFloat::F16, })), TyKind::Scalar(Scalar::Int(ity)) => Some(BuiltinType::Int(match ity { IntTy::Isize => BuiltinInt::Isize, @@ -188,9 +190,10 @@ impl TyExt for Ty { fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { match *self.kind(Interner) { TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), - TyKind::FnDef(callable, ..) => { - Some(db.lookup_intern_callable_def(callable.into()).into()) - } + TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable( + db.upcast(), + db.lookup_intern_callable_def(callable.into()), + )), TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()), TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()), _ => None, @@ -308,7 +311,7 @@ impl TyExt for Ty { TyKind::Placeholder(idx) => { let id = from_placeholder_idx(db, *idx); let generic_params = db.generic_params(id.parent); - let param_data = &generic_params.type_or_consts[id.local_id]; + let param_data = &generic_params[id.local_id]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 1b4584a18d7..095f2eb6c9f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -1,6 +1,10 @@ use base_db::FileId; use chalk_ir::Substitution; use hir_def::db::DefDatabase; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use test_fixture::WithFixture; use test_utils::skip_slow_tests; @@ -141,6 +145,14 @@ fn bit_op() { #[test] fn floating_point() { check_number( + r#"const GOAL: f128 = 2.0 + 3.0 * 5.5 - 8.;"#, + "10.5".parse::<f128>().unwrap().to_bits() as i128, + ); + check_number( + r#"const GOAL: f128 = -90.0 + 36.0;"#, + "-54.0".parse::<f128>().unwrap().to_bits() as i128, + ); + check_number( r#"const GOAL: f64 = 2.0 + 3.0 * 5.5 - 8.;"#, i128::from_le_bytes(pad16(&f64::to_le_bytes(10.5), true)), ); @@ -152,6 +164,20 @@ fn floating_point() { r#"const GOAL: f32 = -90.0 + 36.0;"#, i128::from_le_bytes(pad16(&f32::to_le_bytes(-54.0), true)), ); + check_number( + r#"const GOAL: f16 = 2.0 + 3.0 * 5.5 - 8.;"#, + i128::from_le_bytes(pad16( + &u16::try_from("10.5".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(), + true, + )), + ); + check_number( + r#"const GOAL: f16 = -90.0 + 36.0;"#, + i128::from_le_bytes(pad16( + &u16::try_from("-54.0".parse::<f16>().unwrap().to_bits()).unwrap().to_le_bytes(), + true, + )), + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index 44a4ac27af0..5972b80d169 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -411,6 +411,7 @@ fn likely() { #[test] fn floating_point() { + // FIXME(#17451): Add `f16` and `f128` tests once intrinsics are added. check_number( r#" extern "rust-intrinsic" { @@ -426,6 +427,7 @@ fn floating_point() { true, )), ); + #[allow(unknown_lints, clippy::unnecessary_min_or_max)] check_number( r#" extern "rust-intrinsic" { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index e951048021d..734aad49458 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -9,8 +9,8 @@ use base_db::{ CrateId, Upcast, }; use hir_def::{ - db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId, - DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, + db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, CallableDefId, + ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TypeAliasId, TypeOrConstParamId, VariantId, }; use la_arena::ArenaMap; @@ -24,9 +24,8 @@ use crate::{ lower::{GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, - Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty, - TyDefId, ValueTyDefId, + Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, + PolyFnSig, Substitution, TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, }; use hir_expand::name::Name; @@ -81,8 +80,32 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[salsa::cycle(crate::consteval::const_eval_discriminant_recover)] fn const_eval_discriminant(&self, def: EnumVariantId) -> Result<i128, ConstEvalError>; + #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] + fn lookup_impl_method( + &self, + env: Arc<TraitEnvironment>, + func: FunctionId, + fn_subst: Substitution, + ) -> (FunctionId, Substitution); + // endregion:mir + #[salsa::invoke(crate::layout::layout_of_adt_query)] + #[salsa::cycle(crate::layout::layout_of_adt_recover)] + fn layout_of_adt( + &self, + def: AdtId, + subst: Substitution, + env: Arc<TraitEnvironment>, + ) -> Result<Arc<Layout>, LayoutError>; + + #[salsa::invoke(crate::layout::layout_of_ty_query)] + #[salsa::cycle(crate::layout::layout_of_ty_recover)] + fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>; + + #[salsa::invoke(crate::layout::target_data_layout_query)] + fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>; + #[salsa::invoke(crate::lower::ty_query)] #[salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders<Ty>; @@ -105,30 +128,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[salsa::invoke(crate::lower::field_types_query)] fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; - #[salsa::invoke(crate::layout::layout_of_adt_query)] - #[salsa::cycle(crate::layout::layout_of_adt_recover)] - fn layout_of_adt( - &self, - def: AdtId, - subst: Substitution, - env: Arc<TraitEnvironment>, - ) -> Result<Arc<Layout>, LayoutError>; - - #[salsa::invoke(crate::layout::layout_of_ty_query)] - #[salsa::cycle(crate::layout::layout_of_ty_recover)] - fn layout_of_ty(&self, ty: Ty, env: Arc<TraitEnvironment>) -> Result<Arc<Layout>, LayoutError>; - - #[salsa::invoke(crate::layout::target_data_layout_query)] - fn target_data_layout(&self, krate: CrateId) -> Result<Arc<TargetDataLayout>, Arc<str>>; - - #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] - fn lookup_impl_method( - &self, - env: Arc<TraitEnvironment>, - func: FunctionId, - fn_subst: Substitution, - ) -> (FunctionId, Substitution); - #[salsa::invoke(crate::lower::callable_item_sig)] fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; @@ -145,7 +144,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { def: GenericDefId, param_id: TypeOrConstParamId, assoc_name: Option<Name>, - ) -> Arc<[Binders<QuantifiedWhereClause>]>; + ) -> GenericPredicates; #[salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; @@ -232,7 +231,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { ) -> sync::Arc<chalk_db::ImplDatum>; #[salsa::invoke(chalk_db::fn_def_datum_query)] - fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>; + fn fn_def_datum(&self, fn_def_id: FnDefId) -> sync::Arc<chalk_db::FnDefDatum>; #[salsa::invoke(chalk_db::fn_def_variance_query)] fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index ce3fa53f7ad..c28ab2e98af 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -196,6 +196,9 @@ impl ExprValidator { let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else { return; }; + if pat_ty.contains_unknown() { + return; + } // We only include patterns whose type matches the type // of the scrutinee expression. If we had an InvalidMatchArmPattern diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index 8d6e502c6ab..8dcc14feb27 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -51,6 +51,7 @@ pub(crate) struct Pat { #[derive(Clone, Debug, PartialEq)] pub(crate) enum PatKind { Wild, + Never, /// `x`, `ref x`, `x @ P`, etc. Binding { @@ -294,6 +295,7 @@ impl HirDisplay for Pat { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match &*self.kind { PatKind::Wild => write!(f, "_"), + PatKind::Never => write!(f, "!"), PatKind::Binding { name, subpattern } => { write!(f, "{}", name.display(f.db.upcast()))?; if let Some(subpattern) = subpattern { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index c171dbc1700..bf2ff1a917c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -4,12 +4,10 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use once_cell::unsync::Lazy; -use rustc_hash::FxHashMap; use rustc_pattern_analysis::{ constructor::{Constructor, ConstructorSet, VariantVisibility}, - index::IdxContainer, usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport}, - Captures, PatCx, PrivateUninhabitedField, + Captures, IndexVec, PatCx, PrivateUninhabitedField, }; use smallvec::{smallvec, SmallVec}; use stdx::never; @@ -26,10 +24,10 @@ use super::{is_box, FieldPat, Pat, PatKind}; use Constructor::*; // Re-export r-a-specific versions of all these types. -pub(crate) type DeconstructedPat<'p> = - rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'p>>; -pub(crate) type MatchArm<'p> = rustc_pattern_analysis::MatchArm<'p, MatchCheckCtx<'p>>; -pub(crate) type WitnessPat<'p> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'p>>; +pub(crate) type DeconstructedPat<'db> = + rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'db>>; +pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>; +pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'db>>; /// [Constructor] uses this in unimplemented variants. /// It allows porting match expressions from upstream algorithm without losing semantics. @@ -54,23 +52,27 @@ impl EnumVariantContiguousIndex { } } +impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex { + fn new(idx: usize) -> Self { + EnumVariantContiguousIndex(idx) + } + + fn index(self) -> usize { + self.0 + } +} + #[derive(Clone)] -pub(crate) struct MatchCheckCtx<'p> { +pub(crate) struct MatchCheckCtx<'db> { module: ModuleId, body: DefWithBodyId, - pub(crate) db: &'p dyn HirDatabase, + pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, min_exhaustive_patterns: bool, } -#[derive(Clone)] -pub(crate) struct PatData<'p> { - /// Keep db around so that we can print variant names in `Debug`. - pub(crate) db: &'p dyn HirDatabase, -} - -impl<'p> MatchCheckCtx<'p> { - pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'p dyn HirDatabase) -> Self { +impl<'db> MatchCheckCtx<'db> { + pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self { let def_map = db.crate_def_map(module.krate()); let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns"); let min_exhaustive_patterns = @@ -80,9 +82,9 @@ impl<'p> MatchCheckCtx<'p> { pub(crate) fn compute_match_usefulness( &self, - arms: &[MatchArm<'p>], + arms: &[MatchArm<'db>], scrut_ty: Ty, - ) -> Result<UsefulnessReport<'p, Self>, ()> { + ) -> Result<UsefulnessReport<'db, Self>, ()> { // FIXME: Determine place validity correctly. For now, err on the safe side. let place_validity = PlaceValidity::MaybeInvalid; // Measured to take ~100ms on modern hardware. @@ -101,7 +103,7 @@ impl<'p> MatchCheckCtx<'p> { } fn variant_id_for_adt( - db: &'p dyn HirDatabase, + db: &'db dyn HirDatabase, ctor: &Constructor<Self>, adt: hir_def::AdtId, ) -> Option<VariantId> { @@ -126,7 +128,7 @@ impl<'p> MatchCheckCtx<'p> { &'a self, ty: &'a Ty, variant: VariantId, - ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'p> { + ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> { let (_, substs) = ty.as_adt().unwrap(); let field_tys = self.db.field_types(variant); @@ -139,8 +141,8 @@ impl<'p> MatchCheckCtx<'p> { }) } - pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> { - let singleton = |pat: DeconstructedPat<'p>| vec![pat.at_index(0)]; + pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> { + let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)]; let ctor; let mut fields: Vec<_>; let arity; @@ -228,6 +230,11 @@ impl<'p> MatchCheckCtx<'p> { fields = Vec::new(); arity = 0; } + PatKind::Never => { + ctor = Never; + fields = Vec::new(); + arity = 0; + } PatKind::Or { pats } => { ctor = Or; fields = pats @@ -238,11 +245,10 @@ impl<'p> MatchCheckCtx<'p> { arity = pats.len(); } } - let data = PatData { db: self.db }; - DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), data) + DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ()) } - pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'p>) -> Pat { + pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat { let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p)); let kind = match pat.ctor() { &Bool(value) => PatKind::LiteralBool { value }, @@ -290,6 +296,7 @@ impl<'p> MatchCheckCtx<'p> { Slice(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, + Never => PatKind::Never, Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => { never!("can't convert to pattern: {:?}", pat.ctor()); PatKind::Wild @@ -299,13 +306,13 @@ impl<'p> MatchCheckCtx<'p> { } } -impl<'p> PatCx for MatchCheckCtx<'p> { +impl<'db> PatCx for MatchCheckCtx<'db> { type Error = (); type Ty = Ty; type VariantIdx = EnumVariantContiguousIndex; type StrLit = Void; type ArmData = (); - type PatData = PatData<'p>; + type PatData = (); fn is_exhaustive_patterns_feature_on(&self) -> bool { self.exhaustive_patterns @@ -339,8 +346,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> { }, Ref => 1, Slice(..) => unimplemented!(), - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, + Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) + | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, Or => { never!("The `Or` constructor doesn't have a fixed arity"); 0 @@ -402,8 +409,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> { } }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => smallvec![], + Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) + | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => { + smallvec![] + } Or => { never!("called `Fields::wildcards` on an `Or` ctor"); smallvec![] @@ -442,11 +451,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> { if enum_data.variants.is_empty() && !is_declared_nonexhaustive { ConstructorSet::NoConstructors } else { - let mut variants = FxHashMap::with_capacity_and_hasher( - enum_data.variants.len(), - Default::default(), - ); - for (i, &(variant, _)) in enum_data.variants.iter().enumerate() { + let mut variants = IndexVec::with_capacity(enum_data.variants.len()); + for &(variant, _) in enum_data.variants.iter() { let is_uninhabited = is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module); let visibility = if is_uninhabited { @@ -454,13 +460,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> { } else { VariantVisibility::Visible }; - variants.insert(EnumVariantContiguousIndex(i), visibility); + variants.push(visibility); } - ConstructorSet::Variants { - variants: IdxContainer(variants), - non_exhaustive: is_declared_nonexhaustive, - } + ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive } } } TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union, @@ -476,26 +479,27 @@ impl<'p> PatCx for MatchCheckCtx<'p> { fn write_variant_name( f: &mut fmt::Formatter<'_>, - pat: &rustc_pattern_analysis::pat::DeconstructedPat<Self>, + _ctor: &Constructor<Self>, + _ty: &Self::Ty, ) -> fmt::Result { - let db = pat.data().db; - let variant = - pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, pat.ctor(), adt)); - - if let Some(variant) = variant { - match variant { - VariantId::EnumVariantId(v) => { - write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?; - } - VariantId::StructId(s) => { - write!(f, "{}", db.struct_data(s).name.display(db.upcast()))? - } - VariantId::UnionId(u) => { - write!(f, "{}", db.union_data(u).name.display(db.upcast()))? - } - } - } - Ok(()) + write!(f, "<write_variant_name unsupported>") + // We lack the database here ... + // let variant = ty.as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, ctor, adt)); + + // if let Some(variant) = variant { + // match variant { + // VariantId::EnumVariantId(v) => { + // write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?; + // } + // VariantId::StructId(s) => { + // write!(f, "{}", db.struct_data(s).name.display(db.upcast()))? + // } + // VariantId::UnionId(u) => { + // write!(f, "{}", db.union_data(u).name.display(db.upcast()))? + // } + // } + // } + // Ok(()) } fn bug(&self, fmt: fmt::Arguments<'_>) { @@ -507,7 +511,7 @@ impl<'p> PatCx for MatchCheckCtx<'p> { } } -impl<'p> fmt::Debug for MatchCheckCtx<'p> { +impl<'db> fmt::Debug for MatchCheckCtx<'db> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MatchCheckCtx").finish() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 66b5398b88e..a9a5d829f5f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -21,13 +21,17 @@ use hir_def::{ path::{Path, PathKind}, type_ref::{TraitBoundModifier, TypeBound, TypeRef}, visibility::Visibility, - HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, - TraitId, + GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId, + ModuleId, TraitId, }; use hir_expand::name::Name; use intern::{Internable, Interned}; use itertools::Itertools; use la_arena::ArenaMap; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use smallvec::SmallVec; use stdx::{never, IsNoneOr}; use triomphe::Arc; @@ -545,6 +549,17 @@ fn render_const_scalar( write!(f, "{it}") } Scalar::Float(fl) => match fl { + chalk_ir::FloatTy::F16 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f16::from_bits(u16::from_le_bytes(b.try_into().unwrap()).into()); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") + } + } chalk_ir::FloatTy::F32 => { let it = f32::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") @@ -553,6 +568,17 @@ fn render_const_scalar( let it = f64::from_le_bytes(b.try_into().unwrap()); write!(f, "{it:?}") } + chalk_ir::FloatTy::F128 => { + // FIXME(#17451): Replace with builtins once they are stabilised. + let it = f128::from_bits(u128::from_le_bytes(b.try_into().unwrap())); + let s = it.to_string(); + if s.strip_prefix('-').unwrap_or(&s).chars().all(|c| c.is_ascii_digit()) { + // Match Rust debug formatting + write!(f, "{s}.0") + } else { + write!(f, "{s}") + } + } }, }, TyKind::Ref(_, _, t) => match t.kind(Interner) { @@ -988,7 +1014,8 @@ impl HirDisplay for Ty { f.end_location_link(); if parameters.len(Interner) > 0 { - let generics = generics(db.upcast(), def.into()); + let generic_def_id = GenericDefId::from_callable(db.upcast(), def); + let generics = generics(db.upcast(), generic_def_id); let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); let parameters = parameters.as_slice(Interner); @@ -1002,8 +1029,9 @@ impl HirDisplay for Ty { debug_assert_eq!(parent_params.len(), parent_len); let parent_params = - generic_args_sans_defaults(f, Some(def.into()), parent_params); - let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params); + generic_args_sans_defaults(f, Some(generic_def_id), parent_params); + let fn_params = + generic_args_sans_defaults(f, Some(generic_def_id), fn_params); write!(f, "<")?; hir_fmt_generic_arguments(f, parent_params, None)?; @@ -1041,7 +1069,11 @@ impl HirDisplay for Ty { module_id, PrefixKind::Plain, false, - ImportPathConfig { prefer_no_std: false, prefer_prelude: true }, + ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }, ) { write!(f, "{}", path.display(f.db.upcast()))?; } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index ea10e6881e7..a96c101a388 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -2,8 +2,8 @@ //! //! The layout for generics as expected by chalk are as follows: //! - Optional Self parameter -//! - Type or Const parameters //! - Lifetime parameters +//! - Type or Const parameters //! - Parent parameters //! //! where parent follows the same scheme. @@ -20,18 +20,23 @@ use hir_def::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; use intern::Interned; +use itertools::chain; +use stdx::TupleExt; use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - Generics { def, params: db.generic_params(def), parent_generics } + let params = db.generic_params(def); + let has_trait_self_param = params.trait_self_param().is_some(); + Generics { def, params, parent_generics, has_trait_self_param } } #[derive(Clone, Debug)] pub(crate) struct Generics { def: GenericDefId, params: Interned<GenericParams>, parent_generics: Option<Box<Generics>>, + has_trait_self_param: bool, } impl<T> ops::Index<T> for Generics @@ -57,7 +62,7 @@ impl Generics { self.iter_self().map(|(id, _)| id) } - fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { + pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { self.iter_parent().map(|(id, _)| id) } @@ -67,6 +72,12 @@ impl Generics { self.params.iter_type_or_consts() } + pub(crate) fn iter_self_type_or_consts_id( + &self, + ) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ { + self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head) + } + /// Iterate over the params followed by the parent params. pub(crate) fn iter( &self, @@ -78,10 +89,9 @@ impl Generics { pub(crate) fn iter_self( &self, ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(self.params.iter_lt().map(from_lt_id(self))) + let mut toc = self.params.iter_type_or_consts().map(from_toc_id(self)); + let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten(); + chain!(trait_self_param, self.params.iter_lt().map(from_lt_id(self)), toc) } /// Iterator over types and const params of parent. @@ -89,8 +99,9 @@ impl Generics { &self, ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ { self.parent_generics().into_iter().flat_map(|it| { - let lt_iter = it.params.iter_lt().map(from_lt_id(it)); - it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter) + let mut toc = it.params.iter_type_or_consts().map(from_toc_id(it)); + let trait_self_param = it.has_trait_self_param.then(|| toc.next()).flatten(); + chain!(trait_self_param, it.params.iter_lt().map(from_lt_id(it)), toc) }) } @@ -134,8 +145,11 @@ impl Generics { fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option<usize> { if param.parent == self.def { let idx = param.local_id.into_raw().into_u32() as usize; - debug_assert!(idx <= self.params.type_or_consts.len()); - Some(idx) + debug_assert!(idx <= self.params.len_type_or_consts()); + if self.params.trait_self_param() == Some(param.local_id) { + return Some(idx); + } + Some(self.params.len_lifetimes() + idx) } else { debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); self.parent_generics() @@ -152,8 +166,8 @@ impl Generics { fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<usize> { if lifetime.parent == self.def { let idx = lifetime.local_id.into_raw().into_u32() as usize; - debug_assert!(idx <= self.params.lifetimes.len()); - Some(self.params.type_or_consts.len() + idx) + debug_assert!(idx <= self.params.len_lifetimes()); + Some(self.params.trait_self_param().is_some() as usize + idx) } else { debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); self.parent_generics() @@ -216,7 +230,6 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic GenericDefId::FunctionId(it) => it.lookup(db).container, GenericDefId::TypeAliasId(it) => it.lookup(db).container, GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 96431ba4ce9..66ee02d74d9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -701,18 +701,23 @@ impl<'a> InferenceContext<'a> { table.propagate_diverging_flag(); for ty in type_of_expr.values_mut() { *ty = table.resolve_completely(ty.clone()); + *has_errors = *has_errors || ty.contains_unknown(); } for ty in type_of_pat.values_mut() { *ty = table.resolve_completely(ty.clone()); + *has_errors = *has_errors || ty.contains_unknown(); } for ty in type_of_binding.values_mut() { *ty = table.resolve_completely(ty.clone()); + *has_errors = *has_errors || ty.contains_unknown(); } for ty in type_of_rpit.values_mut() { *ty = table.resolve_completely(ty.clone()); + *has_errors = *has_errors || ty.contains_unknown(); } for ty in type_of_for_iterator.values_mut() { *ty = table.resolve_completely(ty.clone()); + *has_errors = *has_errors || ty.contains_unknown(); } *has_errors = !type_mismatches.is_empty(); @@ -835,11 +840,7 @@ impl<'a> InferenceContext<'a> { let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { // RPIT opaque types use substitution of their parent function. let fn_placeholders = TyBuilder::placeholder_subst(self.db, func); - let result = self.insert_inference_vars_for_impl_trait( - return_ty, - rpits.clone(), - fn_placeholders, - ); + let result = self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders); let rpits = rpits.skip_binders(); for (id, _) in rpits.impl_traits.iter() { if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) { @@ -862,12 +863,7 @@ impl<'a> InferenceContext<'a> { self.insert_atpit_coercion_table(params_and_ret_tys.iter()); } - fn insert_inference_vars_for_impl_trait<T>( - &mut self, - t: T, - rpits: Arc<chalk_ir::Binders<crate::ImplTraits>>, - placeholders: Substitution, - ) -> T + fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T where T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>, { @@ -878,13 +874,21 @@ impl<'a> InferenceContext<'a> { TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id, _ => return ty, }; - let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { - ImplTraitId::ReturnTypeImplTrait(_, idx) => idx, - ImplTraitId::AssociatedTypeImplTrait(_, idx) => idx, - _ => unreachable!(), + let (impl_traits, idx) = + match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { + ImplTraitId::ReturnTypeImplTrait(def, idx) => { + (self.db.return_type_impl_traits(def), idx) + } + ImplTraitId::AssociatedTypeImplTrait(def, idx) => { + (self.db.type_alias_impl_traits(def), idx) + } + _ => unreachable!(), + }; + let Some(impl_traits) = impl_traits else { + return ty; }; - let bounds = - (*rpits).map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter())); + let bounds = (*impl_traits) + .map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter())); let var = self.table.new_type_var(); let var_subst = Substitution::from1(Interner, var.clone()); for bound in bounds { @@ -892,11 +896,8 @@ impl<'a> InferenceContext<'a> { let (var_predicate, binders) = predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders(); always!(binders.is_empty(Interner)); // quantified where clauses not yet handled - let var_predicate = self.insert_inference_vars_for_impl_trait( - var_predicate, - rpits.clone(), - placeholders.clone(), - ); + let var_predicate = self + .insert_inference_vars_for_impl_trait(var_predicate, placeholders.clone()); self.push_obligation(var_predicate.cast(Interner)); } self.result.type_of_rpit.insert(idx, var.clone()); @@ -983,16 +984,8 @@ impl<'a> InferenceContext<'a> { self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) { if assoc_tys.contains(&alias_id) { - let atpits = self - .db - .type_alias_impl_traits(alias_id) - .expect("Marked as ATPIT but no impl traits!"); let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id); - let ty = self.insert_inference_vars_for_impl_trait( - ty, - atpits, - alias_placeholders, - ); + let ty = self.insert_inference_vars_for_impl_trait(ty, alias_placeholders); return Some((opaque_ty_id, ty)); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 95f28531acf..7a0f7872a64 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -13,7 +13,7 @@ use hir_def::{ }, lang_item::{LangItem, LangItemTarget}, path::{GenericArgs, Path}, - BlockId, FieldId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, + BlockId, FieldId, GenericDefId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId, }; use hir_expand::name::{name, Name}; use stdx::always; @@ -440,7 +440,8 @@ impl InferenceContext<'_> { let ty = match self.infer_path(p, tgt_expr.into()) { Some(ty) => ty, None => { - if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident()) { + if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self()) + { self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { expr: tgt_expr, }); @@ -1895,7 +1896,8 @@ impl InferenceContext<'_> { let callable_ty = self.resolve_ty_shallow(callable_ty); if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(Interner) { let def: CallableDefId = from_chalk(self.db, *fn_def); - let generic_predicates = self.db.generic_predicates(def.into()); + let generic_predicates = + self.db.generic_predicates(GenericDefId::from_callable(self.db.upcast(), def)); for predicate in generic_predicates.iter() { let (predicate, binders) = predicate .clone() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index d876008cd58..490ecfd7fa3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -41,14 +41,7 @@ impl InferenceContext<'_> { fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> { let (value, self_subst) = self.resolve_value_path_inner(path, id)?; - let value_def = match value { - ValueNs::LocalBinding(pat) => match self.result.type_of_binding.get(pat) { - Some(ty) => return Some(ValuePathResolution::NonGeneric(ty.clone())), - None => { - never!("uninferred pattern?"); - return None; - } - }, + let value_def: ValueTyDefId = match value { ValueNs::FunctionId(it) => it.into(), ValueNs::ConstId(it) => it.into(), ValueNs::StaticId(it) => it.into(), @@ -62,48 +55,79 @@ impl InferenceContext<'_> { it.into() } + ValueNs::LocalBinding(pat) => { + return match self.result.type_of_binding.get(pat) { + Some(ty) => Some(ValuePathResolution::NonGeneric(ty.clone())), + None => { + never!("uninferred pattern?"); + None + } + } + } ValueNs::ImplSelf(impl_id) => { let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); - if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { - return Some(ValuePathResolution::GenericDef( + return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { + Some(ValuePathResolution::GenericDef( struct_id.into(), struct_id.into(), substs.clone(), - )); + )) } else { // FIXME: report error, invalid Self reference - return None; - } + None + }; } ValueNs::GenericParam(it) => { return Some(ValuePathResolution::NonGeneric(self.db.const_param_ty(it))) } }; + let generic_def_id = value_def.to_generic_def_id(self.db); + let Some(generic_def) = generic_def_id else { + // `value_def` is the kind of item that can never be generic (i.e. statics, at least + // currently). We can just skip the binders to get its type. + let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders(); + stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",); + return Some(ValuePathResolution::NonGeneric(ty)); + }; + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()); let substs = ctx.substs_from_path(path, value_def, true); let substs = substs.as_slice(Interner); + + if let ValueNs::EnumVariantId(_) = value { + let mut it = self_subst + .as_ref() + .map_or(&[][..], |s| s.as_slice(Interner)) + .iter() + .chain(substs) + .cloned(); + let builder = TyBuilder::subst_for_def(self.db, generic_def, None); + let substs = builder + .fill(|x| { + it.next().unwrap_or_else(|| match x { + ParamKind::Type => { + self.result.standard_types.unknown.clone().cast(Interner) + } + ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), + ParamKind::Lifetime => error_lifetime().cast(Interner), + }) + }) + .build(); + + return Some(ValuePathResolution::GenericDef(value_def, generic_def, substs)); + } + let parent_substs = self_subst.or_else(|| { - let generics = generics(self.db.upcast(), value_def.to_generic_def_id()?); + let generics = generics(self.db.upcast(), generic_def_id?); let parent_params_len = generics.parent_generics()?.len(); let parent_args = &substs[substs.len() - parent_params_len..]; Some(Substitution::from_iter(Interner, parent_args)) }); let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner)); let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned(); - - let Some(generic_def) = value_def.to_generic_def_id() else { - // `value_def` is the kind of item that can never be generic (i.e. statics, at least - // currently). We can just skip the binders to get its type. - let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders(); - stdx::always!( - parent_substs.is_none() && binders.is_empty(Interner), - "non-empty binders for non-generic def", - ); - return Some(ValuePathResolution::NonGeneric(ty)); - }; let builder = TyBuilder::subst_for_def(self.db, generic_def, parent_substs); let substs = builder .fill(|x| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index d9fd029d378..034b9c773c2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -265,8 +265,10 @@ pub fn layout_of_ty_query( chalk_ir::Scalar::Float(f) => scalar( dl, Primitive::Float(match f { + FloatTy::F16 => Float::F16, FloatTy::F32 => Float::F32, FloatTy::F64 => Float::F64, + FloatTy::F128 => Float::F128, }), ), }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 392bda51b52..35ea13eb119 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -426,6 +426,7 @@ fn enums() { #[test] fn primitives() { + // FIXME(#17451): Add `f16` and `f128` once they are stabilised. size_and_align! { struct Goal(i32, i128, isize, usize, f32, f64, bool, char); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 5e33e1285ee..bd650869bb3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -1,6 +1,6 @@ //! The type system. We currently use this to infer types for completion, hover //! information and various assists. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] @@ -60,7 +60,7 @@ use chalk_ir::{ NoSolution, }; use either::Either; -use hir_def::{hir::ExprId, type_ref::Rawness, GeneralConstId, TypeOrConstParamId}; +use hir_def::{hir::ExprId, type_ref::Rawness, CallableDefId, GeneralConstId, TypeOrConstParamId}; use hir_expand::name; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; @@ -84,8 +84,8 @@ pub use infer::{ }; pub use interner::Interner; pub use lower::{ - associated_type_shorthand_candidates, CallableDefId, ImplTraitLoweringMode, ParamLoweringMode, - TyDefId, TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId, + TyLoweringContext, ValueTyDefId, }; pub use mapping::{ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 96f545415e2..d421e72d364 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -11,10 +11,7 @@ use std::{ ops::{self, Not as _}, }; -use base_db::{ - salsa::{Cycle, InternValueTrivial}, - CrateId, -}; +use base_db::{salsa::Cycle, CrateId}; use chalk_ir::{ cast::Cast, fold::{Shift, TypeFoldable}, @@ -38,10 +35,10 @@ use hir_def::{ type_ref::{ ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, }, - AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, - GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId, - Lookup, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId, - UnionId, VariantId, + AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, + FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, + LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, + TypeOwnerId, UnionId, VariantId, }; use hir_expand::{name::Name, ExpandResult}; use intern::Interned; @@ -387,14 +384,18 @@ impl<'a> TyLoweringContext<'a> { type_params, const_params, _impl_trait_params, - _lifetime_params, + lifetime_params, ) = self .generics() .expect("variable impl trait lowering must be in a generic def") .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_param as usize + type_params + const_params, + idx as usize + + self_param as usize + + type_params + + const_params + + lifetime_params, )) .intern(Interner) } @@ -815,13 +816,13 @@ impl<'a> TyLoweringContext<'a> { infer_args: bool, explicit_self_ty: Option<Ty>, ) -> Substitution { - // Remember that the item's own generic args come before its parent's. - let mut substs = Vec::new(); - let def = if let Some(d) = def { - d - } else { - return Substitution::empty(Interner); - }; + let Some(def) = def else { return Substitution::empty(Interner) }; + + // Order is + // - Optional Self parameter + // - Lifetime parameters + // - Type or Const parameters + // - Parent parameters let def_generics = generics(self.db.upcast(), def); let ( parent_params, @@ -835,130 +836,121 @@ impl<'a> TyLoweringContext<'a> { self_param as usize + type_params + const_params + impl_trait_params + lifetime_params; let total_len = parent_params + item_len; - let ty_error = TyKind::Error.intern(Interner).cast(Interner); + let mut substs = Vec::new(); - let mut def_generic_iter = def_generics.iter_id(); + // we need to iterate the lifetime and type/const params separately as our order of them + // differs from the supplied syntax - let fill_self_params = || { + let ty_error = || TyKind::Error.intern(Interner).cast(Interner); + let mut def_toc_iter = def_generics.iter_self_type_or_consts_id(); + let fill_self_param = || { if self_param { - let self_ty = - explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone()); + let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error); - if let Some(id) = def_generic_iter.next() { - assert!(matches!( - id, - GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) - )); + if let Some(id) = def_toc_iter.next() { + assert!(matches!(id, GenericParamId::TypeParamId(_))); substs.push(self_ty); } } }; let mut had_explicit_args = false; - if let Some(generic_args) = &args_and_bindings { - if !generic_args.has_self_type { - fill_self_params(); - } - let expected_num = if generic_args.has_self_type { - self_param as usize + type_params + const_params + if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings { + // Fill in the self param first + if has_self_type && self_param { + had_explicit_args = true; + if let Some(id) = def_toc_iter.next() { + assert!(matches!(id, GenericParamId::TypeParamId(_))); + had_explicit_args = true; + if let GenericArg::Type(ty) = &args[0] { + substs.push(self.lower_ty(ty).cast(Interner)); + } + } } else { - type_params + const_params + fill_self_param() }; - let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 }; - // if args are provided, it should be all of them, but we can't rely on that - for arg in generic_args - .args + + // Then fill in the supplied lifetime args, or error lifetimes if there are too few + // (default lifetimes aren't a thing) + for arg in args .iter() - .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) - .skip(skip) - .take(expected_num) + .filter_map(|arg| match arg { + GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)), + _ => None, + }) + .chain(iter::repeat(error_lifetime())) + .take(lifetime_params) { - if let Some(id) = def_generic_iter.next() { - let arg = generic_arg_to_chalk( - self.db, - id, - arg, - &mut (), - |_, type_ref| self.lower_ty(type_ref), - |_, const_ref, ty| self.lower_const(const_ref, ty), - |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ); - had_explicit_args = true; - substs.push(arg); - } + substs.push(arg.cast(Interner)); } - for arg in generic_args - .args + let skip = if has_self_type { 1 } else { 0 }; + // Fill in supplied type and const args + // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that + for (arg, id) in args .iter() - .filter(|arg| matches!(arg, GenericArg::Lifetime(_))) - .take(lifetime_params) + .filter(|arg| !matches!(arg, GenericArg::Lifetime(_))) + .skip(skip) + .take(type_params + const_params) + .zip(def_toc_iter) { - // Taking into the fact that def_generic_iter will always have lifetimes at the end - // Should have some test cases tho to test this behaviour more properly - if let Some(id) = def_generic_iter.next() { - let arg = generic_arg_to_chalk( - self.db, - id, - arg, - &mut (), - |_, type_ref| self.lower_ty(type_ref), - |_, const_ref, ty| self.lower_const(const_ref, ty), - |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ); - had_explicit_args = true; - substs.push(arg); - } + had_explicit_args = true; + let arg = generic_arg_to_chalk( + self.db, + id, + arg, + &mut (), + |_, type_ref| self.lower_ty(type_ref), + |_, const_ref, ty| self.lower_const(const_ref, ty), + |_, lifetime_ref| self.lower_lifetime(lifetime_ref), + ); + substs.push(arg); } } else { - fill_self_params(); + fill_self_param(); } - // These params include those of parent. - let remaining_params: SmallVec<[_; 2]> = def_generic_iter - .map(|id| match id { - GenericParamId::ConstParamId(x) => { - unknown_const_as_generic(self.db.const_param_ty(x)) - } - GenericParamId::TypeParamId(_) => ty_error.clone(), - GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), - }) - .collect(); - assert_eq!(remaining_params.len() + substs.len(), total_len); - + let param_to_err = |id| match id { + GenericParamId::ConstParamId(x) => unknown_const_as_generic(self.db.const_param_ty(x)), + GenericParamId::TypeParamId(_) => ty_error(), + GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), + }; // handle defaults. In expression or pattern path segments without // explicitly specified type arguments, missing type arguments are inferred // (i.e. defaults aren't used). // Generic parameters for associated types are not supposed to have defaults, so we just // ignore them. - let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def { - let container = id.lookup(self.db.upcast()).container; - matches!(container, ItemContainerId::TraitId(_)) - } else { - false + let is_assoc_ty = || match def { + GenericDefId::TypeAliasId(id) => { + matches!(id.lookup(self.db.upcast()).container, ItemContainerId::TraitId(_)) + } + _ => false, }; - if !is_assoc_ty && (!infer_args || had_explicit_args) { - let defaults = self.db.generic_defaults(def); - assert_eq!(total_len, defaults.len()); + let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty(); + if fill_defaults { + let defaults = &*self.db.generic_defaults(def); + let (item, _parent) = defaults.split_at(item_len); let parent_from = item_len - substs.len(); - for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() { + let mut rem = + def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>(); + // Fill in defaults for type/const params + for (idx, default_ty) in item[substs.len()..].iter().enumerate() { // each default can depend on the previous parameters let substs_so_far = Substitution::from_iter( Interner, - substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()), + substs.iter().cloned().chain(rem[idx..].iter().cloned()), ); substs.push(default_ty.clone().substitute(Interner, &substs_so_far)); } - - // Keep parent's params as unknown. - let mut remaining_params = remaining_params; - substs.extend(remaining_params.drain(parent_from..)); + // Fill in remaining parent params + substs.extend(rem.drain(parent_from..)); } else { - substs.extend(remaining_params); + // Fill in remaining def params and parent params + substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err)); } - assert_eq!(substs.len(), total_len); + assert_eq!(substs.len(), total_len, "expected {} substs, got {}", total_len, substs.len()); Substitution::from_iter(Interner, substs) } @@ -1535,7 +1527,7 @@ pub(crate) fn generic_predicates_for_param_query( def: GenericDefId, param_id: TypeOrConstParamId, assoc_name: Option<Name>, -) -> Arc<[Binders<QuantifiedWhereClause>]> { +) -> GenericPredicates { let resolver = def.resolver(db.upcast()); let ctx = if let GenericDefId::FunctionId(_) = def { TyLoweringContext::new(db, &resolver, def.into()) @@ -1611,7 +1603,7 @@ pub(crate) fn generic_predicates_for_param_query( ); }; } - predicates.into() + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) } pub(crate) fn generic_predicates_for_param_recover( @@ -1620,15 +1612,15 @@ pub(crate) fn generic_predicates_for_param_recover( _def: &GenericDefId, _param_id: &TypeOrConstParamId, _assoc_name: &Option<Name>, -) -> Arc<[Binders<QuantifiedWhereClause>]> { - Arc::from_iter(None) +) -> GenericPredicates { + GenericPredicates(None) } pub(crate) fn trait_environment_for_body_query( db: &dyn HirDatabase, def: DefWithBodyId, ) -> Arc<TraitEnvironment> { - let Some(def) = def.as_generic_def_id() else { + let Some(def) = def.as_generic_def_id(db.upcast()) else { let krate = def.module(db.upcast()).krate(); return TraitEnvironment::empty(krate); }; @@ -1725,8 +1717,8 @@ pub(crate) fn generic_predicates_query( }) .collect::<Vec<_>>(); - let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - if !subst.is_empty(Interner) { + if generics.len() > 0 { + let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); let explicitly_unsized_tys = ctx.unsized_types.into_inner(); if let Some(implicitly_sized_predicates) = implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) @@ -1995,47 +1987,6 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum CallableDefId { - FunctionId(FunctionId), - StructId(StructId), - EnumVariantId(EnumVariantId), -} - -impl InternValueTrivial for CallableDefId {} - -impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); -impl From<CallableDefId> for ModuleDefId { - fn from(def: CallableDefId) -> ModuleDefId { - match def { - CallableDefId::FunctionId(f) => ModuleDefId::FunctionId(f), - CallableDefId::StructId(s) => ModuleDefId::AdtId(AdtId::StructId(s)), - CallableDefId::EnumVariantId(e) => ModuleDefId::EnumVariantId(e), - } - } -} - -impl CallableDefId { - pub fn krate(self, db: &dyn HirDatabase) -> CrateId { - let db = db.upcast(); - match self { - CallableDefId::FunctionId(f) => f.krate(db), - CallableDefId::StructId(s) => s.krate(db), - CallableDefId::EnumVariantId(e) => e.krate(db), - } - } -} - -impl From<CallableDefId> for GenericDefId { - fn from(def: CallableDefId) -> GenericDefId { - match def { - CallableDefId::FunctionId(f) => f.into(), - CallableDefId::StructId(s) => s.into(), - CallableDefId::EnumVariantId(e) => e.into(), - } - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TyDefId { BuiltinType(BuiltinType), @@ -2056,12 +2007,12 @@ pub enum ValueTyDefId { impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId); impl ValueTyDefId { - pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> { + pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> Option<GenericDefId> { match self { Self::FunctionId(id) => Some(id.into()), Self::StructId(id) => Some(id.into()), Self::UnionId(id) => Some(id.into()), - Self::EnumVariantId(var) => Some(var.into()), + Self::EnumVariantId(var) => Some(var.lookup(db.upcast()).parent.into()), Self::ConstId(id) => Some(id.into()), Self::StaticId(_) => None, } @@ -2112,7 +2063,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde // returns None if def is a type arg pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { let parent_data = db.generic_params(def.parent()); - let data = &parent_data.type_or_consts[def.local_id()]; + let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, def.parent().into()); match data { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 5ce124d6d27..fad74c2448c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -127,9 +127,11 @@ pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ TyFingerprint::Scalar(Scalar::Uint(UintTy::Usize)), ]; -pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [ +pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 4] = [ + TyFingerprint::Scalar(Scalar::Float(FloatTy::F16)), TyFingerprint::Scalar(Scalar::Float(FloatTy::F32)), TyFingerprint::Scalar(Scalar::Float(FloatTy::F64)), + TyFingerprint::Scalar(Scalar::Float(FloatTy::F128)), ]; type TraitFpMap = FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Box<[ImplId]>>>; @@ -1322,7 +1324,7 @@ fn iterate_inherent_methods( callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { for &impl_id in impls.for_self_ty(self_ty) { - for &item in &table.db.impl_data(impl_id).items { + for &item in table.db.impl_data(impl_id).items.iter() { let visible = match is_valid_impl_method_candidate( table, self_ty, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 4ee96a66a39..2d9c221b732 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -18,6 +18,10 @@ use hir_expand::{mod_path::ModPath, HirFileIdExt, InFile}; use intern::Interned; use la_arena::ArenaMap; use rustc_abi::TargetDataLayout; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; @@ -55,6 +59,13 @@ macro_rules! from_bytes { Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $ty).into())), })) }; + ($apfloat:tt, $bits:tt, $value:expr) => { + // FIXME(#17451): Switch to builtin `f16` and `f128` once they are stable. + $apfloat::from_bits($bits::from_le_bytes(match ($value).try_into() { + Ok(it) => it, + Err(_) => return Err(MirEvalError::InternalError(stringify!(mismatched size in constructing $apfloat).into())), + }).into()) + }; } macro_rules! not_supported { @@ -1110,6 +1121,10 @@ impl Evaluator<'_> { } if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { match f { + chalk_ir::FloatTy::F16 => { + let c = -from_bytes!(f16, u16, c); + Owned(u16::try_from(c.to_bits()).unwrap().to_le_bytes().into()) + } chalk_ir::FloatTy::F32 => { let c = -from_bytes!(f32, c); Owned(c.to_le_bytes().into()) @@ -1118,6 +1133,10 @@ impl Evaluator<'_> { let c = -from_bytes!(f64, c); Owned(c.to_le_bytes().into()) } + chalk_ir::FloatTy::F128 => { + let c = -from_bytes!(f128, u128, c); + Owned(c.to_bits().to_le_bytes().into()) + } } } else { let mut c = c.to_vec(); @@ -1169,6 +1188,39 @@ impl Evaluator<'_> { } if let TyKind::Scalar(chalk_ir::Scalar::Float(f)) = ty.kind(Interner) { match f { + chalk_ir::FloatTy::F16 => { + let l = from_bytes!(f16, u16, lc); + let r = from_bytes!(f16, u16, rc); + match op { + BinOp::Ge + | BinOp::Gt + | BinOp::Le + | BinOp::Lt + | BinOp::Eq + | BinOp::Ne => { + let r = op.run_compare(l, r) as u8; + Owned(vec![r]) + } + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => { + let r = match op { + BinOp::Add => l + r, + BinOp::Sub => l - r, + BinOp::Mul => l * r, + BinOp::Div => l / r, + _ => unreachable!(), + }; + Owned( + u16::try_from(r.value.to_bits()) + .unwrap() + .to_le_bytes() + .into(), + ) + } + it => not_supported!( + "invalid binop {it:?} on floating point operators" + ), + } + } chalk_ir::FloatTy::F32 => { let l = from_bytes!(f32, lc); let r = from_bytes!(f32, rc); @@ -1225,6 +1277,34 @@ impl Evaluator<'_> { ), } } + chalk_ir::FloatTy::F128 => { + let l = from_bytes!(f128, u128, lc); + let r = from_bytes!(f128, u128, rc); + match op { + BinOp::Ge + | BinOp::Gt + | BinOp::Le + | BinOp::Lt + | BinOp::Eq + | BinOp::Ne => { + let r = op.run_compare(l, r) as u8; + Owned(vec![r]) + } + BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div => { + let r = match op { + BinOp::Add => l + r, + BinOp::Sub => l - r, + BinOp::Mul => l * r, + BinOp::Div => l / r, + _ => unreachable!(), + }; + Owned(r.value.to_bits().to_le_bytes().into()) + } + it => not_supported!( + "invalid binop {it:?} on floating point operators" + ), + } + } } } else { let is_signed = matches!(ty.as_builtin(), Some(BuiltinType::Int(_))); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 3438712049e..ce22e9d2c2c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -627,6 +627,7 @@ impl Evaluator<'_> { if let Some(name) = name.strip_prefix("atomic_") { return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); } + // FIXME(#17451): Add `f16` and `f128` intrinsics. if let Some(name) = name.strip_suffix("f64") { let result = match name { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 09302846f1b..1a0a1b780a1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -19,6 +19,7 @@ use hir_def::{ }; use hir_expand::name::Name; use la_arena::ArenaMap; +use rustc_apfloat::Float; use rustc_hash::FxHashMap; use syntax::TextRange; use triomphe::Arc; @@ -183,7 +184,7 @@ impl MirLowerError { }, MirLowerError::GenericArgNotProvided(id, subst) => { let parent = id.parent; - let param = &db.generic_params(parent).type_or_consts[id.local_id]; + let param = &db.generic_params(parent)[id.local_id]; writeln!( f, "Generic arg not provided for {}", @@ -483,7 +484,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } ValueNs::GenericParam(p) => { - let Some(def) = self.owner.as_generic_def_id() else { + let Some(def) = self.owner.as_generic_def_id(self.db.upcast()) else { not_supported!("owner without generic def id"); }; let gen = generics(self.db.upcast(), def); @@ -1330,7 +1331,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn placeholder_subst(&mut self) -> Substitution { - match self.owner.as_generic_def_id() { + match self.owner.as_generic_def_id(self.db.upcast()) { Some(it) => TyBuilder::placeholder_subst(self.db, it), None => Substitution::empty(Interner), } @@ -1432,10 +1433,14 @@ impl<'ctx> MirLowerCtx<'ctx> { hir_def::hir::Literal::Int(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), hir_def::hir::Literal::Uint(it, _) => Box::from(&it.to_le_bytes()[0..size()?]), hir_def::hir::Literal::Float(f, _) => match size()? { - 8 => Box::new(f.into_f64().to_le_bytes()), - 4 => Box::new(f.into_f32().to_le_bytes()), + 16 => Box::new(f.to_f128().to_bits().to_le_bytes()), + 8 => Box::new(f.to_f64().to_le_bytes()), + 4 => Box::new(f.to_f32().to_le_bytes()), + 2 => Box::new(u16::try_from(f.to_f16().to_bits()).unwrap().to_le_bytes()), _ => { - return Err(MirLowerError::TypeError("float with size other than 4 or 8 bytes")) + return Err(MirLowerError::TypeError( + "float with size other than 2, 4, 8 or 16 bytes", + )) } }, }; @@ -2160,9 +2165,7 @@ pub fn lower_to_mir( root_expr: ExprId, ) -> Result<MirBody> { if infer.has_errors { - return Err(MirLowerError::TypeMismatch( - infer.type_mismatches().next().map(|(_, it)| it.clone()), - )); + return Err(MirLowerError::TypeMismatch(None)); } let mut ctx = MirLowerCtx::new(db, owner, body, infer); // 0 is return local diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index 43afa615048..172dea02e61 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -302,7 +302,7 @@ pub fn monomorphized_mir_body_query( subst: Substitution, trait_env: Arc<crate::TraitEnvironment>, ) -> Result<Arc<MirBody>, MirLowerError> { - let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def)); let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; let body = db.mir_body(owner)?; let mut body = (*body).clone(); @@ -327,7 +327,7 @@ pub fn monomorphized_mir_body_for_closure_query( trait_env: Arc<crate::TraitEnvironment>, ) -> Result<Arc<MirBody>, MirLowerError> { let InternedClosure(owner, _) = db.lookup_intern_closure(closure.into()); - let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def)); let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; let body = db.mir_body_for_closure(closure)?; let mut body = (*body).clone(); @@ -343,7 +343,7 @@ pub fn monomorphize_mir_body_bad( trait_env: Arc<crate::TraitEnvironment>, ) -> Result<MirBody, MirLowerError> { let owner = body.owner; - let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def)); + let generics = owner.as_generic_def_id(db.upcast()).map(|g_def| generics(db.upcast(), g_def)); let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner }; filler.fill_body(&mut body)?; Ok(body) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs index d7f48c69a56..a4e077ba635 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/primitive.rs @@ -27,8 +27,10 @@ pub fn uint_ty_to_string(ty: UintTy) -> &'static str { pub fn float_ty_to_string(ty: FloatTy) -> &'static str { match ty { + FloatTy::F16 => "f16", FloatTy::F32 => "f32", FloatTy::F64 => "f64", + FloatTy::F128 => "f128", } } @@ -56,7 +58,9 @@ pub(super) fn uint_ty_from_builtin(t: BuiltinUint) -> UintTy { pub(super) fn float_ty_from_builtin(t: BuiltinFloat) -> FloatTy { match t { + BuiltinFloat::F16 => FloatTy::F16, BuiltinFloat::F32 => FloatTy::F32, BuiltinFloat::F64 => FloatTy::F64, + BuiltinFloat::F128 => FloatTy::F128, } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 5e040a60e29..1c1f7055efd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -111,8 +111,10 @@ fn infer_literal_pattern() { if let "foo" = any() {} if let 1 = any() {} if let 1u32 = any() {} + if let 1f16 = any() {} if let 1f32 = any() {} if let 1.0 = any() {} + if let 1f128 = any() {} if let true = any() {} } "#, @@ -121,7 +123,7 @@ fn infer_literal_pattern() { 19..26 'loop {}': ! 24..26 '{}': () 37..38 'x': &'? i32 - 46..208 '{ ...) {} }': () + 46..263 '{ ...) {} }': () 52..75 'if let...y() {}': () 55..72 'let "f... any()': bool 59..64 '"foo"': &'static str @@ -145,25 +147,39 @@ fn infer_literal_pattern() { 124..126 '{}': () 131..153 'if let...y() {}': () 134..150 'let 1f... any()': bool - 138..142 '1f32': f32 - 138..142 '1f32': f32 - 145..148 'any': fn any<f32>() -> f32 - 145..150 'any()': f32 + 138..142 '1f16': f16 + 138..142 '1f16': f16 + 145..148 'any': fn any<f16>() -> f16 + 145..150 'any()': f16 151..153 '{}': () - 158..179 'if let...y() {}': () - 161..176 'let 1.0 = any()': bool - 165..168 '1.0': f64 - 165..168 '1.0': f64 - 171..174 'any': fn any<f64>() -> f64 - 171..176 'any()': f64 - 177..179 '{}': () - 184..206 'if let...y() {}': () - 187..203 'let tr... any()': bool - 191..195 'true': bool - 191..195 'true': bool - 198..201 'any': fn any<bool>() -> bool - 198..203 'any()': bool + 158..180 'if let...y() {}': () + 161..177 'let 1f... any()': bool + 165..169 '1f32': f32 + 165..169 '1f32': f32 + 172..175 'any': fn any<f32>() -> f32 + 172..177 'any()': f32 + 178..180 '{}': () + 185..206 'if let...y() {}': () + 188..203 'let 1.0 = any()': bool + 192..195 '1.0': f64 + 192..195 '1.0': f64 + 198..201 'any': fn any<f64>() -> f64 + 198..203 'any()': f64 204..206 '{}': () + 211..234 'if let...y() {}': () + 214..231 'let 1f... any()': bool + 218..223 '1f128': f128 + 218..223 '1f128': f128 + 226..229 'any': fn any<f128>() -> f128 + 226..231 'any()': f128 + 232..234 '{}': () + 239..261 'if let...y() {}': () + 242..258 'let tr... any()': bool + 246..250 'true': bool + 246..250 'true': bool + 253..256 'any': fn any<bool>() -> bool + 253..258 'any()': bool + 259..261 '{}': () "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 3aa94be755c..aa7b00b8deb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -1999,3 +1999,45 @@ where "#, ); } + +#[test] +fn tait_async_stack_overflow_17199() { + check_types( + r#" + //- minicore: fmt, future + type Foo = impl core::fmt::Debug; + + async fn foo() -> Foo { + () + } + + async fn test() { + let t = foo().await; + // ^ impl Debug + } +"#, + ); +} + +#[test] +fn lifetime_params_move_param_defaults() { + check_types( + r#" +pub struct Thing<'s, T = u32>; + +impl <'s> Thing<'s> { + pub fn new() -> Thing<'s> { + Thing + //^^^^^ Thing<'?, u32> + } +} + +fn main() { + let scope = + //^^^^^ &'? Thing<'?, u32> + &Thing::new(); + //^^^^^^^^^^^^ Thing<'?, u32> +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index e2cd7fa26b2..d83a34298ea 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -397,8 +397,10 @@ fn infer_literals() { r##" fn test() { 5i32; + 5f16; 5f32; 5f64; + 5f128; "hello"; b"bytes"; 'c'; @@ -421,26 +423,28 @@ h"; } "##, expect![[r##" - 18..478 '{ ... }': () + 18..515 '{ ... }': () 32..36 '5i32': i32 - 50..54 '5f32': f32 - 68..72 '5f64': f64 - 86..93 '"hello"': &'static str - 107..115 'b"bytes"': &'static [u8; 5] - 129..132 ''c'': char - 146..150 'b'b'': u8 - 164..168 '3.14': f64 - 182..186 '5000': i32 - 200..205 'false': bool - 219..223 'true': bool - 237..333 'r#" ... "#': &'static str - 347..357 'br#"yolo"#': &'static [u8; 4] - 375..376 'a': &'static [u8; 4] - 379..403 'b"a\x2... c"': &'static [u8; 4] - 421..422 'b': &'static [u8; 4] - 425..433 'br"g\ h"': &'static [u8; 4] - 451..452 'c': &'static [u8; 6] - 455..467 'br#"x"\"yb"#': &'static [u8; 6] + 50..54 '5f16': f16 + 68..72 '5f32': f32 + 86..90 '5f64': f64 + 104..109 '5f128': f128 + 123..130 '"hello"': &'static str + 144..152 'b"bytes"': &'static [u8; 5] + 166..169 ''c'': char + 183..187 'b'b'': u8 + 201..205 '3.14': f64 + 219..223 '5000': i32 + 237..242 'false': bool + 256..260 'true': bool + 274..370 'r#" ... "#': &'static str + 384..394 'br#"yolo"#': &'static [u8; 4] + 412..413 'a': &'static [u8; 4] + 416..440 'b"a\x2... c"': &'static [u8; 4] + 458..459 'b': &'static [u8; 4] + 462..470 'br"g\ h"': &'static [u8; 4] + 488..489 'c': &'static [u8; 6] + 492..504 'br#"x"\"yb"#': &'static [u8; 6] "##]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 18fc8afd183..fb07e718d10 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4824,3 +4824,76 @@ fn foo() { "#, ) } + +#[test] +fn nested_impl_traits() { + check_infer( + r#" +//- minicore: fn +trait Foo {} + +trait Bar<T> {} + +trait Baz { + type Assoc; +} + +struct Qux<T> { + qux: T, +} + +struct S; + +impl Foo for S {} + +fn not_allowed1(f: impl Fn(impl Foo)) { + let foo = S; + f(foo); +} + +// This caused stack overflow in #17498 +fn not_allowed2(f: impl Fn(&impl Foo)) { + let foo = S; + f(&foo); +} + +fn not_allowed3(bar: impl Bar<impl Foo>) {} + +// This also caused stack overflow +fn not_allowed4(bar: impl Bar<&impl Foo>) {} + +fn allowed1(baz: impl Baz<Assoc = impl Foo>) {} + +fn allowed2<'a>(baz: impl Baz<Assoc = &'a (impl Foo + 'a)>) {} + +fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} +"#, + expect![[r#" + 139..140 'f': impl Fn({unknown}) + ?Sized + 161..193 '{ ...oo); }': () + 171..174 'foo': S + 177..178 'S': S + 184..185 'f': impl Fn({unknown}) + ?Sized + 184..190 'f(foo)': () + 186..189 'foo': S + 251..252 'f': impl Fn(&'? {unknown}) + ?Sized + 274..307 '{ ...oo); }': () + 284..287 'foo': S + 290..291 'S': S + 297..298 'f': impl Fn(&'? {unknown}) + ?Sized + 297..304 'f(&foo)': () + 299..303 '&foo': &'? S + 300..303 'foo': S + 325..328 'bar': impl Bar<{unknown}> + ?Sized + 350..352 '{}': () + 405..408 'bar': impl Bar<&'? {unknown}> + ?Sized + 431..433 '{}': () + 447..450 'baz': impl Baz<Assoc = impl Foo + ?Sized> + ?Sized + 480..482 '{}': () + 500..503 'baz': impl Baz<Assoc = &'a impl Foo + 'a + ?Sized> + ?Sized + 544..546 '{}': () + 560..563 'baz': impl Baz<Assoc = Qux<impl Foo + ?Sized>> + ?Sized + 598..600 '{}': () + "#]], + ) +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 969999cdb84..738e8421463 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -157,8 +157,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra let generic_params = db.generic_params(trait_.into()); let trait_self = generic_params.trait_self_param(); generic_params - .where_predicates - .iter() + .where_predicates() .filter_map(|pred| match pred { WherePredicate::ForLifetime { target, bound, .. } | WherePredicate::TypeBound { target, bound } => { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 79069ed66bf..72e79af75df 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -452,7 +452,7 @@ impl HirDisplay for TypeOrConstParam { impl HirDisplay for TypeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let params = f.db.generic_params(self.id.parent()); - let param_data = ¶ms.type_or_consts[self.id.local_id()]; + let param_data = ¶ms[self.id.local_id()]; let substs = TyBuilder::placeholder_subst(f.db, self.id.parent()); let krate = self.id.parent().krate(f.db).id; let ty = @@ -539,11 +539,10 @@ fn write_generic_params( f: &mut HirFormatter<'_>, ) -> Result<(), HirDisplayError> { let params = f.db.generic_params(def); - if params.lifetimes.is_empty() - && params.type_or_consts.iter().all(|it| it.1.const_param().is_none()) + if params.iter_lt().next().is_none() + && params.iter_type_or_consts().all(|it| it.1.const_param().is_none()) && params - .type_or_consts - .iter() + .iter_type_or_consts() .filter_map(|it| it.1.type_param()) .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList)) { @@ -560,11 +559,11 @@ fn write_generic_params( f.write_str(", ") } }; - for (_, lifetime) in params.lifetimes.iter() { + for (_, lifetime) in params.iter_lt() { delim(f)?; write!(f, "{}", lifetime.name.display(f.db.upcast()))?; } - for (_, ty) in params.type_or_consts.iter() { + for (_, ty) in params.iter_type_or_consts() { if let Some(name) = &ty.name() { match ty { TypeOrConstParamData::TypeParamData(ty) => { @@ -612,11 +611,11 @@ fn write_where_clause( } fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool { - params.where_predicates.iter().any(|pred| { + params.where_predicates().any(|pred| { !matches!( pred, WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } - if params.type_or_consts[*id].name().is_none() + if params[*id].name().is_none() ) }) } @@ -631,13 +630,13 @@ fn write_where_predicates( let is_unnamed_type_target = |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| { matches!(target, - WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none() + WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none() ) }; let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), - WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() { + WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { Some(name) => write!(f, "{}", name.display(f.db.upcast())), None => f.write_str("{unnamed}"), }, @@ -653,7 +652,7 @@ fn write_where_predicates( _ => false, }; - let mut iter = params.where_predicates.iter().peekable(); + let mut iter = params.where_predicates().peekable(); while let Some(pred) = iter.next() { if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) { continue; diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs index 887227bf4d0..2ad39817b2f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs +++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs @@ -182,7 +182,6 @@ impl From<GenericDef> for GenericDefId { GenericDef::TraitAlias(it) => GenericDefId::TraitAliasId(it.id), GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id), GenericDef::Impl(it) => GenericDefId::ImplId(it.id), - GenericDef::Variant(it) => GenericDefId::EnumVariantId(it.into()), GenericDef::Const(it) => GenericDefId::ConstId(it.id), } } @@ -197,7 +196,6 @@ impl From<GenericDefId> for GenericDef { GenericDefId::TraitAliasId(it) => GenericDef::TraitAlias(it.into()), GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()), GenericDefId::ImplId(it) => GenericDef::Impl(it.into()), - GenericDefId::EnumVariantId(it) => GenericDef::Variant(it.into()), GenericDefId::ConstId(it) => GenericDef::Const(it.into()), } } diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 929c8b3c09e..18e27130f37 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -5,10 +5,10 @@ use either::Either; use hir_def::{ nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource as _}, - Lookup, MacroId, VariantId, + CallableDefId, Lookup, MacroId, VariantId, }; use hir_expand::{HirFileId, InFile}; -use hir_ty::{db::InternedClosure, CallableDefId}; +use hir_ty::db::InternedClosure; use syntax::ast; use tt::TextRange; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c1fe8a8b316..016f3418517 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -17,7 +17,6 @@ //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: //! <https://www.tedinski.com/2018/02/06/system-boundaries.html>. -#![warn(rust_2018_idioms, unused_lifetimes)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] @@ -52,11 +51,11 @@ use hir_def::{ path::ImportAlias, per_ns::PerNs, resolver::{HasResolver, Resolver}, - AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, - EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, - ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, - ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId, - TypeParamId, UnionId, + AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, + DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, + HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, + MacroExpander, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, + TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult, @@ -71,7 +70,7 @@ use hir_ty::{ mir::{interpret_mir, MutBorrowKind}, primitive::UintTy, traits::FnTrait, - AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, + AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, WhereClause, @@ -666,7 +665,7 @@ impl Module { } let parent = impl_def.id.into(); let generic_params = db.generic_params(parent); - let lifetime_params = generic_params.lifetimes.iter().map(|(local_id, _)| { + let lifetime_params = generic_params.iter_lt().map(|(local_id, _)| { GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }) }); let type_params = generic_params @@ -760,7 +759,7 @@ impl Module { impl_assoc_items_scratch.clear(); } - for &item in &db.impl_data(impl_def.id).items { + for &item in db.impl_data(impl_def.id).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } } @@ -1144,7 +1143,7 @@ impl Field { let generic_def_id: GenericDefId = match self.parent { VariantDef::Struct(it) => it.id.into(), VariantDef::Union(it) => it.id.into(), - VariantDef::Variant(it) => it.id.into(), + VariantDef::Variant(it) => it.id.lookup(db.upcast()).parent.into(), }; let substs = TyBuilder::placeholder_subst(db, generic_def_id); let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs); @@ -1177,7 +1176,9 @@ impl Field { db.layout_of_ty( self.ty(db).ty, db.trait_environment(match hir_def::VariantId::from(self.parent) { - hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id), + hir_def::VariantId::EnumVariantId(id) => { + GenericDefId::AdtId(id.lookup(db.upcast()).parent.into()) + } hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()), hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()), }), @@ -1539,8 +1540,7 @@ impl Adt { resolver .generic_params() .and_then(|gp| { - gp.lifetimes - .iter() + gp.iter_lt() // there should only be a single lifetime // but `Arena` requires to use an iterator .nth(0) @@ -2501,9 +2501,8 @@ impl Trait { db: &dyn HirDatabase, count_required_only: bool, ) -> usize { - db.generic_params(GenericDefId::from(self.id)) - .type_or_consts - .iter() + db.generic_params(self.id.into()) + .iter_type_or_consts() .filter(|(_, ty)| !matches!(ty, TypeOrConstParamData::TypeParamData(ty) if ty.provenance != TypeParamProvenance::TypeParamList)) .filter(|(_, ty)| !count_required_only || !ty.has_default()) .count() @@ -2623,6 +2622,13 @@ impl BuiltinType { matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_)) } + pub fn is_f16(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F16) + ) + } + pub fn is_f32(&self) -> bool { matches!( self.inner, @@ -2637,6 +2643,13 @@ impl BuiltinType { ) } + pub fn is_f128(&self) -> bool { + matches!( + self.inner, + hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F128) + ) + } + pub fn is_char(&self) -> bool { matches!(self.inner, hir_def::builtin_type::BuiltinType::Char) } @@ -3107,9 +3120,6 @@ pub enum GenericDef { TraitAlias(TraitAlias), TypeAlias(TypeAlias), Impl(Impl), - // enum variants cannot have generics themselves, but their parent enums - // can, and this makes some code easier to write - Variant(Variant), // consts can have type parameters from their parents (i.e. associated consts of traits) Const(Const), } @@ -3120,7 +3130,6 @@ impl_from!( TraitAlias, TypeAlias, Impl, - Variant, Const for GenericDef ); @@ -3128,7 +3137,7 @@ impl_from!( impl GenericDef { pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { let generics = db.generic_params(self.into()); - let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| { + let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| { let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } }; match toc.split(db) { Either::Left(it) => GenericParam::ConstParam(it), @@ -3145,8 +3154,7 @@ impl GenericDef { pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> { let generics = db.generic_params(self.into()); generics - .lifetimes - .iter() + .iter_lt() .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) @@ -3156,8 +3164,7 @@ impl GenericDef { pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> { let generics = db.generic_params(self.into()); generics - .type_or_consts - .iter() + .iter_type_or_consts() .map(|(local_id, _)| TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id }, }) @@ -3499,7 +3506,7 @@ impl TypeParam { /// argument)? pub fn is_implicit(self, db: &dyn HirDatabase) -> bool { let params = db.generic_params(self.id.parent()); - let data = ¶ms.type_or_consts[self.id.local_id()]; + let data = ¶ms[self.id.local_id()]; match data.type_param().unwrap().provenance { hir_def::generics::TypeParamProvenance::TypeParamList => false, hir_def::generics::TypeParamProvenance::TraitSelf @@ -3553,7 +3560,7 @@ pub struct LifetimeParam { impl LifetimeParam { pub fn name(self, db: &dyn HirDatabase) -> Name { let params = db.generic_params(self.id.parent); - params.lifetimes[self.id.local_id].name.clone() + params[self.id.local_id].name.clone() } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -3577,7 +3584,7 @@ impl ConstParam { pub fn name(self, db: &dyn HirDatabase) -> Name { let params = db.generic_params(self.id.parent()); - match params.type_or_consts[self.id.local_id()].name() { + match params[self.id.local_id()].name() { Some(it) => it.clone(), None => { never!(); @@ -3605,9 +3612,9 @@ impl ConstParam { } fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> { - let params = db.generic_defaults(id.parent); let local_idx = hir_ty::param_idx(db, id)?; - let ty = params.get(local_idx)?.clone(); + let defaults = db.generic_defaults(id.parent); + let ty = defaults.get(local_idx)?.clone(); let subst = TyBuilder::placeholder_subst(db, id.parent); Some(ty.substitute(Interner, &subst)) } @@ -3620,7 +3627,7 @@ pub struct TypeOrConstParam { impl TypeOrConstParam { pub fn name(self, db: &dyn HirDatabase) -> Name { let params = db.generic_params(self.id.parent); - match params.type_or_consts[self.id.local_id].name() { + match params[self.id.local_id].name() { Some(n) => n.clone(), _ => Name::missing(), } @@ -3636,7 +3643,7 @@ impl TypeOrConstParam { pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> { let params = db.generic_params(self.id.parent); - match ¶ms.type_or_consts[self.id.local_id] { + match ¶ms[self.id.local_id] { hir_def::generics::TypeOrConstParamData::TypeParamData(_) => { Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) }) } @@ -3655,7 +3662,7 @@ impl TypeOrConstParam { pub fn as_type_param(self, db: &dyn HirDatabase) -> Option<TypeParam> { let params = db.generic_params(self.id.parent); - match ¶ms.type_or_consts[self.id.local_id] { + match ¶ms[self.id.local_id] { hir_def::generics::TypeOrConstParamData::TypeParamData(_) => { Some(TypeParam { id: TypeParamId::from_unchecked(self.id) }) } @@ -3665,7 +3672,7 @@ impl TypeOrConstParam { pub fn as_const_param(self, db: &dyn HirDatabase) -> Option<ConstParam> { let params = db.generic_params(self.id.parent); - match ¶ms.type_or_consts[self.id.local_id] { + match ¶ms[self.id.local_id] { hir_def::generics::TypeOrConstParamData::TypeParamData(_) => None, hir_def::generics::TypeOrConstParamData::ConstParamData(_) => { Some(ConstParam { id: ConstParamId::from_unchecked(self.id) }) @@ -4052,7 +4059,9 @@ impl Type { ValueTyDefId::FunctionId(it) => GenericDefId::FunctionId(it), ValueTyDefId::StructId(it) => GenericDefId::AdtId(AdtId::StructId(it)), ValueTyDefId::UnionId(it) => GenericDefId::AdtId(AdtId::UnionId(it)), - ValueTyDefId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), + ValueTyDefId::EnumVariantId(it) => { + GenericDefId::AdtId(AdtId::EnumId(it.lookup(db.upcast()).parent)) + } ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()), }, ); diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 8e71a54f804..81c57f6caeb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -68,38 +68,44 @@ impl SourceAnalyzer { pub(crate) fn new_for_body( db: &dyn HirDatabase, def: DefWithBodyId, - node @ InFile { file_id, .. }: InFile<&SyntaxNode>, + node: InFile<&SyntaxNode>, offset: Option<TextSize>, ) -> SourceAnalyzer { - let (body, source_map) = db.body_with_source_map(def); - let scopes = db.expr_scopes(def); - let scope = match offset { - None => scope_for(&scopes, &source_map, node), - Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset), - }; - let resolver = resolver_for_scope(db.upcast(), def, scope); - SourceAnalyzer { - resolver, - def: Some((def, body, source_map)), - infer: Some(db.infer(def)), - file_id, - } + Self::new_for_body_(db, def, node, offset, Some(db.infer(def))) } pub(crate) fn new_for_body_no_infer( db: &dyn HirDatabase, def: DefWithBodyId, + node: InFile<&SyntaxNode>, + offset: Option<TextSize>, + ) -> SourceAnalyzer { + Self::new_for_body_(db, def, node, offset, None) + } + + pub(crate) fn new_for_body_( + db: &dyn HirDatabase, + def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option<TextSize>, + infer: Option<Arc<InferenceResult>>, ) -> SourceAnalyzer { let (body, source_map) = db.body_with_source_map(def); let scopes = db.expr_scopes(def); let scope = match offset { - None => scope_for(&scopes, &source_map, node), - Some(offset) => scope_for_offset(db, &scopes, &source_map, node.file_id, offset), + None => scope_for(db, &scopes, &source_map, node), + Some(offset) => { + debug_assert!( + node.text_range().contains_inclusive(offset), + "{:?} not in {:?}", + offset, + node.text_range() + ); + scope_for_offset(db, &scopes, &source_map, node.file_id, offset) + } }; let resolver = resolver_for_scope(db.upcast(), def, scope); - SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id } + SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer, file_id } } pub(crate) fn new_for_resolver( @@ -662,7 +668,6 @@ impl SourceAnalyzer { return resolved; } - // This must be a normal source file rather than macro file. let ctx = LowerCtx::new(db.upcast(), self.file_id); let hir_path = Path::from_src(&ctx, path.clone())?; @@ -955,14 +960,15 @@ impl SourceAnalyzer { } fn scope_for( + db: &dyn HirDatabase, scopes: &ExprScopes, source_map: &BodySourceMap, node: InFile<&SyntaxNode>, ) -> Option<ScopeId> { - node.value - .ancestors() - .filter_map(ast::Expr::cast) - .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it))) + node.ancestors_with_macros(db.upcast()) + .take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind())) + .filter_map(|it| it.map(ast::Expr::cast).transpose()) + .filter_map(|it| source_map.node_expr(it.as_ref())) .find_map(|it| scopes.scope_for(it)) } @@ -988,8 +994,8 @@ fn scope_for_offset( Some(it.file_id.macro_file()?.call_node(db.upcast())) }) .find(|it| it.file_id == from_file) - .filter(|it| it.value.kind() == SyntaxKind::MACRO_CALL)?; - Some((source.value.text_range(), scope)) + .filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?; + Some((source.text_range(), scope)) }) .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end()) // find containing scope diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 3b88836c24b..02905ca2ce4 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -231,7 +231,7 @@ impl<'a> SymbolCollector<'a> { let impl_data = self.db.impl_data(impl_id); let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string())); self.with_container_name(impl_name, |s| { - for &assoc_item_id in &impl_data.items { + for &assoc_item_id in impl_data.items.iter() { s.push_assoc_item(assoc_item_id) } }) diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs index aa046b02e2e..6f845137084 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs @@ -93,12 +93,6 @@ struct LookupTable { data: FxHashMap<Type, AlternativeExprs>, /// New types reached since last query by the `NewTypesKey` new_types: FxHashMap<NewTypesKey, Vec<Type>>, - /// ScopeDefs that are not interesting any more - exhausted_scopedefs: FxHashSet<ScopeDef>, - /// ScopeDefs that were used in current round - round_scopedef_hits: FxHashSet<ScopeDef>, - /// Amount of rounds since scopedef was first used. - rounds_since_sopedef_hit: FxHashMap<ScopeDef, u32>, /// Types queried but not present types_wishlist: FxHashSet<Type>, /// Threshold to squash trees to `Many` @@ -212,37 +206,6 @@ impl LookupTable { } } - /// Mark `ScopeDef` as exhausted meaning it is not interesting for us any more - fn mark_exhausted(&mut self, def: ScopeDef) { - self.exhausted_scopedefs.insert(def); - } - - /// Mark `ScopeDef` as used meaning we managed to produce something useful from it - fn mark_fulfilled(&mut self, def: ScopeDef) { - self.round_scopedef_hits.insert(def); - } - - /// Start new round (meant to be called at the beginning of iteration in `term_search`) - /// - /// This functions marks some `ScopeDef`s as exhausted if there have been - /// `MAX_ROUNDS_AFTER_HIT` rounds after first using a `ScopeDef`. - fn new_round(&mut self) { - for def in &self.round_scopedef_hits { - let hits = - self.rounds_since_sopedef_hit.entry(*def).and_modify(|n| *n += 1).or_insert(0); - const MAX_ROUNDS_AFTER_HIT: u32 = 2; - if *hits > MAX_ROUNDS_AFTER_HIT { - self.exhausted_scopedefs.insert(*def); - } - } - self.round_scopedef_hits.clear(); - } - - /// Get exhausted `ScopeDef`s - fn exhausted_scopedefs(&self) -> &FxHashSet<ScopeDef> { - &self.exhausted_scopedefs - } - /// Types queried but not found fn types_wishlist(&mut self) -> &FxHashSet<Type> { &self.types_wishlist @@ -275,7 +238,7 @@ pub struct TermSearchConfig { impl Default for TermSearchConfig { fn default() -> Self { - Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 } + Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 1200 } } } @@ -328,19 +291,12 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> { solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup)); while should_continue() { - lookup.new_round(); - solutions.extend(tactics::data_constructor(ctx, &defs, &mut lookup, should_continue)); solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue)); solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue)); solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue)); solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue)); solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue)); - - // Discard not interesting `ScopeDef`s for speedup - for def in lookup.exhausted_scopedefs() { - defs.remove(def); - } } solutions.into_iter().filter(|it| !it.is_many()).unique().collect() diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index bb687f5e73d..0c8f6932c71 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -9,8 +9,8 @@ use hir_ty::{ use itertools::Itertools; use crate::{ - Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, GenericDef, Local, - ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant, + Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef, + SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant, }; /// Helper function to get path to `ModuleDef` @@ -35,43 +35,6 @@ fn mod_item_path_str( .ok_or(DisplaySourceCodeError::PathNotFound) } -/// Helper function to get path to `Type` -fn type_path( - sema_scope: &SemanticsScope<'_>, - ty: &Type, - cfg: ImportPathConfig, -) -> Result<String, DisplaySourceCodeError> { - let db = sema_scope.db; - let m = sema_scope.module(); - - match ty.as_adt() { - Some(adt) => { - let ty_name = ty.display_source_code(db, m.id, true)?; - - let mut path = mod_item_path(sema_scope, &ModuleDef::Adt(adt), cfg).unwrap(); - path.pop_segment(); - let path = path.display(db.upcast()).to_string(); - let res = match path.is_empty() { - true => ty_name, - false => format!("{path}::{ty_name}"), - }; - Ok(res) - } - None => ty.display_source_code(db, m.id, true), - } -} - -/// Helper function to filter out generic parameters that are default -fn non_default_generics(db: &dyn HirDatabase, def: GenericDef, generics: &[Type]) -> Vec<Type> { - def.type_or_const_params(db) - .into_iter() - .filter_map(|it| it.as_type_param(db)) - .zip(generics) - .filter(|(tp, arg)| tp.default(db).as_ref() != Some(arg)) - .map(|(_, arg)| arg.clone()) - .collect() -} - /// Type tree shows how can we get from set of types to some type. /// /// Consider the following code as an example @@ -208,20 +171,7 @@ impl Expr { None => Ok(format!("{target_str}.{func_name}({args})")), } } - Expr::Variant { variant, generics, params } => { - let generics = non_default_generics(db, (*variant).into(), generics); - let generics_str = match generics.is_empty() { - true => String::new(), - false => { - let generics = generics - .iter() - .map(|it| type_path(sema_scope, it, cfg)) - .collect::<Result<Vec<String>, DisplaySourceCodeError>>()? - .into_iter() - .join(", "); - format!("::<{generics}>") - } - }; + Expr::Variant { variant, params, .. } => { let inner = match variant.kind(db) { StructKind::Tuple => { let args = params @@ -230,7 +180,7 @@ impl Expr { .collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .into_iter() .join(", "); - format!("{generics_str}({args})") + format!("({args})") } StructKind::Record => { let fields = variant.fields(db); @@ -248,16 +198,15 @@ impl Expr { .collect::<Result<Vec<String>, DisplaySourceCodeError>>()? .into_iter() .join(", "); - format!("{generics_str}{{ {args} }}") + format!("{{ {args} }}") } - StructKind::Unit => generics_str, + StructKind::Unit => String::new(), }; let prefix = mod_item_path_str(sema_scope, &ModuleDef::Variant(*variant))?; Ok(format!("{prefix}{inner}")) } - Expr::Struct { strukt, generics, params } => { - let generics = non_default_generics(db, (*strukt).into(), generics); + Expr::Struct { strukt, params, .. } => { let inner = match strukt.kind(db) { StructKind::Tuple => { let args = params @@ -286,18 +235,7 @@ impl Expr { .join(", "); format!(" {{ {args} }}") } - StructKind::Unit => match generics.is_empty() { - true => String::new(), - false => { - let generics = generics - .iter() - .map(|it| type_path(sema_scope, it, cfg)) - .collect::<Result<Vec<String>, DisplaySourceCodeError>>()? - .into_iter() - .join(", "); - format!("::<{generics}>") - } - }, + StructKind::Unit => String::new(), }; let prefix = mod_item_path_str(sema_scope, &ModuleDef::Adt(Adt::Struct(*strukt)))?; diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs index b738e6af77b..1b0e6f8bd5b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs @@ -17,11 +17,11 @@ use itertools::Itertools; use rustc_hash::FxHashSet; use crate::{ - Adt, AssocItem, Enum, GenericDef, GenericParam, HasVisibility, Impl, ModuleDef, ScopeDef, Type, - TypeParam, Variant, + Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef, + Type, TypeParam, }; -use crate::term_search::{Expr, TermSearchConfig}; +use crate::term_search::Expr; use super::{LookupTable, NewTypesKey, TermSearchCtx}; @@ -74,8 +74,6 @@ pub(super) fn trivial<'a, DB: HirDatabase>( _ => None, }?; - lookup.mark_exhausted(*def); - let ty = expr.ty(db); lookup.insert(ty.clone(), std::iter::once(expr.clone())); @@ -124,6 +122,10 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>( .filter(move |it| it.is_visible_from(db, module)) .filter_map(AssocItem::as_const) .filter_map(|it| { + if it.attrs(db).is_unstable() { + return None; + } + let expr = Expr::Const(it); let ty = it.ty(db); @@ -151,212 +153,101 @@ pub(super) fn assoc_const<'a, DB: HirDatabase>( /// * `should_continue` - Function that indicates when to stop iterating pub(super) fn data_constructor<'a, DB: HirDatabase>( ctx: &'a TermSearchCtx<'a, DB>, - defs: &'a FxHashSet<ScopeDef>, + _defs: &'a FxHashSet<ScopeDef>, lookup: &'a mut LookupTable, should_continue: &'a dyn std::ops::Fn() -> bool, ) -> impl Iterator<Item = Expr> + 'a { let db = ctx.sema.db; let module = ctx.scope.module(); - fn variant_helper( - db: &dyn HirDatabase, - lookup: &mut LookupTable, - should_continue: &dyn std::ops::Fn() -> bool, - parent_enum: Enum, - variant: Variant, - config: &TermSearchConfig, - ) -> Vec<(Type, Vec<Expr>)> { - // Ignore unstable - if variant.is_unstable(db) { - return Vec::new(); - } - - let generics = GenericDef::from(variant.parent_enum(db)); - let Some(type_params) = generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>() - else { - // Ignore enums with const generics - return Vec::new(); - }; - - // We currently do not check lifetime bounds so ignore all types that have something to do - // with them - if !generics.lifetime_params(db).is_empty() { - return Vec::new(); - } + lookup + .types_wishlist() + .clone() + .into_iter() + .chain(iter::once(ctx.goal.clone())) + .filter_map(|ty| ty.as_adt().map(|adt| (adt, ty))) + .filter(|_| should_continue()) + .filter_map(move |(adt, ty)| match adt { + Adt::Struct(strukt) => { + // Ignore unstable or not visible + if strukt.is_unstable(db) || !strukt.is_visible_from(db, module) { + return None; + } - // Only account for stable type parameters for now, unstable params can be default - // tho, for example in `Box<T, #[unstable] A: Allocator>` - if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) { - return Vec::new(); - } + let generics = GenericDef::from(strukt); - let non_default_type_params_len = - type_params.iter().filter(|it| it.default(db).is_none()).count(); - - let enum_ty_shallow = Adt::from(parent_enum).ty(db); - let generic_params = lookup - .types_wishlist() - .clone() - .into_iter() - .filter(|ty| ty.could_unify_with(db, &enum_ty_shallow)) - .map(|it| it.type_arguments().collect::<Vec<Type>>()) - .chain((non_default_type_params_len == 0).then_some(Vec::new())); - - generic_params - .filter(|_| should_continue()) - .filter_map(move |generics| { - // Insert default type params - let mut g = generics.into_iter(); - let generics: Vec<_> = type_params - .iter() - .map(|it| it.default(db).or_else(|| g.next())) - .collect::<Option<_>>()?; + // We currently do not check lifetime bounds so ignore all types that have something to do + // with them + if !generics.lifetime_params(db).is_empty() { + return None; + } - let enum_ty = Adt::from(parent_enum).ty_with_args(db, generics.iter().cloned()); + if ty.contains_unknown() { + return None; + } // Ignore types that have something to do with lifetimes - if config.enable_borrowcheck && enum_ty.contains_reference(db) { + if ctx.config.enable_borrowcheck && ty.contains_reference(db) { return None; } + let fields = strukt.fields(db); + // Check if all fields are visible, otherwise we cannot fill them + if fields.iter().any(|it| !it.is_visible_from(db, module)) { + return None; + } + + let generics: Vec<_> = ty.type_arguments().collect(); // Early exit if some param cannot be filled from lookup - let param_exprs: Vec<Vec<Expr>> = variant - .fields(db) + let param_exprs: Vec<Vec<Expr>> = fields .into_iter() .map(|field| lookup.find(db, &field.ty_with_args(db, generics.iter().cloned()))) .collect::<Option<_>>()?; // Note that we need special case for 0 param constructors because of multi cartesian // product - let variant_exprs: Vec<Expr> = if param_exprs.is_empty() { - vec![Expr::Variant { variant, generics, params: Vec::new() }] + let exprs: Vec<Expr> = if param_exprs.is_empty() { + vec![Expr::Struct { strukt, generics, params: Vec::new() }] } else { param_exprs .into_iter() .multi_cartesian_product() - .map(|params| Expr::Variant { variant, generics: generics.clone(), params }) + .map(|params| Expr::Struct { strukt, generics: generics.clone(), params }) .collect() }; - lookup.insert(enum_ty.clone(), variant_exprs.iter().cloned()); - - Some((enum_ty, variant_exprs)) - }) - .collect() - } - defs.iter() - .filter_map(move |def| match def { - ScopeDef::ModuleDef(ModuleDef::Variant(it)) => { - let variant_exprs = variant_helper( - db, - lookup, - should_continue, - it.parent_enum(db), - *it, - &ctx.config, - ); - if variant_exprs.is_empty() { - return None; - } - if GenericDef::from(it.parent_enum(db)) - .type_or_const_params(db) - .into_iter() - .filter_map(|it| it.as_type_param(db)) - .all(|it| it.default(db).is_some()) - { - lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Variant(*it))); - } - Some(variant_exprs) - } - ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(enum_))) => { - let exprs: Vec<(Type, Vec<Expr>)> = enum_ - .variants(db) - .into_iter() - .flat_map(|it| { - variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config) - }) - .collect(); - - if exprs.is_empty() { - return None; - } - if GenericDef::from(*enum_) - .type_or_const_params(db) - .into_iter() - .filter_map(|it| it.as_type_param(db)) - .all(|it| it.default(db).is_some()) - { - lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Enum(*enum_)))); - } - - Some(exprs) + lookup.insert(ty.clone(), exprs.iter().cloned()); + Some((ty, exprs)) } - ScopeDef::ModuleDef(ModuleDef::Adt(Adt::Struct(it))) => { - // Ignore unstable and not visible - if it.is_unstable(db) || !it.is_visible_from(db, module) { + Adt::Enum(enum_) => { + // Ignore unstable or not visible + if enum_.is_unstable(db) || !enum_.is_visible_from(db, module) { return None; } - let generics = GenericDef::from(*it); - - // Ignore const params for now - let type_params = generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>()?; - + let generics = GenericDef::from(enum_); // We currently do not check lifetime bounds so ignore all types that have something to do // with them if !generics.lifetime_params(db).is_empty() { return None; } - // Only account for stable type parameters for now, unstable params can be default - // tho, for example in `Box<T, #[unstable] A: Allocator>` - if type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) { + if ty.contains_unknown() { return None; } - let non_default_type_params_len = - type_params.iter().filter(|it| it.default(db).is_none()).count(); + // Ignore types that have something to do with lifetimes + if ctx.config.enable_borrowcheck && ty.contains_reference(db) { + return None; + } - let struct_ty_shallow = Adt::from(*it).ty(db); - let generic_params = lookup - .types_wishlist() - .clone() + let generics: Vec<_> = ty.type_arguments().collect(); + let exprs = enum_ + .variants(db) .into_iter() - .filter(|ty| ty.could_unify_with(db, &struct_ty_shallow)) - .map(|it| it.type_arguments().collect::<Vec<Type>>()) - .chain((non_default_type_params_len == 0).then_some(Vec::new())); - - let exprs = generic_params - .filter(|_| should_continue()) - .filter_map(|generics| { - // Insert default type params - let mut g = generics.into_iter(); - let generics: Vec<_> = type_params - .iter() - .map(|it| it.default(db).or_else(|| g.next())) - .collect::<Option<_>>()?; - - let struct_ty = Adt::from(*it).ty_with_args(db, generics.iter().cloned()); - - // Ignore types that have something to do with lifetimes - if ctx.config.enable_borrowcheck && struct_ty.contains_reference(db) { - return None; - } - let fields = it.fields(db); - // Check if all fields are visible, otherwise we cannot fill them - if fields.iter().any(|it| !it.is_visible_from(db, module)) { - return None; - } - + .filter_map(|variant| { // Early exit if some param cannot be filled from lookup - let param_exprs: Vec<Vec<Expr>> = fields + let param_exprs: Vec<Vec<Expr>> = variant + .fields(db) .into_iter() .map(|field| { lookup.find(db, &field.ty_with_args(db, generics.iter().cloned())) @@ -365,36 +256,33 @@ pub(super) fn data_constructor<'a, DB: HirDatabase>( // Note that we need special case for 0 param constructors because of multi cartesian // product - let struct_exprs: Vec<Expr> = if param_exprs.is_empty() { - vec![Expr::Struct { strukt: *it, generics, params: Vec::new() }] + let variant_exprs: Vec<Expr> = if param_exprs.is_empty() { + vec![Expr::Variant { + variant, + generics: generics.clone(), + params: Vec::new(), + }] } else { param_exprs .into_iter() .multi_cartesian_product() - .map(|params| Expr::Struct { - strukt: *it, + .map(|params| Expr::Variant { + variant, generics: generics.clone(), params, }) .collect() }; - - if non_default_type_params_len == 0 { - // Fulfilled only if there are no generic parameters - lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Adt( - Adt::Struct(*it), - ))); - } - lookup.insert(struct_ty.clone(), struct_exprs.iter().cloned()); - - Some((struct_ty, struct_exprs)) + lookup.insert(ty.clone(), variant_exprs.iter().cloned()); + Some(variant_exprs) }) + .flatten() .collect(); - Some(exprs) + + Some((ty, exprs)) } - _ => None, + Adt::Union(_) => None, }) - .flatten() .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) .flatten() } @@ -515,7 +403,6 @@ pub(super) fn free_function<'a, DB: HirDatabase>( .collect() }; - lookup.mark_fulfilled(ScopeDef::ModuleDef(ModuleDef::Function(*it))); lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned()); Some((ret_ty, fn_exprs)) }) @@ -555,6 +442,8 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( lookup .new_types(NewTypesKey::ImplMethod) .into_iter() + .filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown())) + .filter(|_| should_continue()) .flat_map(|ty| { Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp)) }) @@ -563,26 +452,15 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( AssocItem::Function(f) => Some((imp, ty, f)), _ => None, }) + .filter(|_| should_continue()) .filter_map(move |(imp, ty, it)| { let fn_generics = GenericDef::from(it); let imp_generics = GenericDef::from(imp); - // Ignore const params for now - let imp_type_params = imp_generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>()?; - - // Ignore const params for now - let fn_type_params = fn_generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>()?; - // Ignore all functions that have something to do with lifetimes as we don't check them - if !fn_generics.lifetime_params(db).is_empty() { + if !fn_generics.lifetime_params(db).is_empty() + || !imp_generics.lifetime_params(db).is_empty() + { return None; } @@ -596,112 +474,59 @@ pub(super) fn impl_method<'a, DB: HirDatabase>( return None; } - // Only account for stable type parameters for now, unstable params can be default - // tho, for example in `Box<T, #[unstable] A: Allocator>` - if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) - || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) - { + // Ignore functions with generics for now as they kill the performance + // Also checking bounds for generics is problematic + if !fn_generics.type_or_const_params(db).is_empty() { return None; } - // Double check that we have fully known type - if ty.type_arguments().any(|it| it.contains_unknown()) { + let ret_ty = it.ret_type_with_args(db, ty.type_arguments()); + // Filter out functions that return references + if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() + { return None; } - let non_default_fn_type_params_len = - fn_type_params.iter().filter(|it| it.default(db).is_none()).count(); - - // Ignore functions with generics for now as they kill the performance - // Also checking bounds for generics is problematic - if non_default_fn_type_params_len > 0 { + // Ignore functions that do not change the type + if ty.could_unify_with_deeply(db, &ret_ty) { return None; } - let generic_params = lookup - .iter_types() - .collect::<Vec<_>>() // Force take ownership - .into_iter() - .permutations(non_default_fn_type_params_len); + let self_ty = + it.self_param(db).expect("No self param").ty_with_args(db, ty.type_arguments()); - let exprs: Vec<_> = generic_params - .filter(|_| should_continue()) - .filter_map(|generics| { - // Insert default type params - let mut g = generics.into_iter(); - let generics: Vec<_> = ty - .type_arguments() - .map(Some) - .chain(fn_type_params.iter().map(|it| match it.default(db) { - Some(ty) => Some(ty), - None => { - let generic = g.next().expect("Missing type param"); - // Filter out generics that do not unify due to trait bounds - it.ty(db).could_unify_with(db, &generic).then_some(generic) - } - })) - .collect::<Option<_>>()?; - - let ret_ty = it.ret_type_with_args( - db, - ty.type_arguments().chain(generics.iter().cloned()), - ); - // Filter out functions that return references - if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) - || ret_ty.is_raw_ptr() - { - return None; - } + // Ignore functions that have different self type + if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) { + return None; + } - // Ignore functions that do not change the type - if ty.could_unify_with_deeply(db, &ret_ty) { - return None; - } + let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup"); - let self_ty = it - .self_param(db) - .expect("No self param") - .ty_with_args(db, ty.type_arguments().chain(generics.iter().cloned())); + // Early exit if some param cannot be filled from lookup + let param_exprs: Vec<Vec<Expr>> = it + .params_without_self_with_args(db, ty.type_arguments()) + .into_iter() + .map(|field| lookup.find_autoref(db, field.ty())) + .collect::<Option<_>>()?; - // Ignore functions that have different self type - if !self_ty.autoderef(db).any(|s_ty| ty == s_ty) { - return None; + let generics: Vec<_> = ty.type_arguments().collect(); + let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs) + .chain(param_exprs) + .multi_cartesian_product() + .map(|params| { + let mut params = params.into_iter(); + let target = Box::new(params.next().unwrap()); + Expr::Method { + func: it, + generics: generics.clone(), + target, + params: params.collect(), } - - let target_type_exprs = lookup.find(db, &ty).expect("Type not in lookup"); - - // Early exit if some param cannot be filled from lookup - let param_exprs: Vec<Vec<Expr>> = it - .params_without_self_with_args( - db, - ty.type_arguments().chain(generics.iter().cloned()), - ) - .into_iter() - .map(|field| lookup.find_autoref(db, field.ty())) - .collect::<Option<_>>()?; - - let fn_exprs: Vec<Expr> = std::iter::once(target_type_exprs) - .chain(param_exprs) - .multi_cartesian_product() - .map(|params| { - let mut params = params.into_iter(); - let target = Box::new(params.next().unwrap()); - Expr::Method { - func: it, - generics: generics.clone(), - target, - params: params.collect(), - } - }) - .collect(); - - lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned()); - Some((ret_ty, fn_exprs)) }) .collect(); - Some(exprs) + + Some((ret_ty, fn_exprs)) }) - .flatten() .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) .flatten() } @@ -773,9 +598,8 @@ pub(super) fn famous_types<'a, DB: HirDatabase>( Expr::FamousType { ty: Type::new(db, module.id, TyBuilder::unit()), value: "()" }, ] .into_iter() - .map(|exprs| { + .inspect(|exprs| { lookup.insert(exprs.ty(db), std::iter::once(exprs.clone())); - exprs }) .filter(|expr| expr.ty(db).could_unify_with_deeply(db, &ctx.goal)) } @@ -805,6 +629,7 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( .clone() .into_iter() .chain(iter::once(ctx.goal.clone())) + .filter(|ty| !ty.type_arguments().any(|it| it.contains_unknown())) .filter(|_| should_continue()) .flat_map(|ty| { Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp)) @@ -815,24 +640,11 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( AssocItem::Function(f) => Some((imp, ty, f)), _ => None, }) + .filter(|_| should_continue()) .filter_map(move |(imp, ty, it)| { let fn_generics = GenericDef::from(it); let imp_generics = GenericDef::from(imp); - // Ignore const params for now - let imp_type_params = imp_generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>()?; - - // Ignore const params for now - let fn_type_params = fn_generics - .type_or_const_params(db) - .into_iter() - .map(|it| it.as_type_param(db)) - .collect::<Option<Vec<TypeParam>>>()?; - // Ignore all functions that have something to do with lifetimes as we don't check them if !fn_generics.lifetime_params(db).is_empty() || !imp_generics.lifetime_params(db).is_empty() @@ -850,104 +662,43 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>( return None; } - // Only account for stable type parameters for now, unstable params can be default - // tho, for example in `Box<T, #[unstable] A: Allocator>` - if imp_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) - || fn_type_params.iter().any(|it| it.is_unstable(db) && it.default(db).is_none()) - { - return None; - } - - // Double check that we have fully known type - if ty.type_arguments().any(|it| it.contains_unknown()) { + // Ignore functions with generics for now as they kill the performance + // Also checking bounds for generics is problematic + if !fn_generics.type_or_const_params(db).is_empty() { return None; } - let non_default_fn_type_params_len = - fn_type_params.iter().filter(|it| it.default(db).is_none()).count(); - - // Ignore functions with generics for now as they kill the performance - // Also checking bounds for generics is problematic - if non_default_fn_type_params_len > 0 { + let ret_ty = it.ret_type_with_args(db, ty.type_arguments()); + // Filter out functions that return references + if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) || ret_ty.is_raw_ptr() + { return None; } - let generic_params = lookup - .iter_types() - .collect::<Vec<_>>() // Force take ownership + // Early exit if some param cannot be filled from lookup + let param_exprs: Vec<Vec<Expr>> = it + .params_without_self_with_args(db, ty.type_arguments()) .into_iter() - .permutations(non_default_fn_type_params_len); - - let exprs: Vec<_> = generic_params - .filter(|_| should_continue()) - .filter_map(|generics| { - // Insert default type params - let mut g = generics.into_iter(); - let generics: Vec<_> = ty - .type_arguments() - .map(Some) - .chain(fn_type_params.iter().map(|it| match it.default(db) { - Some(ty) => Some(ty), - None => { - let generic = g.next().expect("Missing type param"); - it.trait_bounds(db) - .into_iter() - .all(|bound| generic.impls_trait(db, bound, &[])); - // Filter out generics that do not unify due to trait bounds - it.ty(db).could_unify_with(db, &generic).then_some(generic) - } - })) - .collect::<Option<_>>()?; - - let ret_ty = it.ret_type_with_args( - db, - ty.type_arguments().chain(generics.iter().cloned()), - ); - // Filter out functions that return references - if ctx.config.enable_borrowcheck && ret_ty.contains_reference(db) - || ret_ty.is_raw_ptr() - { - return None; - } + .map(|field| lookup.find_autoref(db, field.ty())) + .collect::<Option<_>>()?; + + // Note that we need special case for 0 param constructors because of multi cartesian + // product + let generics = ty.type_arguments().collect(); + let fn_exprs: Vec<Expr> = if param_exprs.is_empty() { + vec![Expr::Function { func: it, generics, params: Vec::new() }] + } else { + param_exprs + .into_iter() + .multi_cartesian_product() + .map(|params| Expr::Function { func: it, generics: generics.clone(), params }) + .collect() + }; - // Ignore functions that do not change the type - // if ty.could_unify_with_deeply(db, &ret_ty) { - // return None; - // } - - // Early exit if some param cannot be filled from lookup - let param_exprs: Vec<Vec<Expr>> = it - .params_without_self_with_args( - db, - ty.type_arguments().chain(generics.iter().cloned()), - ) - .into_iter() - .map(|field| lookup.find_autoref(db, field.ty())) - .collect::<Option<_>>()?; - - // Note that we need special case for 0 param constructors because of multi cartesian - // product - let fn_exprs: Vec<Expr> = if param_exprs.is_empty() { - vec![Expr::Function { func: it, generics, params: Vec::new() }] - } else { - param_exprs - .into_iter() - .multi_cartesian_product() - .map(|params| Expr::Function { - func: it, - generics: generics.clone(), - params, - }) - .collect() - }; + lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned()); - lookup.insert(ret_ty.clone(), fn_exprs.iter().cloned()); - Some((ret_ty, fn_exprs)) - }) - .collect(); - Some(exprs) + Some((ret_ty, fn_exprs)) }) - .flatten() .filter_map(|(ty, exprs)| ty.could_unify_with_deeply(db, &ctx.goal).then_some(exprs)) .flatten() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs index 5d76cb04323..f1de6aba05b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs @@ -15,6 +15,8 @@ pub struct AssistConfig { pub insert_use: InsertUseConfig, pub prefer_no_std: bool, pub prefer_prelude: bool, + pub prefer_absolute: bool, pub assist_emit_must_use: bool, pub term_search_fuel: u64, + pub term_search_borrowck: bool, } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 22a4674fd46..4eb29a2378a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -74,6 +74,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let module = ctx.sema.scope(expr.syntax())?.module(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 363aa142b25..327709b28a3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -1,7 +1,7 @@ use either::Either; use ide_db::defs::{Definition, NameRefClass}; use syntax::{ - ast::{self, make, HasArgList}, + ast::{self, make, HasArgList, HasGenericArgs}, ted, AstNode, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index fe895eb2598..f17635972b7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -93,6 +93,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index c95e24693d4..ab25e0167bf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -1,3 +1,4 @@ +use either::Either; use hir::{ImportPathConfig, ModuleDef}; use ide_db::{ assists::{AssistId, AssistKind}, @@ -76,7 +77,11 @@ pub(crate) fn bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let usages = definition.usages(&ctx.sema).all(); add_enum_def(edit, ctx, &usages, target_node, &target_module); - replace_usages(edit, ctx, usages, definition, &target_module); + let mut delayed_mutations = Vec::new(); + replace_usages(edit, ctx, usages, definition, &target_module, &mut delayed_mutations); + for (scope, path) in delayed_mutations { + insert_use(&scope, path, &ctx.config.insert_use); + } }, ) } @@ -91,29 +96,32 @@ struct BoolNodeData { /// Attempts to find an appropriate node to apply the action to. fn find_bool_node(ctx: &AssistContext<'_>) -> Option<BoolNodeData> { - let name: ast::Name = ctx.find_node_at_offset()?; - - if let Some(let_stmt) = name.syntax().ancestors().find_map(ast::LetStmt::cast) { - let bind_pat = match let_stmt.pat()? { - ast::Pat::IdentPat(pat) => pat, - _ => { - cov_mark::hit!(not_applicable_in_non_ident_pat); - return None; - } - }; - let def = ctx.sema.to_def(&bind_pat)?; + let name = ctx.find_node_at_offset::<ast::Name>()?; + + if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { + let def = ctx.sema.to_def(&ident_pat)?; if !def.ty(ctx.db()).is_bool() { cov_mark::hit!(not_applicable_non_bool_local); return None; } - Some(BoolNodeData { - target_node: let_stmt.syntax().clone(), - name, - ty_annotation: let_stmt.ty(), - initializer: let_stmt.initializer(), - definition: Definition::Local(def), - }) + let local_definition = Definition::Local(def); + match ident_pat.syntax().parent().and_then(Either::<ast::Param, ast::LetStmt>::cast)? { + Either::Left(param) => Some(BoolNodeData { + target_node: param.syntax().clone(), + name, + ty_annotation: param.ty(), + initializer: None, + definition: local_definition, + }), + Either::Right(let_stmt) => Some(BoolNodeData { + target_node: let_stmt.syntax().clone(), + name, + ty_annotation: let_stmt.ty(), + initializer: let_stmt.initializer(), + definition: local_definition, + }), + } } else if let Some(const_) = name.syntax().parent().and_then(ast::Const::cast) { let def = ctx.sema.to_def(&const_)?; if !def.ty(ctx.db()).is_bool() { @@ -197,6 +205,7 @@ fn replace_usages( usages: UsageSearchResult, target_definition: Definition, target_module: &hir::Module, + delayed_mutations: &mut Vec<(ImportScope, ast::Path)>, ) { for (file_id, references) in usages { edit.edit_file(file_id); @@ -217,6 +226,7 @@ fn replace_usages( def.usages(&ctx.sema).all(), target_definition, target_module, + delayed_mutations, ) } } else if let Some(initializer) = find_assignment_usage(&name) { @@ -255,6 +265,7 @@ fn replace_usages( def.usages(&ctx.sema).all(), target_definition, target_module, + delayed_mutations, ) } } @@ -306,7 +317,7 @@ fn replace_usages( ImportScope::Module(it) => ImportScope::Module(edit.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(edit.make_mut(it)), }; - insert_use(&scope, path, &ctx.config.insert_use); + delayed_mutations.push((scope, path)); } }, ) @@ -329,6 +340,7 @@ fn augment_references_with_imports( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; references @@ -449,7 +461,20 @@ fn add_enum_def( usages: &UsageSearchResult, target_node: SyntaxNode, target_module: &hir::Module, -) { +) -> Option<()> { + let insert_before = node_to_insert_before(target_node); + + if ctx + .sema + .scope(&insert_before)? + .module() + .scope(ctx.db(), Some(*target_module)) + .iter() + .any(|(name, _)| name.as_str() == Some("Bool")) + { + return None; + } + let make_enum_pub = usages .iter() .flat_map(|(_, refs)| refs) @@ -460,7 +485,6 @@ fn add_enum_def( .any(|module| module.nearest_non_block_module(ctx.db()) != *target_module); let enum_def = make_bool_enum(make_enum_pub); - let insert_before = node_to_insert_before(target_node); let indent = IndentLevel::from_node(&insert_before); enum_def.reindent_to(indent); @@ -468,6 +492,8 @@ fn add_enum_def( insert_before.text_range().start(), format!("{}\n\n{indent}", enum_def.syntax().text()), ); + + Some(()) } /// Finds where to put the new enum definition. @@ -518,6 +544,125 @@ mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; #[test] + fn parameter_with_first_param_usage() { + check_assist( + bool_to_enum, + r#" +fn function($0foo: bool, bar: bool) { + if foo { + println!("foo"); + } +} +"#, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn function(foo: Bool, bar: bool) { + if foo == Bool::True { + println!("foo"); + } +} +"#, + ) + } + + #[test] + fn no_duplicate_enums() { + check_assist( + bool_to_enum, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn function(foo: bool, $0bar: bool) { + if bar { + println!("bar"); + } +} +"#, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn function(foo: bool, bar: Bool) { + if bar == Bool::True { + println!("bar"); + } +} +"#, + ) + } + + #[test] + fn parameter_with_last_param_usage() { + check_assist( + bool_to_enum, + r#" +fn function(foo: bool, $0bar: bool) { + if bar { + println!("bar"); + } +} +"#, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn function(foo: bool, bar: Bool) { + if bar == Bool::True { + println!("bar"); + } +} +"#, + ) + } + + #[test] + fn parameter_with_middle_param_usage() { + check_assist( + bool_to_enum, + r#" +fn function(foo: bool, $0bar: bool, baz: bool) { + if bar { + println!("bar"); + } +} +"#, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn function(foo: bool, bar: Bool, baz: bool) { + if bar == Bool::True { + println!("bar"); + } +} +"#, + ) + } + + #[test] + fn parameter_with_closure_usage() { + check_assist( + bool_to_enum, + r#" +fn main() { + let foo = |$0bar: bool| bar; +} +"#, + r#" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn main() { + let foo = |bar: Bool| bar == Bool::True; +} +"#, + ) + } + + #[test] fn local_variable_with_usage() { check_assist( bool_to_enum, @@ -784,7 +929,6 @@ fn main() { #[test] fn local_variable_non_ident_pat() { - cov_mark::check!(not_applicable_in_non_ident_pat); check_assist_not_applicable( bool_to_enum, r#" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 5459bd334c8..67c72a93dad 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -1,7 +1,7 @@ use ide_db::{famous_defs::FamousDefs, traits::resolve_target_trait}; use itertools::Itertools; use syntax::{ - ast::{self, make, AstNode, HasName}, + ast::{self, make, AstNode, HasGenericArgs, HasName}, ted, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs index be433c33338..5349e86cf38 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -1,6 +1,6 @@ use hir::ImportPathConfig; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait}; -use syntax::ast::{self, AstNode, HasName}; +use syntax::ast::{self, AstNode, HasGenericArgs, HasName}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -47,6 +47,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let src_type_path = { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 241fc3b7a37..c55ff24ae38 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -186,6 +186,7 @@ fn augment_references_with_imports( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; references diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 76188715524..666e1a1496e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -90,6 +90,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let module = ctx.sema.scope(ident_pat.syntax())?.module(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index de447c1e338..20c37f92337 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -216,6 +216,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 3c6d73b62e7..54323e2928e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -393,6 +393,7 @@ fn process_references( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ); if let Some(mut mod_path) = mod_path { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index 3612eda7847..dcf16e89b2c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -1,7 +1,7 @@ use either::Either; use ide_db::syntax_helpers::node_ext::walk_ty; use syntax::{ - ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName}, + ast::{self, edit::IndentLevel, make, AstNode, HasGenericArgs, HasGenericParams, HasName}, ted, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 19521b8a4b7..78def51a4a9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -17,8 +17,9 @@ use syntax::{ self, edit::{self, AstNodeEdit}, edit_in_place::AttrsOwnerEdit, - make, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericParams, HasName, - HasTypeBounds, HasVisibility as astHasVisibility, Path, WherePred, + make, AssocItem, GenericArgList, GenericParamList, HasAttrs, HasGenericArgs, + HasGenericParams, HasName, HasTypeBounds, HasVisibility as astHasVisibility, Path, + WherePred, }, ted::{self, Position}, AstNode, NodeOrToken, SmolStr, SyntaxKind, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index 9a441fc5ebc..cc33439dd59 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -64,6 +64,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; @@ -111,6 +112,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index 38b24fd19ca..51dd4884547 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use stdx::{format_to, to_lower_snake_case}; use syntax::{ algo::skip_whitespace_token, - ast::{self, edit::IndentLevel, HasDocComments, HasName}, + ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName}, match_ast, AstNode, AstToken, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index 52007e0e297..6056c808880 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -65,6 +65,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 88fa6dc745e..8c9fe23bb0b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -15,7 +15,9 @@ use ide_db::{ }; use itertools::{izip, Itertools}; use syntax::{ - ast::{self, edit::IndentLevel, edit_in_place::Indent, HasArgList, Pat, PathExpr}, + ast::{ + self, edit::IndentLevel, edit_in_place::Indent, HasArgList, HasGenericArgs, Pat, PathExpr, + }, ted, AstNode, NodeOrToken, SyntaxKind, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index 797c5c06533..7f751c93e48 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -490,6 +490,25 @@ use foo::bar; } #[test] + fn test_merge_nested_empty_and_self_with_other() { + check_assist( + merge_imports, + r" +use foo::$0{bar}; +use foo::{bar::{self, other}}; +", + r" +use foo::bar::{self, other}; +", + ); + check_assist_import_one_variations!( + "foo::$0{bar}", + "foo::{bar::{self, other}}", + "use {foo::bar::{self, other}};" + ); + } + + #[test] fn test_merge_nested_list_self_and_glob() { check_assist( merge_imports, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs index 7d003efe721..0b91eb676df 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/normalize_import.rs @@ -120,9 +120,38 @@ mod tests { } #[test] + fn test_braces_kept() { + check_assist_not_applicable_variations!("foo::bar::{$0self}"); + + // This code compiles but transforming "bar::{self}" into "bar" causes a + // compilation error (the name `bar` is defined multiple times). + // Therefore, the normalize_input assist must not apply here. + check_assist_not_applicable( + normalize_import, + r" +mod foo { + + pub mod bar {} + + pub const bar: i32 = 8; +} + +use foo::bar::{$0self}; + +const bar: u32 = 99; + +fn main() { + let local_bar = bar; +} + +", + ); + } + + #[test] fn test_redundant_braces() { check_assist_variations!("foo::{bar::{baz, Qux}}", "foo::bar::{baz, Qux}"); - check_assist_variations!("foo::{bar::{self}}", "foo::bar"); + check_assist_variations!("foo::{bar::{self}}", "foo::bar::{self}"); check_assist_variations!("foo::{bar::{*}}", "foo::bar::*"); check_assist_variations!("foo::{bar::{Qux as Quux}}", "foo::bar::Qux as Quux"); check_assist_variations!( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs index 5d1140d57ac..89e24fafc55 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -53,6 +53,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs index 978b719c30a..4164a4c1024 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs @@ -6,6 +6,7 @@ use ide_db::{ helpers::mod_path_to_ast, imports::import_assets::{ImportCandidate, LocatedImport}, }; +use syntax::ast::HasGenericArgs; use syntax::{ ast, ast::{make, HasArgList}, @@ -40,6 +41,7 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let mut proposed_imports: Vec<_> = diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs index 799d36be93e..f74fc261128 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_parentheses.rs @@ -239,4 +239,33 @@ mod tests { check_assist_not_applicable(remove_parentheses, r#"fn f() { $0(return 2) + 2 }"#); } + + #[test] + fn remove_parens_indirect_calls() { + check_assist( + remove_parentheses, + r#"fn f(call: fn(usize), arg: usize) { $0(call)(arg); }"#, + r#"fn f(call: fn(usize), arg: usize) { call(arg); }"#, + ); + check_assist( + remove_parentheses, + r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { $0(call)(arg); }"#, + r#"fn f<F>(call: F, arg: usize) where F: Fn(usize) { call(arg); }"#, + ); + + // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union. + check_assist_not_applicable( + remove_parentheses, + r#" +struct Foo<T> { + t: T, +} + +impl Foo<fn(usize)> { + fn foo(&self, arg: usize) { + $0(self.t)(arg); + } +}"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index e792debaa51..5582256a170 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -89,6 +89,7 @@ pub(crate) fn replace_derive_with_manual_impl( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) .as_ref() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 188165e7764..b4e1a49aab5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -4,7 +4,7 @@ use ide_db::{ imports::insert_use::{insert_use, ImportScope}, }; use syntax::{ - ast::{self, make}, + ast::{self, make, HasGenericArgs}, match_ast, ted, AstNode, SyntaxNode, }; @@ -70,6 +70,7 @@ pub(crate) fn replace_qualified_name_with_use( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 1794c887439..3a6391cd380 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -1,7 +1,6 @@ use hir::HirDisplay; use syntax::{ - ast::{Expr, GenericArg, GenericArgList}, - ast::{LetStmt, Type::InferType}, + ast::{Expr, GenericArg, GenericArgList, HasGenericArgs, LetStmt, Type::InferType}, AstNode, TextRange, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index 8a9229c549f..7a911799757 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -37,7 +37,11 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< sema: &ctx.sema, scope: &scope, goal: target_ty, - config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() }, + config: TermSearchConfig { + fuel: ctx.config.term_search_fuel, + enable_borrowcheck: ctx.config.term_search_borrowck, + ..Default::default() + }, }; let paths = hir::term_search::term_search(&term_search_ctx); @@ -56,6 +60,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) .ok() @@ -144,7 +149,7 @@ fn f() { let a = A { x: 1, y: true }; let b: i32 = a.x; }"#, term_search, r#"//- minicore: todo, unimplemented, option fn f() { let a: i32 = 1; let b: Option<i32> = todo$0!(); }"#, - r#"fn f() { let a: i32 = 1; let b: Option<i32> = None; }"#, + r#"fn f() { let a: i32 = 1; let b: Option<i32> = Some(a); }"#, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs index 30e09648ea1..31d18a60138 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -4,7 +4,7 @@ use ide_db::{ famous_defs::FamousDefs, }; use syntax::{ - ast::{self, HasVisibility}, + ast::{self, HasGenericArgs, HasVisibility}, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, }; @@ -142,6 +142,7 @@ pub(crate) fn desugar_async_into_impl_future( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; let trait_path = trait_path.display(ctx.db()); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs index 8a9e669630b..a1987247cb6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs @@ -4,7 +4,7 @@ use ide_db::{ }; use itertools::Itertools; use syntax::{ - ast::{self, Expr}, + ast::{self, Expr, HasGenericArgs}, match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index abebdec1d18..685d230dc6f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -58,8 +58,6 @@ //! See also this post: //! <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html> -#![warn(rust_2018_idioms, unused_lifetimes)] - mod assist_config; mod assist_context; #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 3b6c9512511..2dcfda334b8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -30,8 +30,10 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, assist_emit_must_use: false, term_search_fuel: 400, + term_search_borrowck: true, }; pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { @@ -46,8 +48,10 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, assist_emit_must_use: false, term_search_fuel: 400, + term_search_borrowck: true, }; pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { @@ -62,8 +66,10 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, assist_emit_must_use: false, term_search_fuel: 400, + term_search_borrowck: true, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index eec1087e2df..a2287b2977d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1,4 +1,4 @@ -//! Generated by `sourcegen_assists_docs`, do not edit by hand. +//! Generated by `cargo codegen assists-doc-tests`, do not edit by hand. use super::check_doc_test; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 11ffc8bc441..995a4443edf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -639,6 +639,7 @@ fn enum_variants_with_paths( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) { // Variants with trivial paths are already added by the existing completion logic, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index 7281c607da4..01f9368aa4e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -177,6 +177,7 @@ pub(crate) fn complete_expr_path( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) .filter(|it| it.len() > 1); @@ -202,6 +203,7 @@ pub(crate) fn complete_expr_path( ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) .filter(|it| it.len() > 1); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index 71d44a57cb9..3a8b9c0cb97 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -259,6 +259,7 @@ fn import_on_the_fly( let import_cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; import_assets @@ -309,6 +310,7 @@ fn import_on_the_fly_pat_( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; import_assets @@ -354,6 +356,7 @@ fn import_on_the_fly_method( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; import_assets diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index d67c00c6c69..a59246229bb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -173,7 +173,8 @@ fn should_add_self_completions( } fn comma_wrapper(ctx: &CompletionContext<'_>) -> Option<(impl Fn(&str) -> String, TextRange)> { - let param = ctx.token.parent_ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?; + let param = + ctx.original_token.parent_ancestors().find(|node| node.kind() == SyntaxKind::PARAM)?; let next_token_kind = { let t = param.last_token()?.next_token()?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs index 02298b1e9b0..18833774083 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs @@ -82,17 +82,30 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none(); let in_block = kind.is_none(); + let missing_qualifiers = [ + ctx.qualifier_ctx.unsafe_tok.is_none().then_some(("unsafe", "unsafe $0")), + ctx.qualifier_ctx.async_tok.is_none().then_some(("async", "async $0")), + ]; + if !in_trait_impl { - if ctx.qualifier_ctx.unsafe_tok.is_some() { + // handle qualifier tokens + if missing_qualifiers.iter().any(Option::is_none) { + // only complete missing qualifiers + missing_qualifiers.iter().filter_map(|x| *x).for_each(|(kw, snippet)| { + add_keyword(kw, snippet); + }); + if in_item_list || in_assoc_non_trait_impl { add_keyword("fn", "fn $1($2) {\n $0\n}"); } - if in_item_list { + + if ctx.qualifier_ctx.unsafe_tok.is_some() && in_item_list { add_keyword("trait", "trait $1 {\n $0\n}"); if no_vis_qualifiers { add_keyword("impl", "impl $1 {\n $0\n}"); } } + return; } @@ -100,7 +113,6 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option add_keyword("enum", "enum $1 {\n $0\n}"); add_keyword("mod", "mod $0"); add_keyword("static", "static $0"); - add_keyword("async", "async $0"); add_keyword("struct", "struct $0"); add_keyword("trait", "trait $1 {\n $0\n}"); add_keyword("union", "union $1 {\n $0\n}"); @@ -129,6 +141,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option add_keyword("fn", "fn $1($2) {\n $0\n}"); add_keyword("unsafe", "unsafe $0"); add_keyword("const", "const $0"); + add_keyword("async", "async $0"); } } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index d79b5398828..3f50cd55cb3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -57,6 +57,7 @@ mod tests { check( r"fn my_fn() { unsafe $0 }", expect![[r#" + kw async kw fn kw impl kw trait diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 5041ef8d8a1..d919609237a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -63,6 +63,7 @@ pub(crate) fn complete_postfix( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index 809c305ed82..7d062cb23e5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -22,6 +22,7 @@ pub struct CompletionConfig { pub insert_use: InsertUseConfig, pub prefer_no_std: bool, pub prefer_prelude: bool, + pub prefer_absolute: bool, pub snippets: Vec<Snippet>, pub limit: Option<usize>, } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 992ca18bb06..5782a4423a6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -46,13 +46,15 @@ pub(crate) enum Visible { /// Existing qualifiers for the thing we are currently completing. #[derive(Debug, Default)] pub(crate) struct QualifierCtx { + // TODO: Add try_tok and default_tok + pub(crate) async_tok: Option<SyntaxToken>, pub(crate) unsafe_tok: Option<SyntaxToken>, pub(crate) vis_node: Option<ast::Visibility>, } impl QualifierCtx { pub(crate) fn none(&self) -> bool { - self.unsafe_tok.is_none() && self.vis_node.is_none() + self.async_tok.is_none() && self.unsafe_tok.is_none() && self.vis_node.is_none() } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 80ce5bd4cf2..a14fe24fa75 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -6,7 +6,10 @@ use ide_db::{active_parameter::ActiveParameter, RootDatabase}; use itertools::Either; use syntax::{ algo::{ancestors_at_offset, find_node_at_offset, non_trivia_sibling}, - ast::{self, AttrKind, HasArgList, HasGenericParams, HasLoopBody, HasName, NameOrNameRef}, + ast::{ + self, AttrKind, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, + NameOrNameRef, + }, match_ast, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, T, }; @@ -1287,10 +1290,15 @@ fn classify_name_ref( syntax::algo::non_trivia_sibling(top.clone().into(), syntax::Direction::Prev) { if error_node.kind() == SyntaxKind::ERROR { - qualifier_ctx.unsafe_tok = error_node - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|it| it.kind() == T![unsafe]); + for token in + error_node.children_with_tokens().filter_map(NodeOrToken::into_token) + { + match token.kind() { + SyntaxKind::UNSAFE_KW => qualifier_ctx.unsafe_tok = Some(token), + SyntaxKind::ASYNC_KW => qualifier_ctx.async_tok = Some(token), + _ => {} + } + } qualifier_ctx.vis_node = error_node.children().find_map(ast::Visibility::cast); } } @@ -1334,7 +1342,7 @@ fn pattern_context_for( .map_or((PatternRefutability::Irrefutable, false), |node| { let refutability = match_ast! { match node { - ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()), + ast::LetStmt(let_) => return (PatternRefutability::Refutable, let_.ty().is_some()), ast::Param(param) => { let has_type_ascription = param.ty().is_some(); param_ctx = (|| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 8323b8f9331..7d9c2c7c60d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -1,7 +1,5 @@ //! `completions` crate provides utilities for generating completions of user input. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod completions; mod config; mod context; @@ -255,6 +253,7 @@ pub fn resolve_completion_edits( let cfg = ImportPathConfig { prefer_no_std: config.prefer_no_std, prefer_prelude: config.prefer_prelude, + prefer_absolute: config.prefer_absolute, }; imports.into_iter().for_each(|(full_import_path, imported_name)| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index ebdc813f3d7..fe9e2e5268a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -298,6 +298,7 @@ pub(crate) fn render_expr( let cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg).ok()?; @@ -764,6 +765,7 @@ fn main() { "#, expect![[r#" st dep::test_mod_b::Struct {…} [type_could_unify] + ex dep::test_mod_b::Struct { } [type_could_unify] st Struct (use dep::test_mod_b::Struct) [type_could_unify+requires_import] fn main() [] fn test(…) [] @@ -839,6 +841,7 @@ fn main() { "#, expect![[r#" ev dep::test_mod_b::Enum::variant [type_could_unify] + ex dep::test_mod_b::Enum::variant [type_could_unify] en Enum (use dep::test_mod_b::Enum) [type_could_unify+requires_import] fn main() [] fn test(…) [] @@ -876,6 +879,7 @@ fn main() { "#, expect![[r#" ev dep::test_mod_b::Enum::Variant [type_could_unify] + ex dep::test_mod_b::Enum::Variant [type_could_unify] fn main() [] fn test(…) [] md dep [] @@ -1839,7 +1843,6 @@ fn f() { A { bar: b$0 }; } fn baz() [type] ex baz() [type] ex bar() [type] - ex A { bar: ... }.bar [type] st A [] fn f() [] "#]], @@ -1978,7 +1981,6 @@ fn main() { "#, expect![[r#" ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify] - ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify] lc m [local] lc t [local] lc &t [type+local] @@ -2028,7 +2030,6 @@ fn main() { "#, expect![[r#" ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify] - ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify] lc m [local] lc t [local] lc &mut t [type+local] @@ -2132,7 +2133,6 @@ fn main() { } "#, expect![[r#" - ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify] ex core::ops::Deref::deref(&bar()) (use core::ops::Deref) [type_could_unify] st S [] st &S [type] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs index 07836040b48..5885b74e09d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs @@ -172,6 +172,7 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<V let import_cfg = ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }; let resolve = |import: &GreenNode| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index c1a67315b75..fcac6c7ce72 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -79,6 +79,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, snippets: Vec::new(), limit: None, }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index abffa73c3b4..7d9c1ed98ac 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -871,6 +871,38 @@ fn main() { } #[test] +fn config_prefer_absolute() { + let fixture = r#" +//- /lib.rs crate:dep +pub mod foo { + pub mod bar { + pub struct Item; + } +} + +//- /main.rs crate:main deps:dep +use ::dep::foo::bar; + +fn main() { + Ite$0 +}"#; + let mut config = TEST_CONFIG; + config.prefer_absolute = true; + + check_edit_with_config( + config.clone(), + "Item", + fixture, + r#" +use ::dep::foo::bar::{self, Item}; + +fn main() { + Item +}"#, + ); +} + +#[test] fn unresolved_qualifier() { let fixture = r#" mod foo { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index c37900478e1..f138938b02b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -123,6 +123,7 @@ fn after_unsafe_token() { check( r#"unsafe $0"#, expect![[r#" + kw async kw fn kw impl kw trait @@ -131,6 +132,17 @@ fn after_unsafe_token() { } #[test] +fn after_async_token() { + check( + r#"async $0"#, + expect![[r#" + kw fn + kw unsafe + "#]], + ); +} + +#[test] fn after_visibility() { check( r#"pub $0"#, @@ -157,6 +169,7 @@ fn after_visibility_unsafe() { check( r#"pub unsafe $0"#, expect![[r#" + kw async kw fn kw trait "#]], @@ -170,6 +183,7 @@ fn in_impl_assoc_item_list() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn @@ -189,6 +203,7 @@ fn in_impl_assoc_item_list_after_attr() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn @@ -208,6 +223,7 @@ fn in_trait_assoc_item_list() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn @@ -225,6 +241,7 @@ fn in_trait_assoc_fn_missing_body() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn @@ -242,6 +259,7 @@ fn in_trait_assoc_const_missing_body() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn @@ -259,6 +277,7 @@ fn in_trait_assoc_type_aliases_missing_ty() { expect![[r#" ma makro!(…) macro_rules! makro md module + kw async kw const kw crate:: kw fn diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 8720cb555a1..6a0b67e291a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -146,7 +146,7 @@ enum SingleVariantEnum { } use SingleVariantEnum::Variant; fn foo() { - let a$0 + for a$0 } "#, expect![[r#" diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 088d2ec5e3f..42a80d63b1a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -79,8 +79,9 @@ pub fn generic_def_for_node( sema: &Semantics<'_, RootDatabase>, generic_arg_list: &ast::GenericArgList, token: &SyntaxToken, -) -> Option<(hir::GenericDef, usize, bool)> { +) -> Option<(hir::GenericDef, usize, bool, Option<hir::Variant>)> { let parent = generic_arg_list.syntax().parent()?; + let mut variant = None; let def = match_ast! { match parent { ast::PathSegment(ps) => { @@ -91,7 +92,10 @@ pub fn generic_def_for_node( hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::TraitAlias(it)) => it.into(), hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(), - hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(), + hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => { + variant = Some(it); + it.parent_enum(sema.db).into() + }, hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_)) | hir::PathResolution::Def(hir::ModuleDef::Const(_)) | hir::PathResolution::Def(hir::ModuleDef::Macro(_)) @@ -134,5 +138,5 @@ pub fn generic_def_for_node( .next() .map_or(false, |arg| !matches!(arg, ast::GenericArg::LifetimeArg(_))); - Some((def, active_param, first_arg_is_non_lifetime)) + Some((def, active_param, first_arg_is_non_lifetime, variant)) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index 7755a9b9748..0504f3caf5f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -1,4 +1,4 @@ -//! Generated by `sourcegen_lints`, do not edit by hand. +//! Generated by `cargo codegen lint-definitions`, do not edit by hand. #[derive(Clone)] pub struct Lint { @@ -50,6 +50,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects pattern bindings with the same name as one of the matched variants"##, }, Lint { + label: "boxed_slice_into_iter", + description: r##"detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021"##, + }, + Lint { label: "break_with_label_and_loop", description: r##"`break` expression with label and unlabeled loop as value expression"##, }, @@ -78,6 +82,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects visually confusable pairs between identifiers"##, }, Lint { + label: "const_eval_mutable_ptr_in_final_value", + description: r##"detects a mutable pointer that has leaked into final value of a const expression"##, + }, + Lint { label: "const_evaluatable_unchecked", description: r##"detects a generic constant is used in a type without a emitting a warning"##, }, @@ -86,6 +94,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects attempts to mutate a `const` item"##, }, Lint { label: "dead_code", description: r##"detect unused, unexported items"## }, + Lint { + label: "dependency_on_unit_never_type_fallback", + description: r##"never type fallback affecting unsafe function calls"##, + }, Lint { label: "deprecated", description: r##"detects use of deprecated items"## }, Lint { label: "deprecated_cfg_attr_crate_type_name", @@ -96,6 +108,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects use of items that will be deprecated in a future version"##, }, Lint { + label: "deprecated_safe", + description: r##"detects unsafe functions being used as safe functions"##, + }, + Lint { label: "deprecated_where_clause_location", description: r##"deprecated where clause location"##, }, @@ -171,7 +187,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-eval-mutable-ptr-in-final-value, const-evaluatable-unchecked, dependency-on-unit-never-type-fallback, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, never-type-fallback-flowing-into-unsafe, order-dependent-trait-objects, patterns-in-fns-without-body, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, self-constructor-from-outer-item, semicolon-in-expressions-from-macros, soft-unstable, uncovered-param-in-projection, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, wasm-c-abi, writes-through-immutable-pointer"##, }, Lint { label: "fuzzy_provenance_casts", @@ -186,6 +202,14 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"ill-formed attribute inputs that were previously accepted and used in practice"##, }, Lint { + label: "impl_trait_overcaptures", + description: r##"`impl Trait` will capture more lifetimes than possibly intended in edition 2024"##, + }, + Lint { + label: "impl_trait_redundant_captures", + description: r##"redundant precise-capturing `use<...>` syntax on an `impl Trait`"##, + }, + Lint { label: "improper_ctypes", description: r##"proper use of libc types in foreign modules"##, }, @@ -199,10 +223,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "incomplete_include", description: r##"trailing content in included file"## }, Lint { - label: "indirect_structural_match", - description: r##"constant used in pattern contains value of non-structural-match type in a field or a variant"##, - }, - Lint { label: "ineffective_unstable_trait_impl", description: r##"detects `#[unstable]` on stable trait implementations for stable types"##, }, @@ -256,6 +276,14 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "keyword_idents", + description: r##"lint group for: keyword-idents-2018, keyword-idents-2024"##, + }, + Lint { + label: "keyword_idents_2018", + description: r##"detects edition keywords being used as an identifier"##, + }, + Lint { + label: "keyword_idents_2024", description: r##"detects edition keywords being used as an identifier"##, }, Lint { label: "large_assignments", description: r##"detects large moves or copies"## }, @@ -321,6 +349,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detects missing fragment specifiers in unused `macro_rules!` patterns"##, }, Lint { + label: "missing_unsafe_on_extern", + description: r##"detects missing unsafe keyword on extern declarations"##, + }, + Lint { label: "mixed_script_confusables", description: r##"detects Unicode scripts whose mixed script confusables codepoints are solely used"##, }, @@ -342,6 +374,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "named_asm_labels", description: r##"named labels in inline assembly"## }, Lint { + label: "never_type_fallback_flowing_into_unsafe", + description: r##"never type fallback affecting unsafe function calls"##, + }, + Lint { label: "no_mangle_const_items", description: r##"const items will not have their symbols exported"##, }, @@ -352,6 +388,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"types, variants, traits and type parameters should have camel case names"##, }, Lint { + label: "non_contiguous_range_endpoints", + description: r##"detects off-by-one errors with exclusive range patterns"##, + }, + Lint { label: "non_exhaustive_omitted_patterns", description: r##"detect when patterns of types marked `non_exhaustive` are missed"##, }, @@ -399,10 +439,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"patterns in functions without body were erroneously allowed"##, }, Lint { - label: "pointer_structural_match", - description: r##"pointers are not structural-match"##, - }, - Lint { label: "private_bounds", description: r##"private type in secondary interface of an item"##, }, @@ -411,10 +447,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"private type in primary interface of an item"##, }, Lint { - label: "proc_macro_back_compat", - description: r##"detects usage of old versions of certain proc-macro crates"##, - }, - Lint { label: "proc_macro_derive_resolution_fallback", description: r##"detects proc macro derives using inaccessible names from parent modules"##, }, @@ -423,11 +455,23 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"detect public re-exports of private extern crates"##, }, Lint { + label: "redundant_lifetimes", + description: r##"detects lifetime parameters that are redundant because they are equal to some other named lifetime"##, + }, + Lint { label: "redundant_semicolons", description: r##"detects unnecessary trailing semicolons"##, }, Lint { label: "refining_impl_trait", + description: r##"lint group for: refining-impl-trait-reachable, refining-impl-trait-internal"##, + }, + Lint { + label: "refining_impl_trait_internal", + description: r##"impl trait in impl method signature does not match trait method signature"##, + }, + Lint { + label: "refining_impl_trait_reachable", description: r##"impl trait in impl method signature does not match trait method signature"##, }, Lint { @@ -440,7 +484,7 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "rust_2018_compatibility", - description: r##"lint group for: keyword-idents, anonymous-parameters, absolute-paths-not-starting-with-crate, tyvar-behind-raw-pointer"##, + description: r##"lint group for: keyword-idents-2018, anonymous-parameters, absolute-paths-not-starting-with-crate, tyvar-behind-raw-pointer"##, }, Lint { label: "rust_2018_idioms", @@ -468,7 +512,15 @@ pub const DEFAULT_LINTS: &[Lint] = &[ }, Lint { label: "rust_2024_compatibility", - description: r##"lint group for: static-mut-refs, unsafe-op-in-unsafe-fn"##, + description: r##"lint group for: keyword-idents-2024, deprecated-safe, missing-unsafe-on-extern, static-mut-refs, unsafe-attr-outside-unsafe, unsafe-op-in-unsafe-fn, boxed-slice-into-iter"##, + }, + Lint { + label: "rust_2024_incompatible_pat", + description: r##"detects patterns whose meaning will change in Rust 2024"##, + }, + Lint { + label: "self_constructor_from_outer_item", + description: r##"detect unsupported use of `Self` from outer item"##, }, Lint { label: "semicolon_in_expressions_from_macros", @@ -547,6 +599,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"functions that cannot return without calling themselves"##, }, Lint { + label: "uncovered_param_in_projection", + description: r##"impl contains type parameters that are not covered"##, + }, + Lint { label: "undefined_naked_function_abi", description: r##"undefined naked function ABI"##, }, @@ -595,6 +651,10 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"`pub` items not reachable from crate root"##, }, Lint { + label: "unsafe_attr_outside_unsafe", + description: r##"detects unsafe attributes outside of unsafe"##, + }, + Lint { label: "unsafe_code", description: r##"usage of `unsafe` code and other potentially unsound constructs"##, }, @@ -714,8 +774,8 @@ pub const DEFAULT_LINTS: &[Lint] = &[ description: r##"lint group for: all lints that are set to issue warnings"##, }, Lint { - label: "where_clauses_object_safety", - description: r##"checks the object safety of where clauses"##, + label: "wasm_c_abi", + description: r##"detects dependencies that are incompatible with the Wasm C ABI"##, }, Lint { label: "while_true", @@ -731,7 +791,7 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "future_incompatible", - description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-evaluatable-unchecked, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, indirect-structural-match, invalid-doc-attributes, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, order-dependent-trait-objects, patterns-in-fns-without-body, pointer-structural-match, proc-macro-back-compat, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, semicolon-in-expressions-from-macros, soft-unstable, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, where-clauses-object-safety, writes-through-immutable-pointer"##, + description: r##"lint group for: deref-into-dyn-supertrait, ambiguous-associated-items, ambiguous-glob-imports, byte-slice-in-packed-struct-with-derive, cenum-impl-drop-cast, coherence-leak-check, conflicting-repr-hints, const-eval-mutable-ptr-in-final-value, const-evaluatable-unchecked, dependency-on-unit-never-type-fallback, deprecated-cfg-attr-crate-type-name, elided-lifetimes-in-associated-constant, forbidden-lint-groups, ill-formed-attribute-input, invalid-type-param-default, late-bound-lifetime-arguments, legacy-derive-helpers, macro-expanded-macro-exports-accessed-by-absolute-paths, missing-fragment-specifier, never-type-fallback-flowing-into-unsafe, order-dependent-trait-objects, patterns-in-fns-without-body, proc-macro-derive-resolution-fallback, pub-use-of-private-extern-crate, repr-transparent-external-private-fields, self-constructor-from-outer-item, semicolon-in-expressions-from-macros, soft-unstable, uncovered-param-in-projection, uninhabited-static, unstable-name-collisions, unstable-syntax-pre-expansion, unsupported-calling-conventions, wasm-c-abi, writes-through-immutable-pointer"##, }, children: &[ "deref_into_dyn_supertrait", @@ -741,37 +801,45 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ "cenum_impl_drop_cast", "coherence_leak_check", "conflicting_repr_hints", + "const_eval_mutable_ptr_in_final_value", "const_evaluatable_unchecked", + "dependency_on_unit_never_type_fallback", "deprecated_cfg_attr_crate_type_name", "elided_lifetimes_in_associated_constant", "forbidden_lint_groups", "ill_formed_attribute_input", - "indirect_structural_match", - "invalid_doc_attributes", "invalid_type_param_default", "late_bound_lifetime_arguments", "legacy_derive_helpers", "macro_expanded_macro_exports_accessed_by_absolute_paths", "missing_fragment_specifier", + "never_type_fallback_flowing_into_unsafe", "order_dependent_trait_objects", "patterns_in_fns_without_body", - "pointer_structural_match", - "proc_macro_back_compat", "proc_macro_derive_resolution_fallback", "pub_use_of_private_extern_crate", "repr_transparent_external_private_fields", + "self_constructor_from_outer_item", "semicolon_in_expressions_from_macros", "soft_unstable", + "uncovered_param_in_projection", "uninhabited_static", "unstable_name_collisions", "unstable_syntax_pre_expansion", "unsupported_calling_conventions", - "where_clauses_object_safety", + "wasm_c_abi", "writes_through_immutable_pointer", ], }, LintGroup { lint: Lint { + label: "keyword_idents", + description: r##"lint group for: keyword-idents-2018, keyword-idents-2024"##, + }, + children: &["keyword_idents_2018", "keyword_idents_2024"], + }, + LintGroup { + lint: Lint { label: "let_underscore", description: r##"lint group for: let-underscore-drop, let-underscore-lock"##, }, @@ -786,11 +854,18 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ }, LintGroup { lint: Lint { + label: "refining_impl_trait", + description: r##"lint group for: refining-impl-trait-reachable, refining-impl-trait-internal"##, + }, + children: &["refining_impl_trait_reachable", "refining_impl_trait_internal"], + }, + LintGroup { + lint: Lint { label: "rust_2018_compatibility", - description: r##"lint group for: keyword-idents, anonymous-parameters, absolute-paths-not-starting-with-crate, tyvar-behind-raw-pointer"##, + description: r##"lint group for: keyword-idents-2018, anonymous-parameters, absolute-paths-not-starting-with-crate, tyvar-behind-raw-pointer"##, }, children: &[ - "keyword_idents", + "keyword_idents_2018", "anonymous_parameters", "absolute_paths_not_starting_with_crate", "tyvar_behind_raw_pointer", @@ -828,9 +903,17 @@ pub const DEFAULT_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "rust_2024_compatibility", - description: r##"lint group for: static-mut-refs, unsafe-op-in-unsafe-fn"##, + description: r##"lint group for: keyword-idents-2024, deprecated-safe, missing-unsafe-on-extern, static-mut-refs, unsafe-attr-outside-unsafe, unsafe-op-in-unsafe-fn, boxed-slice-into-iter"##, }, - children: &["static_mut_refs", "unsafe_op_in_unsafe_fn"], + children: &[ + "keyword_idents_2024", + "deprecated_safe", + "missing_unsafe_on_extern", + "static_mut_refs", + "unsafe_attr_outside_unsafe", + "unsafe_op_in_unsafe_fn", + "boxed_slice_into_iter", + ], }, LintGroup { lint: Lint { @@ -1187,9 +1270,23 @@ This feature has no tracking issue, and is therefore likely internal to the comp label: "abi_vectorcall", description: r##"# `abi_vectorcall` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#124485] + +[#124485]: https://github.com/rust-lang/rust/issues/124485 ------------------------ + +Adds support for the Windows `"vectorcall"` ABI, the equivalent of `__vectorcall` in MSVC. + +```rust,ignore (only-windows-or-x86-or-x86-64) +extern "vectorcall" { + fn add_f64s(x: f64, y: f64) -> f64; +} + +fn main() { + println!("{}", add_f64s(2.0, 4.0)); +} +``` "##, }, Lint { @@ -1204,12 +1301,12 @@ The tracking issue for this feature is: [#40180] "##, }, Lint { - label: "absolute_path", - description: r##"# `absolute_path` + label: "acceptfilter", + description: r##"# `acceptfilter` -The tracking issue for this feature is: [#92750] +The tracking issue for this feature is: [#121891] -[#92750]: https://github.com/rust-lang/rust/issues/92750 +[#121891]: https://github.com/rust-lang/rust/issues/121891 ------------------------ "##, @@ -1234,6 +1331,34 @@ The tracking issue for this feature is: [#95174] [#95174]: https://github.com/rust-lang/rust/issues/95174 ------------------------ + +Allows for using more complex types for const parameters, such as structs or enums. + +```rust +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, PartialEq, Eq)] +enum Foo { + A, + B, + C, +} + +#[derive(ConstParamTy, PartialEq, Eq)] +struct Bar { + flag: bool, +} + +fn is_foo_a_and_bar_true<const F: Foo, const B: Bar>() -> bool { + match (F, B.flag) { + (Foo::A, true) => true, + _ => false, + } +} +``` "##, }, Lint { @@ -1380,6 +1505,28 @@ The tracking issue for this feature is: [#91583] "##, }, Lint { + label: "array_ptr_get", + description: r##"# `array_ptr_get` + +The tracking issue for this feature is: [#119834] + +[#119834]: https://github.com/rust-lang/rust/issues/119834 + +------------------------ +"##, + }, + Lint { + label: "array_repeat", + description: r##"# `array_repeat` + +The tracking issue for this feature is: [#126695] + +[#126695]: https://github.com/rust-lang/rust/issues/126695 + +------------------------ +"##, + }, + Lint { label: "array_try_from_fn", description: r##"# `array_try_from_fn` @@ -1483,6 +1630,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - M68k - CSKY - s390x +- Arm64EC ## Register classes @@ -1515,6 +1663,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | | s390x | `freg` | `f[0-15]` | `f` | +| Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | +| Arm64EC | `vreg` | `v[0-15]` | `w` | +| Arm64EC | `vreg_low16` | `v[0-15]` | `x` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -1550,6 +1701,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | +| Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | +| Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | ## Register aliases @@ -1582,6 +1735,12 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r29` | `rtb` | | CSKY | `r30` | `svbr` | | CSKY | `r31` | `tls` | +| Arm64EC | `x[0-30]` | `w[0-30]` | +| Arm64EC | `x29` | `fp` | +| Arm64EC | `x30` | `lr` | +| Arm64EC | `sp` | `wsp` | +| Arm64EC | `xzr` | `wzr` | +| Arm64EC | `v[0-15]` | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -1592,8 +1751,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output. | -| All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output. | +| All | `r19` (Hexagon), `x19` (Arm64EC) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | | MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | @@ -1609,6 +1768,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r15` | This is the link register. | | CSKY | `r[26-30]` | Reserved by its ABI. | | CSKY | `r31` | This is the TLS register. | +| Arm64EC | `xzr` | This is a constant zero register which can't be modified. | +| Arm64EC | `x18` | This is an OS-reserved register. | +| Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | ## Template modifiers @@ -1629,6 +1791,16 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | s390x | `freg` | None | `%f0` | None | | CSKY | `reg` | None | `r0` | None | | CSKY | `freg` | None | `f0` | None | +| Arm64EC | `reg` | None | `x0` | `x` | +| Arm64EC | `reg` | `w` | `w0` | `w` | +| Arm64EC | `reg` | `x` | `x0` | `x` | +| Arm64EC | `vreg` | None | `v0` | None | +| Arm64EC | `vreg` | `v` | `v0` | None | +| Arm64EC | `vreg` | `b` | `b0` | `b` | +| Arm64EC | `vreg` | `h` | `h0` | `h` | +| Arm64EC | `vreg` | `s` | `s0` | `s` | +| Arm64EC | `vreg` | `d` | `d0` | `d` | +| Arm64EC | `vreg` | `q` | `q0` | `q` | # Flags covered by `preserves_flags` @@ -1641,6 +1813,43 @@ These flags registers must be restored upon exiting the asm block if the `preser - The condition code register `ccr`. - s390x - The condition code register `cc`. +- Arm64EC + - Condition flags (`NZCV` register). + - Floating-point status (`FPSR` register). +"##, + }, + Lint { + label: "asm_goto", + description: r##"# `asm_goto` + +The tracking issue for this feature is: [#119364] + +[#119364]: https://github.com/rust-lang/rust/issues/119364 + +------------------------ + +This feature adds a `label <block>` operand type to `asm!`. + +Example: +```rust,ignore (partial-example, x86-only) + +unsafe { + asm!( + "jmp {}", + label { + println!("Jumped from asm!"); + } + ); +} +``` + +The block must have unit type or diverge. + +When `label <block>` is used together with `noreturn` option, it means that the +assembly will not fallthrough. It's allowed to jump to a label within the +assembly. In this case, the entire `asm!` expression will have an unit type as +opposed to diverging, if not all label blocks diverge. The `asm!` expression +still diverges if `noreturn` option is used and all label blocks diverge. "##, }, Lint { @@ -1679,17 +1888,6 @@ The tracking issue for this feature is: [#92827] "##, }, Lint { - label: "associated_type_bounds", - description: r##"# `associated_type_bounds` - -The tracking issue for this feature is: [#52662] - -[#52662]: https://github.com/rust-lang/rust/issues/52662 - ------------------------- -"##, - }, - Lint { label: "associated_type_defaults", description: r##"# `associated_type_defaults` @@ -1712,6 +1910,17 @@ The tracking issue for this feature is: [#62290] "##, }, Lint { + label: "async_drop", + description: r##"# `async_drop` + +The tracking issue for this feature is: [#126482] + +[#126482]: https://github.com/rust-lang/rust/issues/126482 + +------------------------ +"##, + }, + Lint { label: "async_fn_track_caller", description: r##"# `async_fn_track_caller` @@ -1736,7 +1945,7 @@ for creating custom closure-like types that return futures. [`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future -that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does). +that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFnMut::CallRefFuture` does). "##, }, Lint { @@ -1782,17 +1991,6 @@ The tracking issue for this feature is: [#79024] "##, }, Lint { - label: "atomic_bool_fetch_not", - description: r##"# `atomic_bool_fetch_not` - -The tracking issue for this feature is: [#98485] - -[#98485]: https://github.com/rust-lang/rust/issues/98485 - ------------------------- -"##, - }, - Lint { label: "atomic_from_mut", description: r##"# `atomic_from_mut` @@ -1947,17 +2145,6 @@ The tracking issue for this feature is: [#85532] "##, }, Lint { - label: "binary_heap_as_slice", - description: r##"# `binary_heap_as_slice` - -The tracking issue for this feature is: [#83659] - -[#83659]: https://github.com/rust-lang/rust/issues/83659 - ------------------------- -"##, - }, - Lint { label: "binary_heap_drain_sorted", description: r##"# `binary_heap_drain_sorted` @@ -2113,23 +2300,23 @@ The tracking issue for this feature is: [#111735] "##, }, Lint { - label: "builtin_syntax", - description: r##"# `builtin_syntax` + label: "build_hasher_default_const_new", + description: r##"# `build_hasher_default_const_new` -The tracking issue for this feature is: [#110680] +The tracking issue for this feature is: [#123197] -[#110680]: https://github.com/rust-lang/rust/issues/110680 +[#123197]: https://github.com/rust-lang/rust/issues/123197 ------------------------ "##, }, Lint { - label: "byte_slice_trim_ascii", - description: r##"# `byte_slice_trim_ascii` + label: "builtin_syntax", + description: r##"# `builtin_syntax` -The tracking issue for this feature is: [#94035] +The tracking issue for this feature is: [#110680] -[#94035]: https://github.com/rust-lang/rust/issues/94035 +[#110680]: https://github.com/rust-lang/rust/issues/110680 ------------------------ "##, @@ -2146,33 +2333,14 @@ The tracking issue for this feature is: [#88345] "##, }, Lint { - label: "c_unwind", - description: r##"# `c_unwind` + label: "c_str_module", + description: r##"# `c_str_module` -The tracking issue for this feature is: [#74990] +The tracking issue for this feature is: [#112134] -[#74990]: https://github.com/rust-lang/rust/issues/74990 +[#112134]: https://github.com/rust-lang/rust/issues/112134 ------------------------ - -Introduces new ABI strings: -- "C-unwind" -- "cdecl-unwind" -- "stdcall-unwind" -- "fastcall-unwind" -- "vectorcall-unwind" -- "thiscall-unwind" -- "aapcs-unwind" -- "win64-unwind" -- "sysv64-unwind" -- "system-unwind" - -These enable unwinding from other languages (such as C++) into Rust frames and -from Rust into other languages. - -See [RFC 2945] for more information. - -[RFC 2945]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md "##, }, Lint { @@ -2424,6 +2592,17 @@ The tracking issue for this feature is: [#29594] "##, }, Lint { + label: "cfg_ub_checks", + description: r##"# `cfg_ub_checks` + +The tracking issue for this feature is: [#123499] + +[#123499]: https://github.com/rust-lang/rust/issues/123499 + +------------------------ +"##, + }, + Lint { label: "cfg_version", description: r##"# `cfg_version` @@ -2523,6 +2702,17 @@ The tracking issue for this feature is: [#114298] "##, }, Lint { + label: "clone_to_uninit", + description: r##"# `clone_to_uninit` + +The tracking issue for this feature is: [#126799] + +[#126799]: https://github.com/rust-lang/rust/issues/126799 + +------------------------ +"##, + }, + Lint { label: "closure_lifetime_binder", description: r##"# `closure_lifetime_binder` @@ -2657,17 +2847,6 @@ The tracking issue for this feature is: [#18598] "##, }, Lint { - label: "collapse_debuginfo", - description: r##"# `collapse_debuginfo` - -The tracking issue for this feature is: [#100758] - -[#100758]: https://github.com/rust-lang/rust/issues/100758 - ------------------------- -"##, - }, - Lint { label: "compiler_builtins", description: r##"# `compiler_builtins` @@ -2835,8 +3014,8 @@ The tracking issue for this feature is: [#85532] "##, }, Lint { - label: "const_binary_heap_constructor", - description: r##"# `const_binary_heap_constructor` + label: "const_binary_heap_new_in", + description: r##"# `const_binary_heap_new_in` The tracking issue for this feature is: [#112353] @@ -2875,17 +3054,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "const_caller_location", - description: r##"# `const_caller_location` - -The tracking issue for this feature is: [#76156] - -[#76156]: https://github.com/rust-lang/rust/issues/76156 - ------------------------- -"##, - }, - Lint { label: "const_cell_into_inner", description: r##"# `const_cell_into_inner` @@ -2919,17 +3087,6 @@ The tracking issue for this feature is: [#106003] "##, }, Lint { - label: "const_cmp", - description: r##"# `const_cmp` - -The tracking issue for this feature is: [#92391] - -[#92391]: https://github.com/rust-lang/rust/issues/92391 - ------------------------- -"##, - }, - Lint { label: "const_collections_with_hasher", description: r##"# `const_collections_with_hasher` @@ -2966,7 +3123,9 @@ The tracking issue for this feature is: [#113219] label: "const_eval_select", description: r##"# `const_eval_select` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#124625] + +[#124625]: https://github.com/rust-lang/rust/issues/124625 ------------------------ "##, @@ -3076,17 +3235,6 @@ The tracking issue for this feature is: [#79597] "##, }, Lint { - label: "const_hint_assert_unchecked", - description: r##"# `const_hint_assert_unchecked` - -The tracking issue for this feature is: [#119131] - -[#119131]: https://github.com/rust-lang/rust/issues/119131 - ------------------------- -"##, - }, - Lint { label: "const_index_range_slice_index", description: r##"# `const_index_range_slice_index` @@ -3096,10 +3244,12 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "const_int_unchecked_arith", - description: r##"# `const_int_unchecked_arith` + label: "const_int_from_str", + description: r##"# `const_int_from_str` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#59133] + +[#59133]: https://github.com/rust-lang/rust/issues/59133 ------------------------ "##, @@ -3154,17 +3304,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "const_io_structs", - description: r##"# `const_io_structs` - -The tracking issue for this feature is: [#78812] - -[#78812]: https://github.com/rust-lang/rust/issues/78812 - ------------------------- -"##, - }, - Lint { label: "const_ip", description: r##"# `const_ip` @@ -3207,17 +3346,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "const_location_fields", - description: r##"# `const_location_fields` - -The tracking issue for this feature is: [#102911] - -[#102911]: https://github.com/rust-lang/rust/issues/102911 - ------------------------- -"##, - }, - Lint { label: "const_maybe_uninit_array_assume_init", description: r##"# `const_maybe_uninit_array_assume_init` @@ -3304,17 +3432,6 @@ The tracking issue for this feature is: [#110840] "##, }, Lint { - label: "const_ops", - description: r##"# `const_ops` - -The tracking issue for this feature is: [#90080] - -[#90080]: https://github.com/rust-lang/rust/issues/90080 - ------------------------- -"##, - }, - Lint { label: "const_option", description: r##"# `const_option` @@ -3535,6 +3652,17 @@ The tracking issue for this feature is: [#111774] "##, }, Lint { + label: "const_slice_flatten", + description: r##"# `const_slice_flatten` + +The tracking issue for this feature is: [#95629] + +[#95629]: https://github.com/rust-lang/rust/issues/95629 + +------------------------ +"##, + }, + Lint { label: "const_slice_from_mut_ptr_range", description: r##"# `const_slice_from_mut_ptr_range` @@ -3588,17 +3716,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "const_slice_ptr_len", - description: r##"# `const_slice_ptr_len` - -The tracking issue for this feature is: [#71146] - -[#71146]: https://github.com/rust-lang/rust/issues/71146 - ------------------------- -"##, - }, - Lint { label: "const_slice_split_at_mut", description: r##"# `const_slice_split_at_mut` @@ -3665,6 +3782,15 @@ The tracking issue for this feature is: [#83163] "##, }, Lint { + label: "const_three_way_compare", + description: r##"# `const_three_way_compare` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { label: "const_trait_impl", description: r##"# `const_trait_impl` @@ -3709,6 +3835,24 @@ The tracking issue for this feature is: [#63084] "##, }, Lint { + label: "const_typed_swap", + description: r##"# `const_typed_swap` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "const_ub_checks", + description: r##"# `const_ub_checks` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { label: "const_unicode_case_lookup", description: r##"# `const_unicode_case_lookup` @@ -3751,6 +3895,17 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { + label: "context_ext", + description: r##"# `context_ext` + +The tracking issue for this feature is: [#123392] + +[#123392]: https://github.com/rust-lang/rust/issues/123392 + +------------------------ +"##, + }, + Lint { label: "control_flow_enum", description: r##"# `control_flow_enum` @@ -3793,6 +3948,24 @@ The tracking issue for this feature is: [#117693] "##, }, Lint { + label: "core_pattern_type", + description: r##"# `core_pattern_type` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { + label: "core_pattern_types", + description: r##"# `core_pattern_types` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { label: "core_private_bignum", description: r##"# `core_private_bignum` @@ -3862,7 +4035,7 @@ tweaks to the overall design. A syntactical example of a coroutine is: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -3884,7 +4057,8 @@ fn main() { } ``` -Coroutines are closure-like literals which can contain a `yield` statement. The +Coroutines are closure-like literals which are annotated with `#[coroutine]` +and can contain a `yield` statement. The `yield` statement takes an optional expression of a value to yield out of the coroutine. All coroutine literals implement the `Coroutine` trait in the `std::ops` module. The `Coroutine` trait has one main method, `resume`, which @@ -3894,7 +4068,7 @@ An example of the control flow of coroutines is that the following example prints all numbers in order: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -3914,9 +4088,9 @@ fn main() { } ``` -At this time the main intended use case of coroutines is an implementation -primitive for async/await syntax, but coroutines will likely be extended to -ergonomic implementations of iterators and other primitives in the future. +At this time the main use case of coroutines is an implementation +primitive for `async`/`await` and `gen` syntax, but coroutines +will likely be extended to other primitives in the future. Feedback on the design and usage is always appreciated! ### The `Coroutine` trait @@ -3999,7 +4173,7 @@ which point all state is saved off in the coroutine and a value is returned. Let's take a look at an example to see what's going on here: ```rust -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] use std::ops::Coroutine; use std::pin::Pin; @@ -4019,7 +4193,7 @@ fn main() { This coroutine literal will compile down to something similar to: ```rust -#![feature(arbitrary_self_types, coroutines, coroutine_trait)] +#![feature(arbitrary_self_types, coroutine_trait)] use std::ops::{Coroutine, CoroutineState}; use std::pin::Pin; @@ -4139,12 +4313,12 @@ The tracking issue for this feature is: [#44839] "##, }, Lint { - label: "cstr_count_bytes", - description: r##"# `cstr_count_bytes` + label: "cstr_bytes", + description: r##"# `cstr_bytes` -The tracking issue for this feature is: [#114441] +The tracking issue for this feature is: [#112115] -[#114441]: https://github.com/rust-lang/rust/issues/114441 +[#112115]: https://github.com/rust-lang/rust/issues/112115 ------------------------ "##, @@ -4161,17 +4335,6 @@ The tracking issue for this feature is: [#86369] "##, }, Lint { - label: "custom_code_classes_in_docs", - description: r##"# `custom_code_classes_in_docs` - -The tracking issue for this feature is: [#79483] - -[#79483]: https://github.com/rust-lang/rust/issues/79483 - ------------------------- -"##, - }, - Lint { label: "custom_inner_attributes", description: r##"# `custom_inner_attributes` @@ -4281,15 +4444,6 @@ The tracking issue for this feature is: [#27336] "##, }, Lint { - label: "delayed_debug_assertions", - description: r##"# `delayed_debug_assertions` - -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. - ------------------------- -"##, - }, - Lint { label: "deprecated_safe", description: r##"# `deprecated_safe` @@ -4312,6 +4466,28 @@ The tracking issue for this feature is: [#94785] "##, }, Lint { + label: "deref_patterns", + description: r##"# `deref_patterns` + +The tracking issue for this feature is: [#87121] + +[#87121]: https://github.com/rust-lang/rust/issues/87121 + +------------------------ +"##, + }, + Lint { + label: "deref_pure_trait", + description: r##"# `deref_pure_trait` + +The tracking issue for this feature is: [#87121] + +[#87121]: https://github.com/rust-lang/rust/issues/87121 + +------------------------ +"##, + }, + Lint { label: "derive_clone_copy", description: r##"# `derive_clone_copy` @@ -4339,91 +4515,14 @@ This feature is internal to the Rust compiler and is not intended for general us "##, }, Lint { - label: "diagnostic_namespace", - description: r##"# `diagnostic_namespace` + label: "derive_smart_pointer", + description: r##"# `derive_smart_pointer` -The tracking issue for this feature is: [#111996] +The tracking issue for this feature is: [#123430] -[#111996]: https://github.com/rust-lang/rust/issues/111996 +[#123430]: https://github.com/rust-lang/rust/issues/123430 ------------------------ - -The `diagnostic_namespace` feature permits customization of compilation errors. - -## diagnostic::on_unimplemented - -With [#114452] support for `diagnostic::on_unimplemented` was added. - -When used on a trait declaration, the following options are available: - -* `message` to customize the primary error message -* `note` to add a customized note message to an error message -* `label` to customize the label part of the error message - -The attribute will hint to the compiler to use these in error messages: -```rust -// some library -#![feature(diagnostic_namespace)] - -#[diagnostic::on_unimplemented( - message = "cannot insert element", - label = "cannot be put into a table", - note = "see <link> for more information about the Table api" -)] -pub trait Element { - // ... -} -``` - -```rust,compile_fail,E0277 -# #![feature(diagnostic_namespace)] -# -# #[diagnostic::on_unimplemented( -# message = "cannot insert element", -# label = "cannot be put into a table", -# note = "see <link> for more information about the Table api" -# )] -# pub trait Element { -# // ... -# } -# struct Table; -# impl Table { -# fn insert<T: Element>(&self, element: T) { -# // .. -# } -# } -# fn main() { -# let table = Table; -# let element = (); -// user code -table.insert(element); -# } -``` - -```text -error[E0277]: cannot insert element - --> src/main.rs:24:18 - | -24 | table.insert(element); - | ------ ^^^^^^^ cannot be put into a table - | | - | required by a bound introduced by this call - | - = help: the trait `Element` is not implemented for `<type>` - = note: see <link> for more information about the Table api -note: required by a bound in `Table::insert` - --> src/main.rs:15:18 - | -15 | fn insert<T: Element>(&self, element: T) { - | ^^^^^^^ required by this bound in `Table::insert` - -For more information about this error, try `rustc --explain E0277`. -``` - -See [RFC 3368] for more information. - -[#114452]: https://github.com/rust-lang/rust/pull/114452 -[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md "##, }, Lint { @@ -4456,17 +4555,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "div_duration", - description: r##"# `div_duration` - -The tracking issue for this feature is: [#63139] - -[#63139]: https://github.com/rust-lang/rust/issues/63139 - ------------------------- -"##, - }, - Lint { label: "do_not_recommend", description: r##"# `do_not_recommend` @@ -4648,17 +4736,6 @@ The tracking issue for this feature is: [#34761] "##, }, Lint { - label: "duration_abs_diff", - description: r##"# `duration_abs_diff` - -The tracking issue for this feature is: [#117618] - -[#117618]: https://github.com/rust-lang/rust/issues/117618 - ------------------------- -"##, - }, - Lint { label: "duration_constants", description: r##"# `duration_constants` @@ -4694,6 +4771,17 @@ The tracking issue for this feature is: [#72440] "##, }, Lint { + label: "duration_millis_float", + description: r##"# `duration_millis_float` + +The tracking issue for this feature is: [#122451] + +[#122451]: https://github.com/rust-lang/rust/issues/122451 + +------------------------ +"##, + }, + Lint { label: "duration_units", description: r##"# `duration_units` @@ -4725,6 +4813,15 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { + label: "effect_types", + description: r##"# `effect_types` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { label: "effects", description: r##"# `effects` @@ -4769,17 +4866,6 @@ The tracking issue for this feature is: [#99301] "##, }, Lint { - label: "error_in_core", - description: r##"# `error_in_core` - -The tracking issue for this feature is: [#103765] - -[#103765]: https://github.com/rust-lang/rust/issues/103765 - ------------------------- -"##, - }, - Lint { label: "error_iter", description: r##"# `error_iter` @@ -4824,36 +4910,6 @@ The tracking issue for this feature is: [#35428] "##, }, Lint { - label: "exclusive_range_pattern", - description: r##"# `exclusive_range_pattern` - -The tracking issue for this feature is: [#37854]. - - -[#67264]: https://github.com/rust-lang/rust/issues/67264 -[#37854]: https://github.com/rust-lang/rust/issues/37854 ------ - -The `exclusive_range_pattern` feature allows non-inclusive range -patterns (`0..10`) to be used in appropriate pattern matching -contexts. It also can be combined with `#![feature(half_open_range_patterns]` -to be able to use RangeTo patterns (`..10`). - -It also enabled RangeFrom patterns but that has since been -stabilized. - -```rust -#![feature(exclusive_range_pattern)] - let x = 5; - match x { - 0..10 => println!("single digit"), - 10 => println!("ten isn't part of the above range"), - _ => println!("nor is everything else.") - } -``` -"##, - }, - Lint { label: "exclusive_wrapper", description: r##"# `exclusive_wrapper` @@ -4920,6 +4976,17 @@ The tracking issue for this feature is: [#95228] "##, }, Lint { + label: "expr_fragment_specifier_2024", + description: r##"# `expr_fragment_specifier_2024` + +The tracking issue for this feature is: [#123742] + +[#123742]: https://github.com/rust-lang/rust/issues/123742 + +------------------------ +"##, + }, + Lint { label: "extend_one", description: r##"# `extend_one` @@ -4967,6 +5034,32 @@ The tracking issue for this feature is: [#43244] "##, }, Lint { + label: "f128", + description: r##"# `f128` + +The tracking issue for this feature is: [#116909] + +[#116909]: https://github.com/rust-lang/rust/issues/116909 + +--- + +Enable the `f128` type for IEEE 128-bit floating numbers (quad precision). +"##, + }, + Lint { + label: "f16", + description: r##"# `f16` + +The tracking issue for this feature is: [#116909] + +[#116909]: https://github.com/rust-lang/rust/issues/116909 + +--- + +Enable the `f16` type for IEEE 16-bit floating numbers (half precision). +"##, + }, + Lint { label: "fd", description: r##"# `fd` @@ -5249,12 +5342,23 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "fs_try_exists", - description: r##"# `fs_try_exists` + label: "freeze", + description: r##"# `freeze` + +The tracking issue for this feature is: [#121675] + +[#121675]: https://github.com/rust-lang/rust/issues/121675 + +------------------------ +"##, + }, + Lint { + label: "freeze_impls", + description: r##"# `freeze_impls` -The tracking issue for this feature is: [#83186] +The tracking issue for this feature is: [#121675] -[#83186]: https://github.com/rust-lang/rust/issues/83186 +[#121675]: https://github.com/rust-lang/rust/issues/121675 ------------------------ "##, @@ -5368,17 +5472,6 @@ The tracking issue for this feature is: [#113521] "##, }, Lint { - label: "generic_nonzero", - description: r##"# `generic_nonzero` - -The tracking issue for this feature is: [#120257] - -[#120257]: https://github.com/rust-lang/rust/issues/120257 - ------------------------- -"##, - }, - Lint { label: "get_many_mut", description: r##"# `get_many_mut` @@ -5401,11 +5494,22 @@ The tracking issue for this feature is: [#63292] "##, }, Lint { + label: "global_registration", + description: r##"# `global_registration` + +The tracking issue for this feature is: [#125119] + +[#125119]: https://github.com/rust-lang/rust/issues/125119 + +------------------------ +"##, + }, + Lint { label: "half_open_range_patterns_in_slices", description: r##"# `half_open_range_patterns_in_slices` The tracking issue for this feature is: [#67264] -It is part of the `exclusive_range_pattern` feature, +It is a future part of the `exclusive_range_pattern` feature, tracked at [#37854]. [#67264]: https://github.com/rust-lang/rust/issues/67264 @@ -5416,7 +5520,6 @@ This feature allow using top-level half-open range patterns in slices. ```rust #![feature(half_open_range_patterns_in_slices)] -#![feature(exclusive_range_pattern)] fn main() { let xs = [13, 1, 5, 2, 3, 1, 21, 8]; @@ -5499,17 +5602,6 @@ The tracking issue for this feature is: [#44839] "##, }, Lint { - label: "hint_assert_unchecked", - description: r##"# `hint_assert_unchecked` - -The tracking issue for this feature is: [#119131] - -[#119131]: https://github.com/rust-lang/rust/issues/119131 - ------------------------- -"##, - }, - Lint { label: "hint_must_use", description: r##"# `hint_must_use` @@ -5554,17 +5646,6 @@ The tracking issue for this feature is: [#99697] "##, }, Lint { - label: "imported_main", - description: r##"# `imported_main` - -The tracking issue for this feature is: [#28937] - -[#28937]: https://github.com/rust-lang/rust/issues/28937 - ------------------------- -"##, - }, - Lint { label: "inherent_associated_types", description: r##"# `inherent_associated_types` @@ -5576,49 +5657,11 @@ The tracking issue for this feature is: [#8995] "##, }, Lint { - label: "inline_const", - description: r##"# `inline_const` - -The tracking issue for this feature is: [#76001] - -See also [`inline_const_pat`](inline-const-pat.md) - ------- - -This feature allows you to use inline constant expressions. For example, you can -turn this code: - -```rust -# fn add_one(x: i32) -> i32 { x + 1 } -const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4; - -fn main() { - let x = add_one(MY_COMPUTATION); -} -``` - -into this code: - -```rust -#![feature(inline_const)] - -# fn add_one(x: i32) -> i32 { x + 1 } -fn main() { - let x = add_one(const { 1 + 2 * 3 / 4 }); -} -``` - -[#76001]: https://github.com/rust-lang/rust/issues/76001 -"##, - }, - Lint { label: "inline_const_pat", description: r##"# `inline_const_pat` The tracking issue for this feature is: [#76001] -See also [`inline_const`](inline-const.md) - ------ This feature allows you to use inline constant expressions in pattern position: @@ -5671,6 +5714,17 @@ The tracking issue for this feature is: [#99069] "##, }, Lint { + label: "integer_sign_cast", + description: r##"# `integer_sign_cast` + +The tracking issue for this feature is: [#125882] + +[#125882]: https://github.com/rust-lang/rust/issues/125882 + +------------------------ +"##, + }, + Lint { label: "internal_impls_macro", description: r##"# `internal_impls_macro` @@ -5729,7 +5783,7 @@ All intrinsic fallback bodies are automatically made cross-crate inlineable (lik by the codegen backend, but not the MIR inliner. ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -5739,7 +5793,7 @@ const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} Since these are just regular functions, it is perfectly ok to create the intrinsic twice: ```rust -#![feature(rustc_attrs, effects)] +#![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -5763,12 +5817,23 @@ with any regular function. Various intrinsics have native MIR operations that they correspond to. Instead of requiring backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass will convert the calls to the MIR operation. Backends do not need to know about these intrinsics -at all. +at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic" +or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist +anymore after MIR analyses. ## Intrinsics without fallback logic These must be implemented by all backends. +### `#[rustc_intrinsic]` declarations + +These are written like intrinsics with fallback bodies, but the body is irrelevant. +Use `loop {}` for the body or call the intrinsic recursively and add +`#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't +invoke the body. + +### Legacy extern ABI based intrinsics + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and @@ -5792,17 +5857,6 @@ You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call. "##, }, Lint { - label: "io_error_downcast", - description: r##"# `io_error_downcast` - -The tracking issue for this feature is: [#99262] - -[#99262]: https://github.com/rust-lang/rust/issues/99262 - ------------------------- -"##, - }, - Lint { label: "io_error_more", description: r##"# `io_error_more` @@ -5845,23 +5899,23 @@ The tracking issue for this feature is: [#27709] "##, }, Lint { - label: "ip_bits", - description: r##"# `ip_bits` + label: "is_ascii_octdigit", + description: r##"# `is_ascii_octdigit` -The tracking issue for this feature is: [#113744] +The tracking issue for this feature is: [#101288] -[#113744]: https://github.com/rust-lang/rust/issues/113744 +[#101288]: https://github.com/rust-lang/rust/issues/101288 ------------------------ "##, }, Lint { - label: "is_ascii_octdigit", - description: r##"# `is_ascii_octdigit` + label: "is_none_or", + description: r##"# `is_none_or` -The tracking issue for this feature is: [#101288] +The tracking issue for this feature is: [#126383] -[#101288]: https://github.com/rust-lang/rust/issues/101288 +[#126383]: https://github.com/rust-lang/rust/issues/126383 ------------------------ "##, @@ -5935,6 +5989,17 @@ The tracking issue for this feature is: [#100450] "##, }, Lint { + label: "iter_chain", + description: r##"# `iter_chain` + +The tracking issue for this feature is: [#125964] + +[#125964]: https://github.com/rust-lang/rust/issues/125964 + +------------------------ +"##, + }, + Lint { label: "iter_collect_into", description: r##"# `iter_collect_into` @@ -6056,6 +6121,17 @@ The tracking issue for this feature is: [#87053] "##, }, Lint { + label: "junction_point", + description: r##"# `junction_point` + +The tracking issue for this feature is: [#121709] + +[#121709]: https://github.com/rust-lang/rust/issues/121709 + +------------------------ +"##, + }, + Lint { label: "lahfsahf_target_feature", description: r##"# `lahfsahf_target_feature` @@ -6208,23 +6284,12 @@ The tracking issue for this feature is: [#69835] "##, }, Lint { - label: "lazy_cell", - description: r##"# `lazy_cell` - -The tracking issue for this feature is: [#109736] - -[#109736]: https://github.com/rust-lang/rust/issues/109736 - ------------------------- -"##, - }, - Lint { label: "lazy_cell_consume", description: r##"# `lazy_cell_consume` -The tracking issue for this feature is: [#109736] +The tracking issue for this feature is: [#125623] -[#109736]: https://github.com/rust-lang/rust/issues/109736 +[#125623]: https://github.com/rust-lang/rust/issues/125623 ------------------------ "##, @@ -6368,17 +6433,6 @@ The tracking issue for this feature is: [#114135] "##, }, Lint { - label: "lint_reasons", - description: r##"# `lint_reasons` - -The tracking issue for this feature is: [#54503] - -[#54503]: https://github.com/rust-lang/rust/issues/54503 - ------------------------- -"##, - }, - Lint { label: "linux_pidfd", description: r##"# `linux_pidfd` @@ -6434,6 +6488,17 @@ The tracking issue for this feature is: [#83527] "##, }, Lint { + label: "macro_metavar_expr_concat", + description: r##"# `macro_metavar_expr_concat` + +The tracking issue for this feature is: [#124225] + +[#124225]: https://github.com/rust-lang/rust/issues/124225 + +------------------------ +"##, + }, + Lint { label: "map_entry_replace", description: r##"# `map_entry_replace` @@ -6539,6 +6604,17 @@ The tracking issue for this feature is: [#93092] "##, }, Lint { + label: "maybe_uninit_fill", + description: r##"# `maybe_uninit_fill` + +The tracking issue for this feature is: [#117428] + +[#117428]: https://github.com/rust-lang/rust/issues/117428 + +------------------------ +"##, + }, + Lint { label: "maybe_uninit_slice", description: r##"# `maybe_uninit_slice` @@ -6691,6 +6767,17 @@ The tracking issue for this feature is: [#83310] "##, }, Lint { + label: "mut_ref", + description: r##"# `mut_ref` + +The tracking issue for this feature is: [#123076] + +[#123076]: https://github.com/rust-lang/rust/issues/123076 + +------------------------ +"##, + }, + Lint { label: "naked_functions", description: r##"# `naked_functions` @@ -6838,6 +6925,17 @@ The tracking issue for this feature is: [#65992] "##, }, Lint { + label: "new_range_api", + description: r##"# `new_range_api` + +The tracking issue for this feature is: [#125687] + +[#125687]: https://github.com/rust-lang/rust/issues/125687 + +------------------------ +"##, + }, + Lint { label: "new_uninit", description: r##"# `new_uninit` @@ -6915,17 +7013,6 @@ The tracking issue for this feature is: [#108185] "##, }, Lint { - label: "non_null_convenience", - description: r##"# `non_null_convenience` - -The tracking issue for this feature is: [#117691] - -[#117691]: https://github.com/rust-lang/rust/issues/117691 - ------------------------- -"##, - }, - Lint { label: "non_zero_count_ones", description: r##"# `non_zero_count_ones` @@ -7032,6 +7119,17 @@ The tracking issue for this feature is: [#120140] "##, }, Lint { + label: "offset_of_slice", + description: r##"# `offset_of_slice` + +The tracking issue for this feature is: [#126151] + +[#126151]: https://github.com/rust-lang/rust/issues/126151 + +------------------------ +"##, + }, + Lint { label: "omit_gdb_pretty_printer_section", description: r##"# `omit_gdb_pretty_printer_section` @@ -7041,6 +7139,17 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { + label: "once_cell_get_mut", + description: r##"# `once_cell_get_mut` + +The tracking issue for this feature is: [#121641] + +[#121641]: https://github.com/rust-lang/rust/issues/121641 + +------------------------ +"##, + }, + Lint { label: "once_cell_try", description: r##"# `once_cell_try` @@ -7096,17 +7205,6 @@ The tracking issue for this feature is: [#82901] "##, }, Lint { - label: "option_take_if", - description: r##"# `option_take_if` - -The tracking issue for this feature is: [#98934] - -[#98934]: https://github.com/rust-lang/rust/issues/98934 - ------------------------- -"##, - }, - Lint { label: "option_zip", description: r##"# `option_zip` @@ -7140,6 +7238,17 @@ The tracking issue for this feature is: [#118485] "##, }, Lint { + label: "os_string_pathbuf_leak", + description: r##"# `os_string_pathbuf_leak` + +The tracking issue for this feature is: [#125965] + +[#125965]: https://github.com/rust-lang/rust/issues/125965 + +------------------------ +"##, + }, + Lint { label: "panic_abort", description: r##"# `panic_abort` @@ -7184,21 +7293,21 @@ The tracking issue for this feature is: [#92988] "##, }, Lint { - label: "panic_info_message", - description: r##"# `panic_info_message` - -The tracking issue for this feature is: [#66745] + label: "panic_internals", + description: r##"# `panic_internals` -[#66745]: https://github.com/rust-lang/rust/issues/66745 +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ "##, }, Lint { - label: "panic_internals", - description: r##"# `panic_internals` + label: "panic_payload_as_str", + description: r##"# `panic_payload_as_str` -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. +The tracking issue for this feature is: [#125175] + +[#125175]: https://github.com/rust-lang/rust/issues/125175 ------------------------ "##, @@ -7237,6 +7346,28 @@ The tracking issue for this feature is: [#92649] "##, }, Lint { + label: "patchable_function_entry", + description: r##"# `patchable_function_entry` + +The tracking issue for this feature is: [#123115] + +[#123115]: https://github.com/rust-lang/rust/issues/123115 + +------------------------ +"##, + }, + Lint { + label: "path_add_extension", + description: r##"# `path_add_extension` + +The tracking issue for this feature is: [#127292] + +[#127292]: https://github.com/rust-lang/rust/issues/127292 + +------------------------ +"##, + }, + Lint { label: "path_file_prefix", description: r##"# `path_file_prefix` @@ -7268,6 +7399,17 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { + label: "pattern_types", + description: r##"# `pattern_types` + +The tracking issue for this feature is: [#123646] + +[#123646]: https://github.com/rust-lang/rust/issues/123646 + +------------------------ +"##, + }, + Lint { label: "peer_credentials_unix_socket", description: r##"# `peer_credentials_unix_socket` @@ -7290,8 +7432,8 @@ The tracking issue for this feature is: [#86918] "##, }, Lint { - label: "pointer_is_aligned", - description: r##"# `pointer_is_aligned` + label: "pointer_is_aligned_to", + description: r##"# `pointer_is_aligned_to` The tracking issue for this feature is: [#96284] @@ -7321,6 +7463,32 @@ The tracking issue for this feature is: [#86656] "##, }, Lint { + label: "postfix_match", + description: r##"# `postfix-match` + +`postfix-match` adds the feature for matching upon values postfix +the expressions that generate the values. + +```rust,edition2021 +#![feature(postfix_match)] + +enum Foo { + Bar, + Baz +} + +fn get_foo() -> Foo { + Foo::Bar +} + +get_foo().match { + Foo::Bar => {}, + Foo::Baz => panic!(), +} +``` +"##, + }, + Lint { label: "powerpc_target_feature", description: r##"# `powerpc_target_feature` @@ -7332,6 +7500,17 @@ The tracking issue for this feature is: [#44839] "##, }, Lint { + label: "precise_capturing", + description: r##"# `precise_capturing` + +The tracking issue for this feature is: [#123432] + +[#123432]: https://github.com/rust-lang/rust/issues/123432 + +------------------------ +"##, + }, + Lint { label: "prelude_2024", description: r##"# `prelude_2024` @@ -7372,28 +7551,6 @@ This feature is internal to the Rust compiler and is not intended for general us "##, }, Lint { - label: "proc_macro_byte_character", - description: r##"# `proc_macro_byte_character` - -The tracking issue for this feature is: [#115268] - -[#115268]: https://github.com/rust-lang/rust/issues/115268 - ------------------------- -"##, - }, - Lint { - label: "proc_macro_c_str_literals", - description: r##"# `proc_macro_c_str_literals` - -The tracking issue for this feature is: [#119750] - -[#119750]: https://github.com/rust-lang/rust/issues/119750 - ------------------------- -"##, - }, - Lint { label: "proc_macro_def_site", description: r##"# `proc_macro_def_site` @@ -7529,6 +7686,17 @@ The tracking issue for this feature is: [#102070] "##, }, Lint { + label: "ptr_as_ref_unchecked", + description: r##"# `ptr_as_ref_unchecked` + +The tracking issue for this feature is: [#122034] + +[#122034]: https://github.com/rust-lang/rust/issues/122034 + +------------------------ +"##, + }, + Lint { label: "ptr_as_uninit", description: r##"# `ptr_as_uninit` @@ -7582,17 +7750,6 @@ The tracking issue for this feature is: [#95892] "##, }, Lint { - label: "ptr_to_from_bits", - description: r##"# `ptr_to_from_bits` - -The tracking issue for this feature is: [#91126] - -[#91126]: https://github.com/rust-lang/rust/issues/91126 - ------------------------- -"##, - }, - Lint { label: "pub_crate_should_not_need_unstable_attr", description: r##"# `pub_crate_should_not_need_unstable_attr` @@ -7686,6 +7843,28 @@ The tracking issue for this feature is: [#121440] "##, }, Lint { + label: "ref_pat_eat_one_layer_2024", + description: r##"# `ref_pat_eat_one_layer_2024` + +The tracking issue for this feature is: [#123076] + +[#123076]: https://github.com/rust-lang/rust/issues/123076 + +------------------------ +"##, + }, + Lint { + label: "ref_pat_eat_one_layer_2024_structural", + description: r##"# `ref_pat_eat_one_layer_2024_structural` + +The tracking issue for this feature is: [#123076] + +[#123076]: https://github.com/rust-lang/rust/issues/123076 + +------------------------ +"##, + }, + Lint { label: "register_tool", description: r##"# `register_tool` @@ -7739,6 +7918,24 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { + label: "result_ffi_guarantees", + description: r##"# `result_ffi_guarantees` + +The tracking issue for this feature is: [#110503] + +[#110503]: https://github.com/rust-lang/rust/issues/110503 + +------------------------ + +This feature adds the possibility of using `Result<T, E>` in FFI if T's niche +value can be used to describe E or vise-versa. + +See [RFC 3391] for more information. + +[RFC 3391]: https://github.com/rust-lang/rfcs/blob/master/text/3391-result_ffi_guarantees.md +"##, + }, + Lint { label: "result_flattening", description: r##"# `result_flattening` @@ -7882,6 +8079,15 @@ error: aborting due to 2 previous errors "##, }, Lint { + label: "rustc_encodable_decodable", + description: r##"# `rustc_encodable_decodable` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------ +"##, + }, + Lint { label: "rustc_private", description: r##"# `rustc_private` @@ -7924,17 +8130,6 @@ This feature has no tracking issue, and is therefore likely internal to the comp "##, }, Lint { - label: "seek_seek_relative", - description: r##"# `seek_seek_relative` - -The tracking issue for this feature is: [#117374] - -[#117374]: https://github.com/rust-lang/rust/issues/117374 - ------------------------- -"##, - }, - Lint { label: "seek_stream_len", description: r##"# `seek_stream_len` @@ -7979,6 +8174,17 @@ The tracking issue for this feature is: [#56975] "##, }, Lint { + label: "shorter_tail_lifetimes", + description: r##"# `shorter_tail_lifetimes` + +The tracking issue for this feature is: [#123739] + +[#123739]: https://github.com/rust-lang/rust/issues/123739 + +------------------------ +"##, + }, + Lint { label: "simd_ffi", description: r##"# `simd_ffi` @@ -8032,17 +8238,6 @@ The tracking issue for this feature is: [#27747] "##, }, Lint { - label: "slice_flatten", - description: r##"# `slice_flatten` - -The tracking issue for this feature is: [#95629] - -[#95629]: https://github.com/rust-lang/rust/issues/95629 - ------------------------- -"##, - }, - Lint { label: "slice_from_ptr_range", description: r##"# `slice_from_ptr_range` @@ -8116,17 +8311,6 @@ The tracking issue for this feature is: [#74265] "##, }, Lint { - label: "slice_ptr_len", - description: r##"# `slice_ptr_len` - -The tracking issue for this feature is: [#71146] - -[#71146]: https://github.com/rust-lang/rust/issues/71146 - ------------------------- -"##, - }, - Lint { label: "slice_range", description: r##"# `slice_range` @@ -8138,17 +8322,6 @@ The tracking issue for this feature is: [#76393] "##, }, Lint { - label: "slice_split_at_unchecked", - description: r##"# `slice_split_at_unchecked` - -The tracking issue for this feature is: [#76014] - -[#76014]: https://github.com/rust-lang/rust/issues/76014 - ------------------------- -"##, - }, - Lint { label: "slice_split_once", description: r##"# `slice_split_once` @@ -8202,24 +8375,6 @@ The tracking issue for this feature is: [#93396] "##, }, Lint { - label: "sort_internals", - description: r##"# `sort_internals` - -This feature is internal to the Rust compiler and is not intended for general use. - ------------------------- -"##, - }, - Lint { - label: "spec_option_partial_eq", - description: r##"# `spec_option_partial_eq` - -This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. - ------------------------- -"##, - }, - Lint { label: "specialization", description: r##"# `specialization` @@ -8253,17 +8408,6 @@ The tracking issue for this feature is: [#96137] "##, }, Lint { - label: "split_at_checked", - description: r##"# `split_at_checked` - -The tracking issue for this feature is: [#119128] - -[#119128]: https://github.com/rust-lang/rust/issues/119128 - ------------------------- -"##, - }, - Lint { label: "sse4a_target_feature", description: r##"# `sse4a_target_feature` @@ -8696,9 +8840,9 @@ The tracking issue for this feature is: [#96256] label: "tcplistener_into_incoming", description: r##"# `tcplistener_into_incoming` -The tracking issue for this feature is: [#88339] +The tracking issue for this feature is: [#88373] -[#88339]: https://github.com/rust-lang/rust/issues/88339 +[#88373]: https://github.com/rust-lang/rust/issues/88373 ------------------------ "##, @@ -9322,6 +9466,17 @@ The tracking issue for this feature is: [#96374] "##, }, Lint { + label: "try_with_capacity", + description: r##"# `try_with_capacity` + +The tracking issue for this feature is: [#91913] + +[#91913]: https://github.com/rust-lang/rust/issues/91913 + +------------------------ +"##, + }, + Lint { label: "tuple_trait", description: r##"# `tuple_trait` @@ -9390,12 +9545,10 @@ fn main () { "##, }, Lint { - label: "type_privacy_lints", - description: r##"# `type_privacy_lints` - -The tracking issue for this feature is: [#48054] + label: "ub_checks", + description: r##"# `ub_checks` -[#48054]: https://github.com/rust-lang/rust/issues/48054 +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. ------------------------ "##, @@ -9441,17 +9594,6 @@ fn main() {} "##, }, Lint { - label: "unchecked_math", - description: r##"# `unchecked_math` - -The tracking issue for this feature is: [#85122] - -[#85122]: https://github.com/rust-lang/rust/issues/85122 - ------------------------- -"##, - }, - Lint { label: "unchecked_neg", description: r##"# `unchecked_neg` @@ -9516,72 +9658,6 @@ The tracking issue for this feature is: [#96467] "##, }, Lint { - label: "unix_sigpipe", - description: r##"# `unix_sigpipe` - -The tracking issue for this feature is: [#97889] - -[#97889]: https://github.com/rust-lang/rust/issues/97889 - ---- - -The `#[unix_sigpipe = "..."]` attribute on `fn main()` can be used to specify how libstd shall setup `SIGPIPE` on Unix platforms before invoking `fn main()`. This attribute is ignored on non-Unix targets. There are three variants: -* `#[unix_sigpipe = "inherit"]` -* `#[unix_sigpipe = "sig_dfl"]` -* `#[unix_sigpipe = "sig_ign"]` - -## `#[unix_sigpipe = "inherit"]` - -Leave `SIGPIPE` untouched before entering `fn main()`. Unless the parent process has changed the default `SIGPIPE` handler from `SIG_DFL` to something else, this will behave the same as `#[unix_sigpipe = "sig_dfl"]`. - -## `#[unix_sigpipe = "sig_dfl"]` - -Set the `SIGPIPE` handler to `SIG_DFL`. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output. - -### Example - -```rust,no_run -#![feature(unix_sigpipe)] -#[unix_sigpipe = "sig_dfl"] -fn main() { loop { println!("hello world"); } } -``` - -```bash -% ./main | head -n 1 -hello world -``` - -## `#[unix_sigpipe = "sig_ign"]` - -Set the `SIGPIPE` handler to `SIG_IGN` before invoking `fn main()`. This will result in `ErrorKind::BrokenPipe` errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers. - -This is what libstd has done by default since 2014. (However, see the note on child processes below.) - -### Example - -```rust,no_run -#![feature(unix_sigpipe)] -#[unix_sigpipe = "sig_ign"] -fn main() { loop { println!("hello world"); } } -``` - -```bash -% ./main | head -n 1 -hello world -thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -``` - -### Note on child processes - -When spawning child processes, the legacy Rust behavior if `#[unix_sigpipe]` is not specified is to -reset `SIGPIPE` to `SIG_DFL`. - -If `#[unix_sigpipe = "..."]` is specified, no matter what its value is, the signal disposition of -`SIGPIPE` is no longer reset. This means that the child inherits the parent's `SIGPIPE` behavior. -"##, - }, - Lint { label: "unix_socket_ancillary_data", description: r##"# `unix_socket_ancillary_data` @@ -9615,6 +9691,17 @@ The tracking issue for this feature is: [#49804] "##, }, Lint { + label: "unsafe_attributes", + description: r##"# `unsafe_attributes` + +The tracking issue for this feature is: [#123757] + +[#123757]: https://github.com/rust-lang/rust/issues/123757 + +------------------------ +"##, + }, + Lint { label: "unsafe_cell_from_mut", description: r##"# `unsafe_cell_from_mut` @@ -9626,6 +9713,17 @@ The tracking issue for this feature is: [#111645] "##, }, Lint { + label: "unsafe_extern_blocks", + description: r##"# `unsafe_extern_blocks` + +The tracking issue for this feature is: [#123743] + +[#123743]: https://github.com/rust-lang/rust/issues/123743 + +------------------------ +"##, + }, + Lint { label: "unsafe_pin_internals", description: r##"# `unsafe_pin_internals` @@ -9920,17 +10018,6 @@ The tracking issue for this feature is: [#94919] "##, }, Lint { - label: "utf8_chunks", - description: r##"# `utf8_chunks` - -The tracking issue for this feature is: [#99543] - -[#99543]: https://github.com/rust-lang/rust/issues/99543 - ------------------------- -"##, - }, - Lint { label: "variant_count", description: r##"# `variant_count` @@ -9953,6 +10040,17 @@ The tracking issue for this feature is: [#65816] "##, }, Lint { + label: "vec_pop_if", + description: r##"# `vec_pop_if` + +The tracking issue for this feature is: [#122741] + +[#122741]: https://github.com/rust-lang/rust/issues/122741 + +------------------------ +"##, + }, + Lint { label: "vec_push_within_capacity", description: r##"# `vec_push_within_capacity` @@ -10224,18 +10322,12 @@ checked."##, description: r##"Checks for usage of the `#[allow]` attribute and suggests replacing it with the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) -The expect attribute is still unstable and requires the `lint_reasons` -on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to -the crate root. - This lint only warns outer attributes (`#[allow]`), as inner attributes (`#![allow]`) are usually used to enable or disable lints on a global scale."##, }, Lint { label: "clippy::allow_attributes_without_reason", - description: r##"Checks for attributes that allow lints without a reason. - -(This requires the `lint_reasons` feature)"##, + description: r##"Checks for attributes that allow lints without a reason."##, }, Lint { label: "clippy::almost_complete_range", @@ -10309,6 +10401,10 @@ patterns."##, description: r##"Nothing. This lint has been deprecated."##, }, Lint { + label: "clippy::assigning_clones", + description: r##"Checks for code like `foo = bar.clone();`"##, + }, + Lint { label: "clippy::async_yields_async", description: r##"Checks for async blocks that yield values of types that can themselves be awaited."##, @@ -10401,8 +10497,8 @@ Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) fo }, Lint { label: "clippy::box_default", - description: r##"checks for `Box::new(T::default())`, which is better written as -`Box::<T>::default()`."##, + description: r##"checks for `Box::new(Default::default())`, which can be written as +`Box::default()`."##, }, Lint { label: "clippy::boxed_local", @@ -10419,6 +10515,11 @@ moved out of the blocks."##, description: r##"Warns if a generic shadows a built-in type."##, }, Lint { + label: "clippy::byte_char_slices", + description: r##"Checks for hard to read slices of byte characters, that could be more easily expressed as a +byte string."##, + }, + Lint { label: "clippy::bytes_count_to_len", description: r##"It checks for `str::bytes().count()` and suggests replacing it with `str::len()`."##, @@ -10507,6 +10608,10 @@ defined, this lint is `Allow` by default."##, description: r##"Checks for a raw slice being cast to a slice pointer"##, }, Lint { + label: "clippy::cfg_not_test", + description: r##"Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`)"##, + }, + Lint { label: "clippy::char_lit_as_u8", description: r##"Checks for expressions where a character literal is cast to `u8` and suggests using a byte literal instead."##, @@ -10595,6 +10700,10 @@ rewritten with `match` and `cmp`."##, and suggests using `.is_empty()` where applicable."##, }, Lint { + label: "clippy::const_is_empty", + description: r##"It identifies calls to `.is_empty()` on constant values."##, + }, + Lint { label: "clippy::copy_iterator", description: r##"Checks for types that implement `Copy` as well as `Iterator`."##, @@ -10748,6 +10857,13 @@ types are defined in the clippy.toml file."##, statements."##, }, Lint { + label: "clippy::doc_lazy_continuation", + description: r##"In CommonMark Markdown, the language used to write doc comments, a +paragraph nested within a list or block quote does not need any line +after the first one to be indented or marked. The specification calls +this a lazy paragraph continuation."##, + }, + Lint { label: "clippy::doc_link_with_quotes", description: r##"Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) outside of code blocks"##, @@ -10796,6 +10912,10 @@ marked as `#[must_use]`."##, differing by an underscore."##, }, Lint { + label: "clippy::duplicated_attributes", + description: r##"Checks for attributes that appear two or more times."##, + }, + Lint { label: "clippy::duration_subsec", description: r##"Checks for calculation of subsecond microseconds or milliseconds from other `Duration` methods."##, @@ -10817,11 +10937,11 @@ but without a final `else` branch."##, }, Lint { label: "clippy::empty_enum", - description: r##"Checks for `enum`s with no variants. + description: r##"Checks for `enum`s with no variants, which therefore are uninhabited types +(cannot be instantiated). -As of this writing, the `never_type` is still a -nightly-only experimental API. Therefore, this lint is only triggered -if the `never_type` is enabled."##, +As of this writing, the `never_type` is still a nightly-only experimental API. +Therefore, this lint is only triggered if `#![feature(never_type)]` is enabled."##, }, Lint { label: "clippy::empty_enum_variants_with_brackets", @@ -10890,7 +11010,7 @@ than that supported by the underlying type."##, }, Lint { label: "clippy::exhaustive_structs", - description: r##"Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`"##, + description: r##"Warns on any exported `struct`s that are not tagged `#[non_exhaustive]`"##, }, Lint { label: "clippy::exit", @@ -10965,6 +11085,11 @@ anywhere else."##, with Default::default()."##, }, Lint { + label: "clippy::field_scoped_visibility_modifiers", + description: r##"Checks for usage of scoped visibility modifiers, like `pub(crate)`, on fields. These +make a field visible within a scope between public and private."##, + }, + Lint { label: "clippy::filetype_is_file", description: r##"Checks for `FileType::is_file()`."##, }, @@ -11297,6 +11422,11 @@ unless the annotated function is empty or simply panics."##, }, Lint { label: "clippy::integer_division", description: r##"Checks for division of integers"## }, Lint { + label: "clippy::integer_division_remainder_used", + description: r##"Checks for the usage of division (`/`) and remainder (`%`) operations +when performed on any integer types using the default `Div` and `Rem` trait implementations."##, + }, + Lint { label: "clippy::into_iter_on_ref", description: r##"Checks for `into_iter` calls on references which should be replaced by `iter` or `iter_mut`."##, @@ -11353,12 +11483,12 @@ create a `Vec`."##, Lint { label: "clippy::iter_filter_is_ok", description: r##"Checks for usage of `.filter(Result::is_ok)` that may be replaced with a `.flatten()` call. -This lint will require additional changes to the follow-up calls as it appects the type."##, +This lint will require additional changes to the follow-up calls as it affects the type."##, }, Lint { label: "clippy::iter_filter_is_some", description: r##"Checks for usage of `.filter(Option::is_some)` that may be replaced with a `.flatten()` call. -This lint will require additional changes to the follow-up calls as it appects the type."##, +This lint will require additional changes to the follow-up calls as it affects the type."##, }, Lint { label: "clippy::iter_kv_map", @@ -11376,8 +11506,8 @@ ignoring either the keys or values."##, }, Lint { label: "clippy::iter_nth", - description: r##"Checks for usage of `.iter().nth()` (and the related -`.iter_mut().nth()`) on standard library types with *O*(1) element access."##, + description: r##"Checks for usage of `.iter().nth()`/`.iter_mut().nth()` on standard library types that have +equivalent `.get()`/`.get_mut()` methods."##, }, Lint { label: "clippy::iter_nth_zero", @@ -11456,7 +11586,7 @@ are too large."##, Lint { label: "clippy::large_include_file", description: r##"Checks for the inclusion of large files via `include_bytes!()` -and `include_str!()`"##, +or `include_str!()`."##, }, Lint { label: "clippy::large_stack_arrays", @@ -11481,6 +11611,11 @@ because that might induce API breakage, if the parameter is declared as mutable, or if the argument is a `self`."##, }, Lint { + label: "clippy::legacy_numeric_constants", + description: r##"Checks for usage of `<integer>::max_value()`, `std::<integer>::MAX`, +`std::<float>::EPSILON`, etc."##, + }, + Lint { label: "clippy::len_without_is_empty", description: r##"Checks for items that implement `.len()` but not `.is_empty()`."##, @@ -11547,6 +11682,10 @@ is resolved."##, cannot be represented as the underlying type without loss."##, }, Lint { + label: "clippy::macro_metavars_in_unsafe", + description: r##"Looks for macros that expand metavariables in an unsafe block."##, + }, + Lint { label: "clippy::macro_use_imports", description: r##"Checks for `#[macro_use] use...`."##, }, @@ -11567,7 +11706,12 @@ cannot be represented as the underlying type without loss."##, description: r##"Checks for usage of `std::mem::size_of::<T>() * 8` when `T::BITS` is available."##, }, - Lint { label: "clippy::manual_c_str_literals", description: r##""## }, + Lint { + label: "clippy::manual_c_str_literals", + description: r##"Checks for the manual creation of C strings (a string with a `NUL` byte at the end), either +through one of the `CStr` constructor functions, or more plainly by calling `.as_ptr()` +on a (byte) string literal with a hardcoded `\\0` byte at the end."##, + }, Lint { label: "clippy::manual_clamp", description: r##"Identifies good opportunities for a clamp function from std or core, and suggests using it."##, @@ -11602,6 +11746,10 @@ where only the `Some` or `Ok` variant of the iterator element is used."##, [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one"##, }, Lint { + label: "clippy::manual_inspect", + description: r##"Checks for uses of `map` which return the original item."##, + }, + Lint { label: "clippy::manual_instant_elapsed", description: r##"Lints subtraction between `Instant::now()` and another `Instant`."##, }, @@ -11621,7 +11769,10 @@ ascii range"##, description: r##"Checks for manual `is_infinite` reimplementations (i.e., `x == <float>::INFINITY || x == <float>::NEG_INFINITY`)."##, }, - Lint { label: "clippy::manual_is_variant_and", description: r##""## }, + Lint { + label: "clippy::manual_is_variant_and", + description: r##"Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type."##, + }, Lint { label: "clippy::manual_let_else", description: r##"Warn of cases where `let...else` could be used"##, @@ -11653,6 +11804,10 @@ slices that could be optimized by having a memcpy."##, description: r##"Finds patterns that reimplement `Option::ok_or`."##, }, Lint { + label: "clippy::manual_pattern_char_comparison", + description: r##"Checks for manual `char` comparison in string patterns"##, + }, + Lint { label: "clippy::manual_range_contains", description: r##"Checks for expressions like `x >= 3 && x < 8` that could be more readably expressed as `(3..8).contains(x)`."##, @@ -11672,6 +11827,11 @@ of `x.rem_euclid(4)`."##, description: r##"Checks for code to be replaced by `.retain()`."##, }, Lint { + label: "clippy::manual_rotate", + description: r##"It detects manual bit rotations that could be rewritten using standard +functions `rotate_left` or `rotate_right`."##, + }, + Lint { label: "clippy::manual_saturating_arithmetic", description: r##"Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`."##, }, @@ -11713,6 +11873,11 @@ Note that the lint will not be emitted in const blocks, as the suggestion would description: r##"Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`."##, }, Lint { + label: "clippy::manual_unwrap_or_default", + description: r##"Checks if a `match` or `if let` expression can be simplified using +`.unwrap_or_default()`."##, + }, + Lint { label: "clippy::manual_while_let_some", description: r##"Looks for loops that check for emptiness of a `Vec` in the condition and pop an element in the body as a separate operation."##, @@ -11817,10 +11982,7 @@ and take drastic actions like `panic!`."##, }, Lint { label: "clippy::maybe_misused_cfg", - description: r##"Checks for `#[cfg(features = ...)]` and suggests to replace it with -`#[cfg(feature = ...)]`. - -It also checks if `cfg(test)` was misspelled."##, + description: r##"Nothing. This lint has been deprecated."##, }, Lint { label: "clippy::mem_forget", @@ -11844,7 +12006,7 @@ and `mem::replace(&mut _, mem::zeroed())`."##, }, Lint { label: "clippy::min_ident_chars", - description: r##"Checks for idents which comprise of a single letter. + description: r##"Checks for identifiers which consist of a single character (or fewer than the configured threshold). Note: This lint can be very noisy when enabled; it may be desirable to only enable it temporarily."##, @@ -11860,7 +12022,7 @@ used to clamp values, but switched so that the result is constant."##, }, Lint { label: "clippy::mismatched_target_os", - description: r##"Checks for cfg attributes having operating systems used in target family position."##, + description: r##"Nothing. This lint has been deprecated."##, }, Lint { label: "clippy::mismatching_type_param_order", @@ -11892,8 +12054,12 @@ is greater than the largest index used to index into the slice."##, description: r##"Suggests the use of `const` in functions and methods where possible."##, }, Lint { + label: "clippy::missing_const_for_thread_local", + description: r##"Suggests to use `const` in `thread_local!` macro if possible."##, + }, + Lint { label: "clippy::missing_docs_in_private_items", - description: r##"Warns if there is missing doc for any private documentable item"##, + description: r##"Warns if there is missing documentation for any private documentable item."##, }, Lint { label: "clippy::missing_enforced_import_renames", @@ -11931,12 +12097,11 @@ unsafe functions and warns if there is no `# Safety` section."##, Lint { label: "clippy::missing_trait_methods", description: r##"Checks if a provided method is used implicitly by a trait -implementation. A usage example would be a wrapper where every method -should perform some operation before delegating to the inner type's -implementation. - -This lint should typically be enabled on a specific trait `impl` item -rather than globally."##, +implementation."##, + }, + Lint { + label: "clippy::missing_transmute_annotations", + description: r##"Checks if transmute calls have all generics specified."##, }, Lint { label: "clippy::mistyped_literal_suffixes", @@ -11944,7 +12109,7 @@ rather than globally."##, }, Lint { label: "clippy::mixed_attributes_style", - description: r##"Checks that an item has only one kind of attributes."##, + description: r##"Checks for items that have the same kind of attributes with mixed styles (inner/outer)."##, }, Lint { label: "clippy::mixed_case_hex_literals", @@ -11959,7 +12124,7 @@ order of sub-expressions."##, }, Lint { label: "clippy::mod_module_files", - description: r##"Checks that module layout uses only self named module files, bans `mod.rs` files."##, + description: r##"Checks that module layout uses only self named module files; bans `mod.rs` files."##, }, Lint { label: "clippy::module_inception", @@ -12025,7 +12190,7 @@ reference with the output lifetime, this lint will not trigger."##, }, Lint { label: "clippy::mut_range_bound", - description: r##"Checks for loops which have a range bound that is a mutable variable"##, + description: r##"Checks for loops with a range bound that is a mutable variable."##, }, Lint { label: "clippy::mutable_key_type", @@ -12074,10 +12239,14 @@ value with `&ref`."##, }, Lint { label: "clippy::needless_borrows_for_generic_args", - description: r##"Checks for borrow operations (`&`) that used as a generic argument to a + description: r##"Checks for borrow operations (`&`) that are used as a generic argument to a function when the borrowed value could be used."##, }, Lint { + label: "clippy::needless_character_iteration", + description: r##"Checks if an iterator is used to check if a string is ascii."##, + }, + Lint { label: "clippy::needless_collect", description: r##"Checks for functions collecting an iterator when collect is not needed."##, @@ -12119,6 +12288,10 @@ relying on lifetime elision."##, when function signatures are the same."##, }, Lint { + label: "clippy::needless_maybe_sized", + description: r##"Lints `?Sized` bounds applied to type parameters that cannot be unsized"##, + }, + Lint { label: "clippy::needless_option_as_deref", description: r##"Checks for no-op uses of `Option::{as_deref, as_deref_mut}`, for example, `Option<&T>::as_deref()` returns the same type."##, @@ -12137,7 +12310,7 @@ superfluous."##, description: r##"Check if a `&mut` function argument is actually used mutably. Be careful if the function is publicly reexported as it would break compatibility with -users of this function."##, +users of this function, when the users pass this function as an argument."##, }, Lint { label: "clippy::needless_pass_by_value", @@ -12369,7 +12542,7 @@ can be eliminated."##, Lint { label: "clippy::panic", description: r##"Checks for usage of `panic!`."## }, Lint { label: "clippy::panic_in_result_fn", - description: r##"Checks for usage of `panic!` or assertions in a function of type result."##, + description: r##"Checks for usage of `panic!` or assertions in a function whose return type is `Result`."##, }, Lint { label: "clippy::panicking_unwrap", @@ -12377,7 +12550,7 @@ can be eliminated."##, }, Lint { label: "clippy::partial_pub_fields", - description: r##"Checks whether partial fields of a struct are public. + description: r##"Checks whether some but not all fields of a `struct` are public. Either make all fields of a type public, or make none of them public"##, }, @@ -12685,6 +12858,11 @@ and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead."##, description: r##"Nothing. This lint has been deprecated."##, }, Lint { + label: "clippy::renamed_function_params", + description: r##"Lints when the name of function parameters from trait impl is +different than its default implementation."##, + }, + Lint { label: "clippy::repeat_once", description: r##"Checks for usage of `.repeat(1)` and suggest the following method for each types. - `.to_string()` for `str` @@ -12765,8 +12943,8 @@ one from a trait, another not from trait."##, }, Lint { label: "clippy::seek_from_current", - description: r##"Checks an argument of `seek` method of `Seek` trait -and if it start seek from `SeekFrom::Current(0)`, suggests `stream_position` instead."##, + description: r##"Checks if the `seek` method of the `Seek` trait is called with `SeekFrom::Current(0)`, +and if it is, suggests using `stream_position` instead."##, }, Lint { label: "clippy::seek_to_start_instead_of_rewind", @@ -12810,6 +12988,11 @@ see the `unseparated_literal_suffix` lint."##, description: r##"Checks for misuses of the serde API."##, }, Lint { + label: "clippy::set_contains_or_insert", + description: r##"Checks for usage of `contains` to see if a value is not +present on `HashSet` followed by a `insert`."##, + }, + Lint { label: "clippy::shadow_reuse", description: r##"Checks for bindings that shadow other bindings already in scope, while reusing the original value."##, @@ -13100,10 +13283,6 @@ either `ignore`, `no_run` or `compile_fail`."##, (marked with `#[cfg(test)]`)."##, }, Lint { - label: "clippy::thread_local_initializer_can_be_made_const", - description: r##"Suggests to use `const` in `thread_local!` macro if possible."##, - }, - Lint { label: "clippy::to_digit_is_some", description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##, }, @@ -13162,7 +13341,7 @@ syntax specifications for trait bounds are used simultaneously."##, }, Lint { label: "clippy::transmute_int_to_non_zero", - description: r##"Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked` + description: r##"Checks for transmutes from `T` to `NonZero<T>`, and suggests the `new_unchecked` method instead."##, }, Lint { @@ -13222,7 +13401,7 @@ declarations above a certain complexity threshold."##, }, Lint { label: "clippy::type_id_on_box", - description: r##"Looks for calls to `<Box<dyn Any> as Any>::type_id`."##, + description: r##"Looks for calls to `.type_id()` on a `Box<dyn _>`."##, }, Lint { label: "clippy::type_repetition_in_bounds", @@ -13234,8 +13413,8 @@ declarations above a certain complexity threshold."##, }, Lint { label: "clippy::unconditional_recursion", - description: r##"Checks that there isn't an infinite recursion in `PartialEq` trait -implementation."##, + description: r##"Checks that there isn't an infinite recursion in trait +implementations."##, }, Lint { label: "clippy::undocumented_unsafe_blocks", @@ -13380,6 +13559,12 @@ simpler code: is being constructed."##, }, Lint { + label: "clippy::unnecessary_min_or_max", + description: r##"Checks for unnecessary calls to `min()` or `max()` in the following cases +- Either both side is constant +- One side is clearly larger than the other, like i32::MIN and an i32 variable"##, + }, + Lint { label: "clippy::unnecessary_mut_passed", description: r##"Detects passing a mutable reference to a function that only requires an immutable reference."##, @@ -13586,11 +13771,21 @@ lint attributes. This lint permits lint attributes for lints emitted on the items themself. For `use` items these lints are: +* ambiguous_glob_reexports +* dead_code * deprecated +* hidden_glob_reexports * unreachable_pub -* unused_imports +* unused +* unused_braces +* unused_import_braces +* clippy::disallowed_types * clippy::enum_glob_use * clippy::macro_use_imports +* clippy::module_name_repetitions +* clippy::redundant_pub_crate +* clippy::single_component_path_imports +* clippy::unsafe_removed_from_name * clippy::wildcard_imports For `extern crate` items these lints are: @@ -13655,6 +13850,10 @@ to `trailing_zeros`"##, description: r##"Checks for usage of `waker.clone().wake()`"##, }, Lint { + label: "clippy::while_float", + description: r##"Checks for while loops comparing floating point values."##, + }, + Lint { label: "clippy::while_immutable_condition", description: r##"Checks whether variables used within while loop condition can be (and are) mutated in the body."##, @@ -13746,6 +13945,11 @@ architecture."##, description: r##"Catch casts from `0` to some pointer type"##, }, Lint { + label: "clippy::zero_repeat_side_effects", + description: r##"Checks for array or vec initializations which call a function or method, +but which have a repeat count of zero."##, + }, + Lint { label: "clippy::zero_sized_map_values", description: r##"Checks for maps with zero-sized value types anywhere in the code."##, }, @@ -13772,7 +13976,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::complexity", - description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::implied_bounds_in_impls, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_filter_map, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, + description: r##"lint group for: clippy::bind_instead_of_map, clippy::bool_comparison, clippy::borrow_deref_ref, clippy::borrowed_box, clippy::bytes_count_to_len, clippy::char_lit_as_u8, clippy::clone_on_copy, clippy::crosspointer_transmute, clippy::default_constructed_unit_structs, clippy::deprecated_cfg_attr, clippy::deref_addrof, clippy::derivable_impls, clippy::diverging_sub_expression, clippy::double_comparisons, clippy::double_parens, clippy::duration_subsec, clippy::excessive_nesting, clippy::explicit_auto_deref, clippy::explicit_counter_loop, clippy::explicit_write, clippy::extra_unused_lifetimes, clippy::extra_unused_type_parameters, clippy::filter_map_identity, clippy::filter_next, clippy::flat_map_identity, clippy::get_last_with_len, clippy::identity_op, clippy::implied_bounds_in_impls, clippy::inspect_for_each, clippy::int_plus_one, clippy::iter_count, clippy::iter_kv_map, clippy::let_with_type_underscore, clippy::manual_clamp, clippy::manual_filter, clippy::manual_filter_map, clippy::manual_find, clippy::manual_find_map, clippy::manual_flatten, clippy::manual_hash_one, clippy::manual_inspect, clippy::manual_main_separator_str, clippy::manual_range_patterns, clippy::manual_rem_euclid, clippy::manual_slice_size_calculation, clippy::manual_split_once, clippy::manual_strip, clippy::manual_swap, clippy::manual_unwrap_or, clippy::map_flatten, clippy::map_identity, clippy::match_as_ref, clippy::match_single_binding, clippy::needless_arbitrary_self_type, clippy::needless_bool, clippy::needless_bool_assign, clippy::needless_borrowed_reference, clippy::needless_if, clippy::needless_lifetimes, clippy::needless_match, clippy::needless_option_as_deref, clippy::needless_option_take, clippy::needless_question_mark, clippy::needless_splitn, clippy::needless_update, clippy::neg_cmp_op_on_partial_ord, clippy::no_effect, clippy::nonminimal_bool, clippy::only_used_in_recursion, clippy::option_as_ref_deref, clippy::option_filter_map, clippy::option_map_unit_fn, clippy::or_then_unwrap, clippy::overflow_check_conditional, clippy::partialeq_ne_impl, clippy::precedence, clippy::ptr_offset_with_cast, clippy::range_zip_with_len, clippy::redundant_as_str, clippy::redundant_async_block, clippy::redundant_at_rest_pattern, clippy::redundant_closure_call, clippy::redundant_guards, clippy::redundant_slicing, clippy::repeat_once, clippy::reserve_after_initialization, clippy::result_filter_map, clippy::result_map_unit_fn, clippy::search_is_some, clippy::seek_from_current, clippy::seek_to_start_instead_of_rewind, clippy::short_circuit_statement, clippy::single_element_loop, clippy::skip_while_next, clippy::string_from_utf8_as_bytes, clippy::strlen_on_c_strings, clippy::temporary_assignment, clippy::too_many_arguments, clippy::transmute_bytes_to_str, clippy::transmute_float_to_int, clippy::transmute_int_to_bool, clippy::transmute_int_to_char, clippy::transmute_int_to_float, clippy::transmute_int_to_non_zero, clippy::transmute_num_to_bytes, clippy::transmute_ptr_to_ref, clippy::transmutes_expressible_as_ptr_casts, clippy::type_complexity, clippy::unit_arg, clippy::unnecessary_cast, clippy::unnecessary_filter_map, clippy::unnecessary_find_map, clippy::unnecessary_literal_unwrap, clippy::unnecessary_map_on_constructor, clippy::unnecessary_min_or_max, clippy::unnecessary_operation, clippy::unnecessary_sort_by, clippy::unnecessary_unwrap, clippy::unneeded_wildcard_pattern, clippy::unused_format_specs, clippy::useless_asref, clippy::useless_conversion, clippy::useless_format, clippy::useless_transmute, clippy::vec_box, clippy::while_let_loop, clippy::wildcard_in_or_patterns, clippy::zero_divided_by_zero, clippy::zero_prefixed_literal"##, }, children: &[ "clippy::bind_instead_of_map", @@ -13808,12 +14012,14 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::iter_count", "clippy::iter_kv_map", "clippy::let_with_type_underscore", + "clippy::manual_clamp", "clippy::manual_filter", "clippy::manual_filter_map", "clippy::manual_find", "clippy::manual_find_map", "clippy::manual_flatten", "clippy::manual_hash_one", + "clippy::manual_inspect", "clippy::manual_main_separator_str", "clippy::manual_range_patterns", "clippy::manual_rem_euclid", @@ -13887,6 +14093,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unnecessary_find_map", "clippy::unnecessary_literal_unwrap", "clippy::unnecessary_map_on_constructor", + "clippy::unnecessary_min_or_max", "clippy::unnecessary_operation", "clippy::unnecessary_sort_by", "clippy::unnecessary_unwrap", @@ -13906,7 +14113,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::correctness", - description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::eager_transmute, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::ifs_same_cond, clippy::impl_hash_borrow_with_str_and_bytes, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::lint_groups_priority, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mismatched_target_os, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, + description: r##"lint group for: clippy::absurd_extreme_comparisons, clippy::almost_swapped, clippy::approx_constant, clippy::async_yields_async, clippy::bad_bit_mask, clippy::cast_slice_different_sizes, clippy::deprecated_semver, clippy::derive_ord_xor_partial_ord, clippy::derived_hash_with_manual_eq, clippy::eager_transmute, clippy::enum_clike_unportable_variant, clippy::eq_op, clippy::erasing_op, clippy::fn_address_comparisons, clippy::if_let_mutex, clippy::ifs_same_cond, clippy::impl_hash_borrow_with_str_and_bytes, clippy::impossible_comparisons, clippy::ineffective_bit_mask, clippy::infinite_iter, clippy::inherent_to_string_shadow_display, clippy::inline_fn_without_body, clippy::invalid_null_ptr_usage, clippy::invalid_regex, clippy::invisible_characters, clippy::iter_next_loop, clippy::iter_skip_zero, clippy::iterator_step_by_zero, clippy::let_underscore_lock, clippy::lint_groups_priority, clippy::match_str_case_mismatch, clippy::mem_replace_with_uninit, clippy::min_max, clippy::mistyped_literal_suffixes, clippy::modulo_one, clippy::mut_from_ref, clippy::never_loop, clippy::non_octal_unix_permissions, clippy::nonsensical_open_options, clippy::not_unsafe_ptr_arg_deref, clippy::option_env_unwrap, clippy::out_of_bounds_indexing, clippy::overly_complex_bool_expr, clippy::panicking_unwrap, clippy::possible_missing_comma, clippy::read_line_without_trim, clippy::recursive_format_impl, clippy::redundant_comparisons, clippy::redundant_locals, clippy::reversed_empty_ranges, clippy::self_assignment, clippy::serde_api_misuse, clippy::size_of_in_element_count, clippy::suspicious_splitn, clippy::transmute_null_to_fn, clippy::transmuting_null, clippy::uninit_assumed_init, clippy::uninit_vec, clippy::unit_cmp, clippy::unit_hash, clippy::unit_return_expecting_ord, clippy::unsound_collection_transmute, clippy::unused_io_amount, clippy::useless_attribute, clippy::vec_resize_to_zero, clippy::while_immutable_condition, clippy::wrong_transmute, clippy::zst_offset"##, }, children: &[ "clippy::absurd_extreme_comparisons", @@ -13942,7 +14149,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::match_str_case_mismatch", "clippy::mem_replace_with_uninit", "clippy::min_max", - "clippy::mismatched_target_os", "clippy::mistyped_literal_suffixes", "clippy::modulo_one", "clippy::mut_from_ref", @@ -13983,7 +14189,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::deprecated", - description: r##"lint group for: clippy::assign_ops, clippy::extend_from_slice, clippy::filter_map, clippy::find_map, clippy::if_let_redundant_pattern_matching, clippy::misaligned_transmute, clippy::pub_enum_variant_names, clippy::range_step_by_zero, clippy::regex_macro, clippy::replace_consts, clippy::should_assert_eq, clippy::unsafe_vector_initialization, clippy::unstable_as_mut_slice, clippy::unstable_as_slice, clippy::unused_collect, clippy::wrong_pub_self_convention"##, + description: r##"lint group for: clippy::assign_ops, clippy::extend_from_slice, clippy::filter_map, clippy::find_map, clippy::if_let_redundant_pattern_matching, clippy::maybe_misused_cfg, clippy::misaligned_transmute, clippy::mismatched_target_os, clippy::pub_enum_variant_names, clippy::range_step_by_zero, clippy::regex_macro, clippy::replace_consts, clippy::should_assert_eq, clippy::unsafe_vector_initialization, clippy::unstable_as_mut_slice, clippy::unstable_as_slice, clippy::unused_collect, clippy::wrong_pub_self_convention"##, }, children: &[ "clippy::assign_ops", @@ -13991,7 +14197,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::filter_map", "clippy::find_map", "clippy::if_let_redundant_pattern_matching", + "clippy::maybe_misused_cfg", "clippy::misaligned_transmute", + "clippy::mismatched_target_os", "clippy::pub_enum_variant_names", "clippy::range_step_by_zero", "clippy::regex_macro", @@ -14007,7 +14215,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::nursery", - description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::manual_clamp, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::read_zero_byte_vec, clippy::readonly_write_lock, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::uninhabited_references, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq"##, + description: r##"lint group for: clippy::as_ptr_cast_mut, clippy::branches_sharing_code, clippy::clear_with_drain, clippy::cognitive_complexity, clippy::collection_is_never_read, clippy::debug_assert_with_mut_call, clippy::derive_partial_eq_without_eq, clippy::empty_line_after_doc_comments, clippy::empty_line_after_outer_attr, clippy::equatable_if_let, clippy::fallible_impl_from, clippy::future_not_send, clippy::imprecise_flops, clippy::iter_on_empty_collections, clippy::iter_on_single_items, clippy::iter_with_drain, clippy::large_stack_frames, clippy::missing_const_for_fn, clippy::mutex_integer, clippy::needless_collect, clippy::needless_pass_by_ref_mut, clippy::non_send_fields_in_send_ty, clippy::nonstandard_macro_braces, clippy::option_if_let_else, clippy::or_fun_call, clippy::path_buf_push_overwrite, clippy::read_zero_byte_vec, clippy::redundant_clone, clippy::redundant_pub_crate, clippy::set_contains_or_insert, clippy::significant_drop_in_scrutinee, clippy::significant_drop_tightening, clippy::string_lit_as_bytes, clippy::suboptimal_flops, clippy::suspicious_operation_groupings, clippy::trailing_empty_array, clippy::trait_duplication_in_bounds, clippy::transmute_undefined_repr, clippy::trivial_regex, clippy::tuple_array_conversions, clippy::type_repetition_in_bounds, clippy::uninhabited_references, clippy::unnecessary_struct_initialization, clippy::unused_peekable, clippy::unused_rounding, clippy::use_self, clippy::useless_let_if_seq, clippy::while_float"##, }, children: &[ "clippy::as_ptr_cast_mut", @@ -14027,7 +14235,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::iter_on_single_items", "clippy::iter_with_drain", "clippy::large_stack_frames", - "clippy::manual_clamp", "clippy::missing_const_for_fn", "clippy::mutex_integer", "clippy::needless_collect", @@ -14038,9 +14245,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::or_fun_call", "clippy::path_buf_push_overwrite", "clippy::read_zero_byte_vec", - "clippy::readonly_write_lock", "clippy::redundant_clone", "clippy::redundant_pub_crate", + "clippy::set_contains_or_insert", "clippy::significant_drop_in_scrutinee", "clippy::significant_drop_tightening", "clippy::string_lit_as_bytes", @@ -14058,14 +14265,16 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unused_rounding", "clippy::use_self", "clippy::useless_let_if_seq", + "clippy::while_float", ], }, LintGroup { lint: Lint { label: "clippy::pedantic", - description: r##"lint group for: clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_filter_is_ok, clippy::iter_filter_is_some, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_c_str_literals, clippy::manual_instant_elapsed, clippy::manual_is_variant_and, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_as_ref_cloned, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::pub_underscore_fields, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_as_ptr, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_match_else, clippy::stable_sort_primitive, clippy::str_split_at_newline, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, + description: r##"lint group for: clippy::assigning_clones, clippy::bool_to_int_with_if, clippy::borrow_as_ptr, clippy::case_sensitive_file_extension_comparisons, clippy::cast_lossless, clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_ptr_alignment, clippy::cast_sign_loss, clippy::checked_conversions, clippy::cloned_instead_of_copied, clippy::copy_iterator, clippy::default_trait_access, clippy::doc_link_with_quotes, clippy::doc_markdown, clippy::empty_enum, clippy::enum_glob_use, clippy::expl_impl_clone_on_copy, clippy::explicit_deref_methods, clippy::explicit_into_iter_loop, clippy::explicit_iter_loop, clippy::filter_map_next, clippy::flat_map_option, clippy::float_cmp, clippy::fn_params_excessive_bools, clippy::from_iter_instead_of_collect, clippy::if_not_else, clippy::ignored_unit_patterns, clippy::implicit_clone, clippy::implicit_hasher, clippy::inconsistent_struct_constructor, clippy::index_refutable_slice, clippy::inefficient_to_string, clippy::inline_always, clippy::into_iter_without_iter, clippy::invalid_upcast_comparisons, clippy::items_after_statements, clippy::iter_filter_is_ok, clippy::iter_filter_is_some, clippy::iter_not_returning_iterator, clippy::iter_without_into_iter, clippy::large_digit_groups, clippy::large_futures, clippy::large_stack_arrays, clippy::large_types_passed_by_value, clippy::linkedlist, clippy::macro_use_imports, clippy::manual_assert, clippy::manual_c_str_literals, clippy::manual_instant_elapsed, clippy::manual_is_variant_and, clippy::manual_let_else, clippy::manual_ok_or, clippy::manual_string_new, clippy::many_single_char_names, clippy::map_unwrap_or, clippy::match_bool, clippy::match_on_vec_items, clippy::match_same_arms, clippy::match_wild_err_arm, clippy::match_wildcard_for_single_variants, clippy::maybe_infinite_iter, clippy::mismatching_type_param_order, clippy::missing_errors_doc, clippy::missing_fields_in_debug, clippy::missing_panics_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::mut_mut, clippy::naive_bytecount, clippy::needless_bitwise_bool, clippy::needless_continue, clippy::needless_for_each, clippy::needless_pass_by_value, clippy::needless_raw_string_hashes, clippy::no_effect_underscore_binding, clippy::no_mangle_with_rust_abi, clippy::option_as_ref_cloned, clippy::option_option, clippy::ptr_as_ptr, clippy::ptr_cast_constness, clippy::pub_underscore_fields, clippy::range_minus_one, clippy::range_plus_one, clippy::redundant_closure_for_method_calls, clippy::redundant_else, clippy::ref_as_ptr, clippy::ref_binding_to_reference, clippy::ref_option_ref, clippy::return_self_not_must_use, clippy::same_functions_in_if_condition, clippy::semicolon_if_nothing_returned, clippy::should_panic_without_expect, clippy::similar_names, clippy::single_char_pattern, clippy::single_match_else, clippy::stable_sort_primitive, clippy::str_split_at_newline, clippy::string_add_assign, clippy::struct_excessive_bools, clippy::struct_field_names, clippy::too_many_lines, clippy::transmute_ptr_to_ptr, clippy::trivially_copy_pass_by_ref, clippy::unchecked_duration_subtraction, clippy::unicode_not_nfc, clippy::uninlined_format_args, clippy::unnecessary_box_returns, clippy::unnecessary_join, clippy::unnecessary_wraps, clippy::unnested_or_patterns, clippy::unreadable_literal, clippy::unsafe_derive_deserialize, clippy::unused_async, clippy::unused_self, clippy::used_underscore_binding, clippy::verbose_bit_mask, clippy::wildcard_imports, clippy::zero_sized_map_values"##, }, children: &[ + "clippy::assigning_clones", "clippy::bool_to_int_with_if", "clippy::borrow_as_ptr", "clippy::case_sensitive_file_extension_comparisons", @@ -14160,6 +14369,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::semicolon_if_nothing_returned", "clippy::should_panic_without_expect", "clippy::similar_names", + "clippy::single_char_pattern", "clippy::single_match_else", "clippy::stable_sort_primitive", "clippy::str_split_at_newline", @@ -14189,11 +14399,10 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::perf", - description: r##"lint group for: clippy::box_collection, clippy::box_default, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_nth, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_spin_loop, clippy::redundant_allocation, clippy::result_large_err, clippy::single_char_pattern, clippy::slow_vector_initialization, clippy::thread_local_initializer_can_be_made_const, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push, clippy::waker_clone_wake"##, + description: r##"lint group for: clippy::box_collection, clippy::boxed_local, clippy::cmp_owned, clippy::collapsible_str_replace, clippy::drain_collect, clippy::expect_fun_call, clippy::extend_with_drain, clippy::format_collect, clippy::format_in_format_args, clippy::iter_overeager_cloned, clippy::large_const_arrays, clippy::large_enum_variant, clippy::manual_memcpy, clippy::manual_retain, clippy::manual_str_repeat, clippy::manual_try_fold, clippy::map_entry, clippy::missing_const_for_thread_local, clippy::missing_spin_loop, clippy::readonly_write_lock, clippy::redundant_allocation, clippy::result_large_err, clippy::slow_vector_initialization, clippy::to_string_in_format_args, clippy::unnecessary_to_owned, clippy::useless_vec, clippy::vec_init_then_push, clippy::waker_clone_wake"##, }, children: &[ "clippy::box_collection", - "clippy::box_default", "clippy::boxed_local", "clippy::cmp_owned", "clippy::collapsible_str_replace", @@ -14202,7 +14411,6 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::extend_with_drain", "clippy::format_collect", "clippy::format_in_format_args", - "clippy::iter_nth", "clippy::iter_overeager_cloned", "clippy::large_const_arrays", "clippy::large_enum_variant", @@ -14211,12 +14419,12 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::manual_str_repeat", "clippy::manual_try_fold", "clippy::map_entry", + "clippy::missing_const_for_thread_local", "clippy::missing_spin_loop", + "clippy::readonly_write_lock", "clippy::redundant_allocation", "clippy::result_large_err", - "clippy::single_char_pattern", "clippy::slow_vector_initialization", - "clippy::thread_local_initializer_can_be_made_const", "clippy::to_string_in_format_args", "clippy::unnecessary_to_owned", "clippy::useless_vec", @@ -14227,7 +14435,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::restriction", - description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_enum_variants_with_brackets, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::infinite_loop, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::iter_over_hash_type, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, + description: r##"lint group for: clippy::absolute_paths, clippy::alloc_instead_of_core, clippy::allow_attributes, clippy::allow_attributes_without_reason, clippy::arithmetic_side_effects, clippy::as_conversions, clippy::as_underscore, clippy::assertions_on_result_states, clippy::big_endian_bytes, clippy::cfg_not_test, clippy::clone_on_ref_ptr, clippy::create_dir, clippy::dbg_macro, clippy::decimal_literal_representation, clippy::default_numeric_fallback, clippy::default_union_representation, clippy::deref_by_slicing, clippy::disallowed_script_idents, clippy::else_if_without_else, clippy::empty_drop, clippy::empty_enum_variants_with_brackets, clippy::empty_structs_with_brackets, clippy::error_impl_error, clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::exit, clippy::expect_used, clippy::field_scoped_visibility_modifiers, clippy::filetype_is_file, clippy::float_arithmetic, clippy::float_cmp_const, clippy::fn_to_numeric_cast_any, clippy::format_push_string, clippy::get_unwrap, clippy::host_endian_bytes, clippy::if_then_some_else_none, clippy::impl_trait_in_params, clippy::implicit_return, clippy::indexing_slicing, clippy::infinite_loop, clippy::inline_asm_x86_att_syntax, clippy::inline_asm_x86_intel_syntax, clippy::integer_division, clippy::integer_division_remainder_used, clippy::iter_over_hash_type, clippy::large_include_file, clippy::let_underscore_must_use, clippy::let_underscore_untyped, clippy::little_endian_bytes, clippy::lossy_float_literal, clippy::map_err_ignore, clippy::mem_forget, clippy::min_ident_chars, clippy::missing_assert_message, clippy::missing_asserts_for_indexing, clippy::missing_docs_in_private_items, clippy::missing_inline_in_public_items, clippy::missing_trait_methods, clippy::mixed_read_write_in_expression, clippy::mod_module_files, clippy::modulo_arithmetic, clippy::multiple_inherent_impl, clippy::multiple_unsafe_ops_per_block, clippy::mutex_atomic, clippy::needless_raw_strings, clippy::non_ascii_literal, clippy::panic, clippy::panic_in_result_fn, clippy::partial_pub_fields, clippy::pattern_type_mismatch, clippy::print_stderr, clippy::print_stdout, clippy::pub_use, clippy::pub_with_shorthand, clippy::pub_without_shorthand, clippy::question_mark_used, clippy::rc_buffer, clippy::rc_mutex, clippy::redundant_type_annotations, clippy::ref_patterns, clippy::renamed_function_params, clippy::rest_pat_in_fully_bound_structs, clippy::same_name_method, clippy::self_named_module_files, clippy::semicolon_inside_block, clippy::semicolon_outside_block, clippy::separated_literal_suffix, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_call_fn, clippy::single_char_lifetime_names, clippy::std_instead_of_alloc, clippy::std_instead_of_core, clippy::str_to_string, clippy::string_add, clippy::string_lit_chars_any, clippy::string_slice, clippy::string_to_string, clippy::suspicious_xor_used_as_pow, clippy::tests_outside_test_module, clippy::todo, clippy::try_err, clippy::undocumented_unsafe_blocks, clippy::unimplemented, clippy::unnecessary_safety_comment, clippy::unnecessary_safety_doc, clippy::unnecessary_self_imports, clippy::unneeded_field_pattern, clippy::unreachable, clippy::unseparated_literal_suffix, clippy::unwrap_in_result, clippy::unwrap_used, clippy::use_debug, clippy::verbose_file_reads, clippy::wildcard_enum_match_arm"##, }, children: &[ "clippy::absolute_paths", @@ -14239,6 +14447,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::as_underscore", "clippy::assertions_on_result_states", "clippy::big_endian_bytes", + "clippy::cfg_not_test", "clippy::clone_on_ref_ptr", "clippy::create_dir", "clippy::dbg_macro", @@ -14256,6 +14465,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::exhaustive_structs", "clippy::exit", "clippy::expect_used", + "clippy::field_scoped_visibility_modifiers", "clippy::filetype_is_file", "clippy::float_arithmetic", "clippy::float_cmp_const", @@ -14271,6 +14481,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::inline_asm_x86_att_syntax", "clippy::inline_asm_x86_intel_syntax", "clippy::integer_division", + "clippy::integer_division_remainder_used", "clippy::iter_over_hash_type", "clippy::large_include_file", "clippy::let_underscore_must_use", @@ -14307,6 +14518,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::rc_mutex", "clippy::redundant_type_annotations", "clippy::ref_patterns", + "clippy::renamed_function_params", "clippy::rest_pat_in_fully_bound_structs", "clippy::same_name_method", "clippy::self_named_module_files", @@ -14347,7 +14559,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::style", - description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::builtin_type_shadow, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::if_same_then_else, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_range_contains, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_enforced_import_renames, clippy::missing_safety_doc, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_err_ok, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::to_string_trait_impl, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fallible_conversions, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_enumerate_index, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, + description: r##"lint group for: clippy::assertions_on_constants, clippy::assign_op_pattern, clippy::blocks_in_conditions, clippy::bool_assert_comparison, clippy::borrow_interior_mutable_const, clippy::box_default, clippy::builtin_type_shadow, clippy::byte_char_slices, clippy::bytes_nth, clippy::chars_last_cmp, clippy::chars_next_cmp, clippy::cmp_null, clippy::collapsible_else_if, clippy::collapsible_if, clippy::collapsible_match, clippy::comparison_chain, clippy::comparison_to_empty, clippy::declare_interior_mutable_const, clippy::default_instead_of_iter_empty, clippy::disallowed_macros, clippy::disallowed_methods, clippy::disallowed_names, clippy::disallowed_types, clippy::doc_lazy_continuation, clippy::double_must_use, clippy::double_neg, clippy::duplicate_underscore_argument, clippy::enum_variant_names, clippy::err_expect, clippy::excessive_precision, clippy::field_reassign_with_default, clippy::filter_map_bool_then, clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation, clippy::for_kv_map, clippy::from_over_into, clippy::from_str_radix_10, clippy::get_first, clippy::if_same_then_else, clippy::implicit_saturating_add, clippy::implicit_saturating_sub, clippy::inconsistent_digit_grouping, clippy::infallible_destructuring_match, clippy::inherent_to_string, clippy::init_numbered_fields, clippy::into_iter_on_ref, clippy::is_digit_ascii_radix, clippy::items_after_test_module, clippy::iter_cloned_collect, clippy::iter_next_slice, clippy::iter_nth, clippy::iter_nth_zero, clippy::iter_skip_next, clippy::just_underscores_and_digits, clippy::legacy_numeric_constants, clippy::len_without_is_empty, clippy::len_zero, clippy::let_and_return, clippy::let_unit_value, clippy::main_recursion, clippy::manual_async_fn, clippy::manual_bits, clippy::manual_is_ascii_check, clippy::manual_is_finite, clippy::manual_is_infinite, clippy::manual_map, clippy::manual_next_back, clippy::manual_non_exhaustive, clippy::manual_pattern_char_comparison, clippy::manual_range_contains, clippy::manual_rotate, clippy::manual_saturating_arithmetic, clippy::manual_while_let_some, clippy::map_clone, clippy::map_collect_result_unit, clippy::match_like_matches_macro, clippy::match_overlapping_arm, clippy::match_ref_pats, clippy::match_result_ok, clippy::mem_replace_option_with_none, clippy::mem_replace_with_default, clippy::missing_enforced_import_renames, clippy::missing_safety_doc, clippy::mixed_attributes_style, clippy::mixed_case_hex_literals, clippy::module_inception, clippy::must_use_unit, clippy::mut_mutex_lock, clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::needless_doctest_main, clippy::needless_else, clippy::needless_late_init, clippy::needless_parens_on_range_literals, clippy::needless_pub_self, clippy::needless_range_loop, clippy::needless_return, clippy::needless_return_with_question_mark, clippy::neg_multiply, clippy::new_ret_no_self, clippy::new_without_default, clippy::non_minimal_cfg, clippy::obfuscated_if_else, clippy::ok_expect, clippy::op_ref, clippy::option_map_or_err_ok, clippy::option_map_or_none, clippy::partialeq_to_none, clippy::print_literal, clippy::print_with_newline, clippy::println_empty_string, clippy::ptr_arg, clippy::ptr_eq, clippy::question_mark, clippy::redundant_closure, clippy::redundant_field_names, clippy::redundant_pattern, clippy::redundant_pattern_matching, clippy::redundant_static_lifetimes, clippy::result_map_or_into_option, clippy::result_unit_err, clippy::same_item_push, clippy::self_named_constructors, clippy::should_implement_trait, clippy::single_char_add_str, clippy::single_component_path_imports, clippy::single_match, clippy::string_extend_chars, clippy::tabs_in_doc_comments, clippy::to_digit_is_some, clippy::to_string_trait_impl, clippy::toplevel_ref_arg, clippy::trim_split_whitespace, clippy::unnecessary_fallible_conversions, clippy::unnecessary_fold, clippy::unnecessary_lazy_evaluations, clippy::unnecessary_mut_passed, clippy::unnecessary_owned_empty_strings, clippy::unsafe_removed_from_name, clippy::unused_enumerate_index, clippy::unused_unit, clippy::unusual_byte_groupings, clippy::unwrap_or_default, clippy::upper_case_acronyms, clippy::while_let_on_iterator, clippy::write_literal, clippy::write_with_newline, clippy::writeln_empty_string, clippy::wrong_self_convention, clippy::zero_ptr"##, }, children: &[ "clippy::assertions_on_constants", @@ -14355,7 +14567,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::blocks_in_conditions", "clippy::bool_assert_comparison", "clippy::borrow_interior_mutable_const", + "clippy::box_default", "clippy::builtin_type_shadow", + "clippy::byte_char_slices", "clippy::bytes_nth", "clippy::chars_last_cmp", "clippy::chars_next_cmp", @@ -14371,6 +14585,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::disallowed_methods", "clippy::disallowed_names", "clippy::disallowed_types", + "clippy::doc_lazy_continuation", "clippy::double_must_use", "clippy::double_neg", "clippy::duplicate_underscore_argument", @@ -14397,9 +14612,11 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::items_after_test_module", "clippy::iter_cloned_collect", "clippy::iter_next_slice", + "clippy::iter_nth", "clippy::iter_nth_zero", "clippy::iter_skip_next", "clippy::just_underscores_and_digits", + "clippy::legacy_numeric_constants", "clippy::len_without_is_empty", "clippy::len_zero", "clippy::let_and_return", @@ -14413,7 +14630,9 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::manual_map", "clippy::manual_next_back", "clippy::manual_non_exhaustive", + "clippy::manual_pattern_char_comparison", "clippy::manual_range_contains", + "clippy::manual_rotate", "clippy::manual_saturating_arithmetic", "clippy::manual_while_let_some", "clippy::map_clone", @@ -14426,6 +14645,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::mem_replace_with_default", "clippy::missing_enforced_import_renames", "clippy::missing_safety_doc", + "clippy::mixed_attributes_style", "clippy::mixed_case_hex_literals", "clippy::module_inception", "clippy::must_use_unit", @@ -14497,7 +14717,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ LintGroup { lint: Lint { label: "clippy::suspicious", - description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::crate_in_macro_def, clippy::deprecated_clippy_cfg_attr, clippy::drop_non_drop, clippy::duplicate_mod, clippy::empty_docs, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::incompatible_msrv, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::maybe_misused_cfg, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::mixed_attributes_style, clippy::multi_assignments, clippy::multiple_bound_locations, clippy::mut_range_bound, clippy::mutable_key_type, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_open_options, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion, clippy::unnecessary_clippy_cfg, clippy::unnecessary_get_then_check, clippy::unnecessary_result_map_or_else"##, + description: r##"lint group for: clippy::almost_complete_range, clippy::arc_with_non_send_sync, clippy::await_holding_invalid_type, clippy::await_holding_lock, clippy::await_holding_refcell_ref, clippy::blanket_clippy_restriction_lints, clippy::cast_abs_to_unsigned, clippy::cast_enum_constructor, clippy::cast_enum_truncation, clippy::cast_nan_to_int, clippy::cast_slice_from_raw_parts, clippy::const_is_empty, clippy::crate_in_macro_def, clippy::deprecated_clippy_cfg_attr, clippy::drop_non_drop, clippy::duplicate_mod, clippy::duplicated_attributes, clippy::empty_docs, clippy::empty_loop, clippy::float_equality_without_abs, clippy::forget_non_drop, clippy::four_forward_slashes, clippy::from_raw_with_void_ptr, clippy::incompatible_msrv, clippy::ineffective_open_options, clippy::iter_out_of_bounds, clippy::join_absolute_paths, clippy::let_underscore_future, clippy::lines_filter_map_ok, clippy::macro_metavars_in_unsafe, clippy::manual_unwrap_or_default, clippy::misnamed_getters, clippy::misrefactored_assign_op, clippy::missing_transmute_annotations, clippy::multi_assignments, clippy::multiple_bound_locations, clippy::mut_range_bound, clippy::mutable_key_type, clippy::needless_character_iteration, clippy::needless_maybe_sized, clippy::no_effect_replace, clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, clippy::octal_escapes, clippy::path_ends_with_ext, clippy::permissions_set_readonly_false, clippy::print_in_format_impl, clippy::rc_clone_in_vec_init, clippy::repeat_vec_with_capacity, clippy::single_range_in_vec_init, clippy::size_of_ref, clippy::suspicious_arithmetic_impl, clippy::suspicious_assignment_formatting, clippy::suspicious_command_arg_space, clippy::suspicious_doc_comments, clippy::suspicious_else_formatting, clippy::suspicious_map, clippy::suspicious_op_assign_impl, clippy::suspicious_open_options, clippy::suspicious_to_owned, clippy::suspicious_unary_op_formatting, clippy::swap_ptr_to_ref, clippy::test_attr_in_doctest, clippy::type_id_on_box, clippy::unconditional_recursion, clippy::unnecessary_clippy_cfg, clippy::unnecessary_get_then_check, clippy::unnecessary_result_map_or_else, clippy::zero_repeat_side_effects"##, }, children: &[ "clippy::almost_complete_range", @@ -14511,10 +14731,12 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::cast_enum_truncation", "clippy::cast_nan_to_int", "clippy::cast_slice_from_raw_parts", + "clippy::const_is_empty", "clippy::crate_in_macro_def", "clippy::deprecated_clippy_cfg_attr", "clippy::drop_non_drop", "clippy::duplicate_mod", + "clippy::duplicated_attributes", "clippy::empty_docs", "clippy::empty_loop", "clippy::float_equality_without_abs", @@ -14527,14 +14749,17 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::join_absolute_paths", "clippy::let_underscore_future", "clippy::lines_filter_map_ok", - "clippy::maybe_misused_cfg", + "clippy::macro_metavars_in_unsafe", + "clippy::manual_unwrap_or_default", "clippy::misnamed_getters", "clippy::misrefactored_assign_op", - "clippy::mixed_attributes_style", + "clippy::missing_transmute_annotations", "clippy::multi_assignments", "clippy::multiple_bound_locations", "clippy::mut_range_bound", "clippy::mutable_key_type", + "clippy::needless_character_iteration", + "clippy::needless_maybe_sized", "clippy::no_effect_replace", "clippy::non_canonical_clone_impl", "clippy::non_canonical_partial_ord_impl", @@ -14563,6 +14788,7 @@ pub const CLIPPY_LINT_GROUPS: &[LintGroup] = &[ "clippy::unnecessary_clippy_cfg", "clippy::unnecessary_get_then_check", "clippy::unnecessary_result_map_or_else", + "clippy::zero_repeat_side_effects", ], }, ]; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 9d1f1cc09c6..81604b55272 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1222,6 +1222,26 @@ use self::foo::{self, Bar, Foo}; ); } +#[test] +fn insert_with_double_colon_prefixed_import_merge() { + check_with_config( + "use ::ext::foo::Foo", + r#" +use ::ext::foo::Foo as _; +"#, + r#" +use ::ext::foo::Foo; +"#, + &InsertUseConfig { + granularity: ImportGranularity::Crate, + prefix_kind: hir::PrefixKind::BySelf, + enforce_granularity: true, + group: true, + skip_glob_imports: true, + }, + ); +} + fn check_with_config( path: &str, ra_fixture_before: &str, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs index b153aafa0e1..9cacb6b1a60 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/merge_imports.rs @@ -157,10 +157,14 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior) } match (tree_contains_self(lhs_t), tree_contains_self(&rhs_t)) { - (Some(true), None) => continue, + (Some(true), None) => { + remove_subtree_if_only_self(lhs_t); + continue; + } (None, Some(true)) => { ted::replace(lhs_t.syntax(), rhs_t.syntax()); *lhs_t = rhs_t; + remove_subtree_if_only_self(lhs_t); continue; } _ => (), @@ -278,14 +282,20 @@ pub fn try_normalize_use_tree_mut( fn recursive_normalize(use_tree: &ast::UseTree, style: NormalizationStyle) -> Option<()> { let use_tree_list = use_tree.use_tree_list()?; let merge_subtree_into_parent_tree = |single_subtree: &ast::UseTree| { + let subtree_is_only_self = single_subtree.path().as_ref().map_or(false, path_is_self); + let merged_path = match (use_tree.path(), single_subtree.path()) { + // If the subtree is `{self}` then we cannot merge: `use + // foo::bar::{self}` is not equivalent to `use foo::bar`. See + // https://github.com/rust-lang/rust-analyzer/pull/17140#issuecomment-2079189725. + _ if subtree_is_only_self => None, + (None, None) => None, (Some(outer), None) => Some(outer), - (None, Some(inner)) if path_is_self(&inner) => None, (None, Some(inner)) => Some(inner), - (Some(outer), Some(inner)) if path_is_self(&inner) => Some(outer), (Some(outer), Some(inner)) => Some(make::path_concat(outer, inner).clone_for_update()), }; + if merged_path.is_some() || single_subtree.use_tree_list().is_some() || single_subtree.star_token().is_some() @@ -706,3 +716,20 @@ fn path_is_self(path: &ast::Path) -> bool { fn path_len(path: ast::Path) -> usize { path.segments().count() } + +fn get_single_subtree(use_tree: &ast::UseTree) -> Option<ast::UseTree> { + use_tree + .use_tree_list() + .and_then(|tree_list| tree_list.use_trees().collect_tuple()) + .map(|(single_subtree,)| single_subtree) +} + +fn remove_subtree_if_only_self(use_tree: &ast::UseTree) { + let Some(single_subtree) = get_single_subtree(use_tree) else { return }; + match (use_tree.path(), single_subtree.path()) { + (Some(_), Some(inner)) if path_is_self(&inner) => { + ted::remove_all_iter(single_subtree.syntax().children_with_tokens()); + } + _ => (), + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 357209ceb0b..8fac5baa57b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -2,8 +2,6 @@ //! //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod apply_change; pub mod active_parameter; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 7c11dd3e2a4..e21d54ccd0e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -6,7 +6,7 @@ use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope}; use itertools::Itertools; use rustc_hash::FxHashMap; use syntax::{ - ast::{self, make, AstNode}, + ast::{self, make, AstNode, HasGenericArgs}, ted, SyntaxNode, }; @@ -308,8 +308,11 @@ impl Ctx<'_> { parent.segment()?.name_ref()?, ) .and_then(|trait_ref| { - let cfg = - ImportPathConfig { prefer_no_std: false, prefer_prelude: true }; + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }; let found_path = self.target_module.find_path( self.source_scope.db.upcast(), hir::ModuleDef::Trait(trait_ref), @@ -348,7 +351,11 @@ impl Ctx<'_> { } } - let cfg = ImportPathConfig { prefer_no_std: false, prefer_prelude: true }; + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }; let found_path = self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?; let res = mod_path_to_ast(&found_path).clone_for_update(); @@ -383,7 +390,11 @@ impl Ctx<'_> { if let Some(adt) = ty.as_adt() { if let ast::Type::PathType(path_ty) = &ast_ty { - let cfg = ImportPathConfig { prefer_no_std: false, prefer_prelude: true }; + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }; let found_path = self.target_module.find_path( self.source_scope.db.upcast(), ModuleDef::from(adt), diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs b/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs index ab2a250289c..eacd9b9b4d2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rust_doc.rs @@ -7,11 +7,7 @@ pub fn is_rust_fence(s: &str) -> bool { let mut seen_rust_tags = false; let mut seen_other_tags = false; - let tokens = s - .trim() - .split(|c| c == ',' || c == ' ' || c == '\t') - .map(str::trim) - .filter(|t| !t.is_empty()); + let tokens = s.trim().split([',', ' ', '\t']).map(str::trim).filter(|t| !t.is_empty()); for token in tokens { match token { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index b62f34f4157..e1cfe048983 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -320,7 +320,6 @@ impl Definition { hir::GenericDef::TraitAlias(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()), - hir::GenericDef::Variant(it) => it.source(db).map(|src| src.syntax().cloned()), hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()), }; return match def { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs index 9f56e104145..d3f30207752 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs @@ -1,16 +1,23 @@ use hir::InFile; +use syntax::{AstNode, TextRange}; -use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: incoherent-impl // // This diagnostic is triggered if the targe type of an impl is from a foreign crate. pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic { - Diagnostic::new_with_syntax_node_ptr( - ctx, + let display_range = adjusted_display_range(ctx, InFile::new(d.file_id, d.impl_), &|node| { + Some(TextRange::new( + node.syntax().text_range().start(), + node.self_ty()?.syntax().text_range().end(), + )) + }); + + Diagnostic::new( DiagnosticCode::RustcHardError("E0210"), "cannot define inherent `impl` for foreign type".to_owned(), - InFile::new(d.file_id, d.impl_.into()), + display_range, ) } @@ -23,7 +30,7 @@ mod change_case { check_diagnostics( r#" impl bool {} -//^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +//^^^^^^^^^ error: cannot define inherent `impl` for foreign type "#, ); } @@ -60,7 +67,7 @@ impl foo::S { pub struct S; //- /main.rs crate:main deps:foo impl foo::S { #[rustc_allow_incoherent_impl] fn func(self) {} } -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +//^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type "#, ); check_diagnostics( @@ -70,7 +77,7 @@ pub struct S; pub struct S; //- /main.rs crate:main deps:foo impl foo::S { fn func(self) {} } -//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type +//^^^^^^^^^^^ error: cannot define inherent `impl` for foreign type "#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 2b8779044fb..a9c0e3b7319 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -146,6 +146,7 @@ pub(crate) fn json_in_items( let cfg = ImportPathConfig { prefer_no_std: config.prefer_no_std, prefer_prelude: config.prefer_prelude, + prefer_absolute: config.prefer_absolute, }; if !scope_has("Serialize") { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index f8780fc0da7..2cd6a71c001 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -13,7 +13,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> ) } -// Diagnostic: macro-error +// Diagnostic: macro-def-error // // This diagnostic is shown for macro expansion errors. pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefError) -> Diagnostic { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 9eff84b8987..6a809cb0cef 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -128,6 +128,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, )?; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index be1e6ed5722..a470ce72fc3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -28,10 +28,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let function = id; ( format!("`fn {redundant_assoc_item_name}`"), - function - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), + function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), format!("\n {};", function.display(db)), ) } @@ -39,10 +36,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let constant = id; ( format!("`const {redundant_assoc_item_name}`"), - constant - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), + constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), format!("\n {};", constant.display(db)), ) } @@ -50,10 +44,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( let type_alias = id; ( format!("`type {redundant_assoc_item_name}`"), - type_alias - .source(db) - .map(|it| it.syntax().value.text_range()) - .unwrap_or(default_range), + type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), format!("\n type {};", type_alias.name(ctx.sema.db).to_smol_str()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 9651ce6106b..4f04267adb1 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -47,7 +47,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist> sema: &ctx.sema, scope: &scope, goal: d.expected.clone(), - config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() }, + config: TermSearchConfig { + fuel: ctx.config.term_search_fuel, + enable_borrowcheck: ctx.config.term_search_borrowck, + + ..Default::default() + }, }; let paths = term_search(&term_search_ctx); @@ -62,6 +67,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist> ImportPathConfig { prefer_no_std: ctx.config.prefer_no_std, prefer_prelude: ctx.config.prefer_prelude, + prefer_absolute: ctx.config.prefer_absolute, }, ) .ok() @@ -276,7 +282,7 @@ impl Foo for Baz { } fn asd() -> Bar { let a = Baz; - Foo::foo(_) + Foo::foo(a) } ", ); @@ -365,7 +371,7 @@ impl Foo for A { } fn main() { let a = A; - let c: Bar = Foo::foo(_); + let c: Bar = Foo::foo(&a); }"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs index cbf50d13f58..77ffd0fd968 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -30,11 +30,13 @@ pub(crate) fn unlinked_file( // FIXME: This is a hack for the vscode extension to notice whether there is an autofix or not before having to resolve diagnostics. // This is to prevent project linking popups from appearing when there is an autofix. https://github.com/rust-lang/rust-analyzer/issues/14523 let message = if fixes.is_none() { - "file not included in crate hierarchy" + "This file is not included in any crates, so rust-analyzer can't offer IDE services." } else { - "file not included in module tree" + "This file is not included anywhere in the module tree, so rust-analyzer can't offer IDE services." }; + let message = format!("{message}\n\nIf you're intentionally working on unowned files, you can silence this warning by adding \"unlinked-file\" to rust-analyzer.diagnostics.disabled in your settings."); + let mut range = ctx.sema.db.parse(file_id).syntax_node().text_range(); let mut unused = true; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs index 7aa3e16536c..9a81682aaeb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs @@ -56,4 +56,20 @@ fn main() { "#, ); } + + #[test] + fn unresolved_self_val() { + check_diagnostics( + r#" +fn main() { + self.a; + //^^^^ error: no such value in this scope + let self: + self = + self; + //^^^^ error: no such value in this scope +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index a419f04bfae..6d1226d65c5 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -23,8 +23,6 @@ //! There are also a couple of ad-hoc diagnostics implemented directly here, we //! don't yet have a great pattern for how to do them properly. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod handlers { pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; @@ -233,7 +231,9 @@ pub struct DiagnosticsConfig { pub insert_use: InsertUseConfig, pub prefer_no_std: bool, pub prefer_prelude: bool, + pub prefer_absolute: bool, pub term_search_fuel: u64, + pub term_search_borrowck: bool, } impl DiagnosticsConfig { @@ -259,7 +259,9 @@ impl DiagnosticsConfig { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, term_search_fuel: 400, + term_search_borrowck: true, } } } @@ -311,9 +313,13 @@ pub fn diagnostics( FileRange { file_id, range: err.range() }, ) })); + let parse_errors = res.len(); let parse = sema.parse(file_id); + // FIXME: This iterates the entire file which is a rather expensive operation. + // We should implement these differently in some form? + // Salsa caching + incremental re-parse would be better here for node in parse.syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); @@ -326,7 +332,10 @@ pub fn diagnostics( let mut diags = Vec::new(); match module { - Some(m) => m.diagnostics(db, &mut diags, config.style_lints), + // A bunch of parse errors in a file indicate some bigger structural parse changes in the + // file, so we skip semantic diagnostics so we can show these faster. + Some(m) if parse_errors < 16 => m.diagnostics(db, &mut diags, config.style_lints), + Some(_) => (), None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id), } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index b5bf510aeed..407433ed192 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -3,8 +3,6 @@ //! Allows searching the AST for code that matches one or more patterns and then replacing that code //! based on a template. -#![warn(rust_2018_idioms, unused_lifetimes)] - // Feature: Structural Search and Replace // // Search and replace with named wildcards that will match any expression, type, path, pattern or item. diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index b29053c0c2d..7c357b3c217 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -10,7 +10,7 @@ use hir::{ImportPathConfig, Semantics}; use ide_db::{base_db::FileRange, FxHashMap}; use std::{cell::Cell, iter::Peekable}; use syntax::{ - ast::{self, AstNode, AstToken}, + ast::{self, AstNode, AstToken, HasGenericArgs}, SmolStr, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, }; @@ -663,7 +663,11 @@ impl Match { .module(); for (path, resolved_path) in &template.resolved_paths { if let hir::PathResolution::Def(module_def) = resolved_path.resolution { - let cfg = ImportPathConfig { prefer_no_std: false, prefer_prelude: true }; + let cfg = ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }; let mod_path = module.find_path(sema.db, module_def, cfg).ok_or_else(|| { match_error!("Failed to render template path `{}` at match location") })?; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs index 4731f14f4e6..d3c1af1f31e 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/resolving.rs @@ -3,7 +3,10 @@ use hir::AsAssocItem; use ide_db::{base_db::FilePosition, FxHashMap}; use parsing::Placeholder; -use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; +use syntax::{ + ast::{self, HasGenericArgs}, + SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, +}; use crate::{errors::error, parsing, SsrError}; diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml index a535015a27f..9d8400ba3ad 100644 --- a/src/tools/rust-analyzer/crates/ide/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml @@ -25,6 +25,7 @@ dot.workspace = true smallvec.workspace = true triomphe.workspace = true nohash-hasher.workspace = true +rustc_apfloat = "0.2.0" # local deps cfg.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index f7e5b40dde1..3c29f2f4276 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -9,14 +9,15 @@ use ide_db::{ search::FileReference, FxIndexMap, RootDatabase, }; -use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange}; +use span::FileRange; +use syntax::{ast, AstNode, SyntaxKind::IDENT}; use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; #[derive(Debug, Clone)] pub struct CallItem { pub target: NavigationTarget, - pub ranges: Vec<TextRange>, + pub ranges: Vec<FileRange>, } pub(crate) fn call_hierarchy( @@ -61,9 +62,10 @@ pub(crate) fn incoming_calls( def.try_to_nav(sema.db) }); if let Some(nav) = nav { - calls.add(nav.call_site, sema.original_range(name.syntax()).range); + let range = sema.original_range(name.syntax()); + calls.add(nav.call_site, range); if let Some(other) = nav.def_site { - calls.add(other, sema.original_range(name.syntax()).range); + calls.add(other, range); } } } @@ -107,12 +109,13 @@ pub(crate) fn outgoing_calls( hir::CallableKind::TupleStruct(it) => it.try_to_nav(db), _ => None, } - .zip(Some(expr.syntax().text_range())) + .zip(Some(sema.original_range(expr.syntax()))) } ast::CallableExpr::MethodCall(expr) => { - let range = expr.name_ref()?.syntax().text_range(); let function = sema.resolve_method_call(&expr)?; - function.try_to_nav(db).zip(Some(range)) + function + .try_to_nav(db) + .zip(Some(sema.original_range(expr.name_ref()?.syntax()))) } }?; Some(nav_target.into_iter().zip(iter::repeat(range))) @@ -125,11 +128,11 @@ pub(crate) fn outgoing_calls( #[derive(Default)] struct CallLocations { - funcs: FxIndexMap<NavigationTarget, Vec<TextRange>>, + funcs: FxIndexMap<NavigationTarget, Vec<FileRange>>, } impl CallLocations { - fn add(&mut self, target: NavigationTarget, range: TextRange) { + fn add(&mut self, target: NavigationTarget, range: FileRange) { self.funcs.entry(target).or_default().push(range); } @@ -153,7 +156,14 @@ mod tests { expected_outgoing: Expect, ) { fn debug_render(item: crate::CallItem) -> String { - format!("{} : {:?}", item.target.debug_render(), item.ranges) + format!( + "{} : {}", + item.target.debug_render(), + item.ranges.iter().format_with(", ", |range, f| f(&format_args!( + "{:?}:{:?}", + range.file_id, range.range + ))) + ) } let (analysis, pos) = fixture::position(ra_fixture); @@ -183,7 +193,7 @@ fn caller() { } "#, expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], + expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"], expect![[]], ); } @@ -199,7 +209,7 @@ fn caller() { } "#, expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..44 18..24 : [33..39]"]], + expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"], expect![[]], ); } @@ -216,7 +226,7 @@ fn caller() { } "#, expect![["callee Function FileId(0) 0..14 3..9"]], - expect![["caller Function FileId(0) 15..58 18..24 : [33..39, 47..53]"]], + expect!["caller Function FileId(0) 15..58 18..24 : FileId(0):33..39, FileId(0):47..53"], expect![[]], ); } @@ -236,9 +246,9 @@ fn caller2() { } "#, expect![["callee Function FileId(0) 0..14 3..9"]], - expect![[" - caller1 Function FileId(0) 15..45 18..25 : [34..40] - caller2 Function FileId(0) 47..77 50..57 : [66..72]"]], + expect![[r#" + caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40 + caller2 Function FileId(0) 47..77 50..57 : FileId(0):66..72"#]], expect![[]], ); } @@ -265,8 +275,8 @@ mod tests { "#, expect![["callee Function FileId(0) 0..14 3..9"]], expect![[r#" - caller1 Function FileId(0) 15..45 18..25 : [34..40] - test_caller Function FileId(0) 95..149 110..121 tests : [134..140]"#]], + caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40 + test_caller Function FileId(0) 95..149 110..121 tests : FileId(0):134..140"#]], expect![[]], ); } @@ -287,7 +297,7 @@ fn caller() { pub fn callee() {} "#, expect!["callee Function FileId(1) 0..18 7..13 foo"], - expect![["caller Function FileId(0) 27..56 30..36 : [45..51]"]], + expect!["caller Function FileId(0) 27..56 30..36 : FileId(0):45..51"], expect![[]], ); } @@ -305,7 +315,7 @@ fn call$0er() { "#, expect![["caller Function FileId(0) 15..58 18..24"]], expect![[]], - expect![["callee Function FileId(0) 0..14 3..9 : [33..39, 47..53]"]], + expect!["callee Function FileId(0) 0..14 3..9 : FileId(0):33..39, FileId(0):47..53"], ); } @@ -326,7 +336,7 @@ pub fn callee() {} "#, expect![["caller Function FileId(0) 27..56 30..36"]], expect![[]], - expect!["callee Function FileId(1) 0..18 7..13 foo : [45..51]"], + expect!["callee Function FileId(1) 0..18 7..13 foo : FileId(0):45..51"], ); } @@ -348,8 +358,8 @@ fn caller3() { } "#, expect![["caller2 Function FileId(0) 33..64 36..43"]], - expect![["caller1 Function FileId(0) 0..31 3..10 : [19..26]"]], - expect![["caller3 Function FileId(0) 66..83 69..76 : [52..59]"]], + expect!["caller1 Function FileId(0) 0..31 3..10 : FileId(0):19..26"], + expect!["caller3 Function FileId(0) 66..83 69..76 : FileId(0):52..59"], ); } @@ -368,8 +378,8 @@ fn main() { } "#, expect![["a Function FileId(0) 0..18 3..4"]], - expect![["main Function FileId(0) 31..52 34..38 : [47..48]"]], - expect![["b Function FileId(0) 20..29 23..24 : [13..14]"]], + expect!["main Function FileId(0) 31..52 34..38 : FileId(0):47..48"], + expect!["b Function FileId(0) 20..29 23..24 : FileId(0):13..14"], ); check_hierarchy( @@ -385,7 +395,7 @@ fn main() { } "#, expect![["b Function FileId(0) 20..29 23..24"]], - expect![["a Function FileId(0) 0..18 3..4 : [13..14]"]], + expect!["a Function FileId(0) 0..18 3..4 : FileId(0):13..14"], expect![[]], ); } @@ -410,7 +420,7 @@ fn caller() { } "#, expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], + expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"], expect![[]], ); check_hierarchy( @@ -431,7 +441,7 @@ fn caller() { } "#, expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect![[r#"caller Function FileId(0) 160..194 163..169 : [184..190]"#]], + expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"], expect![[]], ); } @@ -461,6 +471,148 @@ fn caller$0() { expect![[]], ); } + #[test] + fn test_call_hierarchy_in_macros_incoming_different_files() { + check_hierarchy( + r#" +//- /lib.rs +#[macro_use] +mod foo; +define!(callee) +fn caller() { + call!(call$0ee); +} +//- /foo.rs +macro_rules! define { + ($ident:ident) => { + fn $ident {} + } +} +macro_rules! call { + ($ident:ident) => { + $ident() + } +} +"#, + expect!["callee Function FileId(0) 22..37 30..36"], + expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"], + expect![[]], + ); + check_hierarchy( + r#" +//- /lib.rs +#[macro_use] +mod foo; +define!(cal$0lee) +fn caller() { + call!(callee); +} +//- /foo.rs +macro_rules! define { + ($ident:ident) => { + fn $ident {} + } +} +macro_rules! call { + ($ident:ident) => { + $ident() + } +} +"#, + expect!["callee Function FileId(0) 22..37 30..36"], + expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"], + expect![[]], + ); + check_hierarchy( + r#" +//- /lib.rs +#[macro_use] +mod foo; +define!(cal$0lee) +call!(callee); +//- /foo.rs +macro_rules! define { + ($ident:ident) => { + fn $ident {} + } +} +macro_rules! call { + ($ident:ident) => { + fn caller() { + $ident() + } + fn $ident() { + $ident() + } + } +} +"#, + expect!["callee Function FileId(0) 22..37 30..36"], + expect![[r#" + callee Function FileId(0) 38..52 44..50 : FileId(0):44..50 + caller Function FileId(0) 38..52 : FileId(0):44..50 + caller Function FileId(1) 130..136 130..136 : FileId(0):44..50"#]], + expect![[]], + ); + } + + #[test] + fn test_call_hierarchy_in_macros_outgoing_different_files() { + check_hierarchy( + r#" +//- /lib.rs +#[macro_use] +mod foo; +define!(callee) +fn caller$0() { + call!(callee); +} +//- /foo.rs +macro_rules! define { + ($ident:ident) => { + fn $ident {} + } +} +macro_rules! call { + ($ident:ident) => { + $ident() + callee() + } +} +"#, + expect!["caller Function FileId(0) 38..72 41..47"], + expect![[]], + // FIXME + expect![[]], + ); + check_hierarchy( + r#" +//- /lib.rs +#[macro_use] +mod foo; +define!(callee) +fn caller$0() { + call!(callee); +} +//- /foo.rs +macro_rules! define { + () => { + fn callee {} + } +} +macro_rules! call { + ($ident:ident) => { + $ident() + callee() + } +} +"#, + expect!["caller Function FileId(0) 38..72 41..47"], + expect![[]], + // FIXME + expect![[]], + ); + } #[test] fn test_trait_method_call_hierarchy() { @@ -481,7 +633,7 @@ fn caller() { } "#, expect!["callee Function FileId(0) 15..27 18..24 T1"], - expect![["caller Function FileId(0) 82..115 85..91 : [104..110]"]], + expect!["caller Function FileId(0) 82..115 85..91 : FileId(0):104..110"], expect![[]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 99568c9922b..7091b15b8a4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -16,6 +16,10 @@ use ide_db::{ RootDatabase, }; use itertools::Itertools; +use rustc_apfloat::{ + ieee::{Half as f16, Quad as f128}, + Float, +}; use stdx::format_to; use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T}; @@ -540,13 +544,22 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> ast::Char(char) => char .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string), ast::Byte(byte) => byte .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")), ast::FloatNumber(num) => { - let (text, _) = num.split_into_parts(); - let text = text.replace('_', ""); - if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) { + let text = num.value_string(); + if ty.as_builtin().map(|it| it.is_f16()).unwrap_or(false) { + match text.parse::<f16>() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.0.to_owned()), + } + } else if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) { match text.parse::<f32>() { Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), Err(e) => Err(e.to_string()), } + } else if ty.as_builtin().map(|it| it.is_f128()).unwrap_or(false) { + match text.parse::<f128>() { + Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), + Err(e) => Err(e.0.to_owned()), + } } else { match text.parse::<f64>() { Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 20d07bf9919..5036770fec8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -5310,6 +5310,71 @@ const FOO$0: f64 = expf64(1.2); ``` "#]], ); + // check `f32` isn't double rounded via `f64` + check( + r#" +/// This is a doc +const FOO$0: f32 = 1.9999999403953552_f32; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f32 = 1.9999999 + ``` + + --- + + This is a doc + "#]], + ); + // Check `f16` and `f128` + check( + r#" +/// This is a doc +const FOO$0: f16 = -1.0f16; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f16 = -1.0 + ``` + + --- + + This is a doc + "#]], + ); + check( + r#" +/// This is a doc +const FOO$0: f128 = -1.0f128; +"#, + expect![[r#" + *FOO* + + ```rust + test + ``` + + ```rust + const FOO: f128 = -1.0 + ``` + + --- + + This is a doc + "#]], + ); } #[test] @@ -6138,7 +6203,7 @@ fn hover_feature() { by the codegen backend, but not the MIR inliner. ```rust - #![feature(rustc_attrs, effects)] + #![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -6148,7 +6213,7 @@ fn hover_feature() { Since these are just regular functions, it is perfectly ok to create the intrinsic twice: ```rust - #![feature(rustc_attrs, effects)] + #![feature(rustc_attrs)] #![allow(internal_features)] #[rustc_intrinsic] @@ -6172,12 +6237,23 @@ fn hover_feature() { Various intrinsics have native MIR operations that they correspond to. Instead of requiring backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass will convert the calls to the MIR operation. Backends do not need to know about these intrinsics - at all. + at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic" + or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist + anymore after MIR analyses. ## Intrinsics without fallback logic These must be implemented by all backends. + ### `#[rustc_intrinsic]` declarations + + These are written like intrinsics with fallback bodies, but the body is irrelevant. + Use `loop {}` for the body or call the intrinsic recursively and add + `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't + invoke the body. + + ### Legacy extern ABI based intrinsics + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and @@ -8013,6 +8089,22 @@ fn main() { check( r#" fn main() { + $01.0f16; +} +"#, + expect![[r#" + *1.0f16* + ```rust + f16 + ``` + ___ + + value of literal: 1 (bits: 0x3C00) + "#]], + ); + check( + r#" +fn main() { $01.0f32; } "#, @@ -8029,6 +8121,22 @@ fn main() { check( r#" fn main() { + $01.0f128; +} +"#, + expect![[r#" + *1.0f128* + ```rust + f128 + ``` + ___ + + value of literal: 1 (bits: 0x3FFF0000000000000000000000000000) + "#]], + ); + check( + r#" +fn main() { $0134e12; } "#, @@ -8357,8 +8465,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 7791..7999, - focus_range: 7856..7862, + full_range: 7800..8008, + focus_range: 7865..7871, name: "Future", kind: Trait, container_name: "future", @@ -8371,8 +8479,8 @@ impl Iterator for S { file_id: FileId( 1, ), - full_range: 8629..9095, - focus_range: 8673..8681, + full_range: 8638..9104, + focus_range: 8682..8690, name: "Iterator", kind: Trait, container_name: "iterator", diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 3f10bed5110..944951f26a2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -29,6 +29,7 @@ mod closure_captures; mod closure_ret; mod discriminant; mod fn_lifetime_fn; +mod generic_param; mod implicit_drop; mod implicit_static; mod param_name; @@ -40,6 +41,7 @@ pub struct InlayHintsConfig { pub type_hints: bool, pub discriminant_hints: DiscriminantHints, pub parameter_hints: bool, + pub generic_parameter_hints: GenericParameterHints, pub chaining_hints: bool, pub adjustment_hints: AdjustmentHints, pub adjustment_hints_mode: AdjustmentHintsMode, @@ -95,6 +97,13 @@ pub enum DiscriminantHints { } #[derive(Clone, Debug, PartialEq, Eq)] +pub struct GenericParameterHints { + pub type_hints: bool, + pub lifetime_hints: bool, + pub const_hints: bool, +} + +#[derive(Clone, Debug, PartialEq, Eq)] pub enum LifetimeElisionHints { Always, SkipTrivial, @@ -127,6 +136,7 @@ pub enum InlayKind { GenericParamList, Lifetime, Parameter, + GenericParameter, Type, Drop, RangeExclusive, @@ -447,6 +457,7 @@ fn ty_to_text_edit( // // * types of local variables // * names of function arguments +// * names of const generic parameters // * types of chained expressions // // Optionally, one can enable additional hints for @@ -454,6 +465,7 @@ fn ty_to_text_edit( // * return types of closure expressions // * elided lifetimes // * compiler inserted reborrows +// * names of generic type and lifetime parameters // // Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if // any of the @@ -543,6 +555,9 @@ fn hints( node: SyntaxNode, ) { closing_brace::hints(hints, sema, config, file_id, node.clone()); + if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { + generic_param::hints(hints, sema, config, any_has_generic_args); + } match_ast! { match node { ast::Expr(expr) => { @@ -645,13 +660,18 @@ mod tests { use crate::DiscriminantHints; use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints}; - use super::{ClosureReturnTypeHints, InlayFieldsToResolve}; + use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve}; pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig { discriminant_hints: DiscriminantHints::Never, render_colons: false, type_hints: false, parameter_hints: false, + generic_parameter_hints: GenericParameterHints { + type_hints: false, + lifetime_hints: false, + const_hints: false, + }, chaining_hints: false, lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 3311bb48ad6..1118f11d99d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -8,7 +8,7 @@ use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase}; use itertools::Itertools; use syntax::{ - ast::{self, AstNode, HasName}, + ast::{self, AstNode, HasGenericArgs, HasName}, match_ast, }; diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs new file mode 100644 index 00000000000..51855eeae23 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -0,0 +1,315 @@ +//! Implementation of inlay hints for generic parameters. +use ide_db::{active_parameter::generic_def_for_node, RootDatabase}; +use syntax::{ + ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName}, + AstNode, +}; + +use crate::{inlay_hints::GenericParameterHints, InlayHint, InlayHintsConfig, InlayKind}; + +use super::param_name::{is_argument_similar_to_param_name, render_label}; + +pub(crate) fn hints( + acc: &mut Vec<InlayHint>, + sema: &hir::Semantics<'_, RootDatabase>, + config: &InlayHintsConfig, + node: AnyHasGenericArgs, +) -> Option<()> { + let GenericParameterHints { type_hints, lifetime_hints, const_hints } = + config.generic_parameter_hints; + if !(type_hints || lifetime_hints || const_hints) { + return None; + } + + let generic_arg_list = node.generic_arg_list()?; + + let (generic_def, _, _, _) = + generic_def_for_node(sema, &generic_arg_list, &node.syntax().first_token()?)?; + + let mut args = generic_arg_list.generic_args().peekable(); + let start_with_lifetime = matches!(args.peek()?, ast::GenericArg::LifetimeArg(_)); + let params = generic_def.params(sema.db).into_iter().filter(|p| { + if let hir::GenericParam::TypeParam(it) = p { + if it.is_implicit(sema.db) { + return false; + } + } + if !start_with_lifetime { + return !matches!(p, hir::GenericParam::LifetimeParam(_)); + } + true + }); + + let hints = params.zip(args).filter_map(|(param, arg)| { + if matches!(arg, ast::GenericArg::AssocTypeArg(_)) { + return None; + } + + let name = param.name(sema.db); + let param_name = name.as_str()?; + + let should_hide = { + let argument = get_string_representation(&arg)?; + is_argument_similar_to_param_name(&argument, param_name) + }; + + if should_hide { + return None; + } + + let range = sema.original_range_opt(arg.syntax())?.range; + + let source_syntax = match param { + hir::GenericParam::TypeParam(it) => { + if !type_hints || !matches!(arg, ast::GenericArg::TypeArg(_)) { + return None; + } + sema.source(it.merge())?.value.syntax().clone() + } + hir::GenericParam::ConstParam(it) => { + if !const_hints || !matches!(arg, ast::GenericArg::ConstArg(_)) { + return None; + } + let syntax = sema.source(it.merge())?.value.syntax().clone(); + let const_param = ast::ConstParam::cast(syntax)?; + const_param.name()?.syntax().clone() + } + hir::GenericParam::LifetimeParam(it) => { + if !lifetime_hints || !matches!(arg, ast::GenericArg::LifetimeArg(_)) { + return None; + } + sema.source(it)?.value.syntax().clone() + } + }; + let linked_location = sema.original_range_opt(&source_syntax); + let label = render_label(param_name, config, linked_location); + + Some(InlayHint { + range, + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: InlayKind::GenericParameter, + label, + text_edit: None, + }) + }); + + acc.extend(hints); + Some(()) +} + +fn get_string_representation(arg: &ast::GenericArg) -> Option<String> { + return match arg { + ast::GenericArg::AssocTypeArg(_) => None, + ast::GenericArg::ConstArg(const_arg) => Some(const_arg.to_string()), + ast::GenericArg::LifetimeArg(lifetime_arg) => { + let lifetime = lifetime_arg.lifetime()?; + Some(lifetime.to_string()) + } + ast::GenericArg::TypeArg(type_arg) => { + let ty = type_arg.ty()?; + Some( + type_path_segment(&ty) + .map_or_else(|| type_arg.to_string(), |segment| segment.to_string()), + ) + } + }; + + fn type_path_segment(ty: &ast::Type) -> Option<ast::PathSegment> { + match ty { + ast::Type::ArrayType(it) => type_path_segment(&it.ty()?), + ast::Type::ForType(it) => type_path_segment(&it.ty()?), + ast::Type::ParenType(it) => type_path_segment(&it.ty()?), + ast::Type::PathType(path_type) => path_type.path()?.segment(), + ast::Type::PtrType(it) => type_path_segment(&it.ty()?), + ast::Type::RefType(it) => type_path_segment(&it.ty()?), + ast::Type::SliceType(it) => type_path_segment(&it.ty()?), + _ => None, + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + inlay_hints::{ + tests::{check_with_config, DISABLED_CONFIG}, + GenericParameterHints, + }, + InlayHintsConfig, + }; + + #[track_caller] + fn generic_param_name_hints_always(ra_fixture: &str) { + check_with_config( + InlayHintsConfig { + generic_parameter_hints: GenericParameterHints { + type_hints: true, + lifetime_hints: true, + const_hints: true, + }, + ..DISABLED_CONFIG + }, + ra_fixture, + ); + } + + #[track_caller] + fn generic_param_name_hints_const_only(ra_fixture: &str) { + check_with_config( + InlayHintsConfig { + generic_parameter_hints: GenericParameterHints { + type_hints: false, + lifetime_hints: false, + const_hints: true, + }, + ..DISABLED_CONFIG + }, + ra_fixture, + ); + } + + #[test] + fn type_only() { + generic_param_name_hints_always( + r#" +struct A<X, Y> { + x: X, + y: Y, +} + +fn foo(a: A<usize, u32>) {} + //^^^^^ X ^^^ Y +"#, + ) + } + + #[test] + fn lifetime_and_type() { + generic_param_name_hints_always( + r#" +struct A<'a, X> { + x: &'a X +} + +fn foo<'b>(a: A<'b, u32>) {} + //^^ 'a^^^ X +"#, + ) + } + + #[test] + fn omit_lifetime() { + generic_param_name_hints_always( + r#" +struct A<'a, X> { + x: &'a X +} + +fn foo() { + let x: i32 = 1; + let a: A<i32> = A { x: &x }; + // ^^^ X +} +"#, + ) + } + + #[test] + fn const_only() { + generic_param_name_hints_always( + r#" +struct A<const X: usize, const Y: usize> {}; + +fn foo(a: A<12, 2>) {} + //^^ X^ Y +"#, + ) + } + + #[test] + fn lifetime_and_type_and_const() { + generic_param_name_hints_always( + r#" +struct A<'a, X, const LEN: usize> { + x: &'a [X; LEN], +} + +fn foo<'b>(a: A< + 'b, + // ^^ 'a + u32, + // ^^^ X + 3 + // ^ LEN + >) {} +"#, + ) + } + + #[test] + fn const_only_config() { + generic_param_name_hints_const_only( + r#" +struct A<'a, X, const LEN: usize> { + x: &'a [X; LEN], +} + +fn foo<'b>(a: A< + 'b, + u32, + 3 + // ^ LEN + >) {} +"#, + ) + } + + #[test] + fn assoc_type() { + generic_param_name_hints_always( + r#" +trait Trait<T> { + type Assoc1; + type Assoc2; +} + +fn foo() -> impl Trait<i32, Assoc1 = u32, Assoc2 = u32> {} + // ^^^ T +"#, + ) + } + + #[test] + fn hide_similar() { + generic_param_name_hints_always( + r#" +struct A<'a, X, const N: usize> { + x: &'a [X; N], +} + +const N: usize = 3; + +mod m { + type X = u32; +} + +fn foo<'a>(a: A<'a, m::X, N>) {} +"#, + ) + } + + #[test] + fn mismatching_args() { + generic_param_name_hints_always( + r#" +struct A<X, const N: usize> { + x: [X; N] +} + +type InvalidType = A<3, i32>; +"#, + ) + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index 9819d0e3fbb..2e2a64c5520 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -3,6 +3,8 @@ //! fn max(x: i32, y: i32) -> i32 { x + y } //! _ = max(/*x*/4, /*y*/4); //! ``` +use std::fmt::Display; + use either::Either; use hir::{Callable, Semantics}; use ide_db::{base_db::FileRange, RootDatabase}; @@ -46,9 +48,7 @@ pub(super) fn hints( .map(|(param, param_name, _, FileRange { range, .. })| { let linked_location = param.and_then(|name| sema.original_range_opt(name.syntax())); - let colon = if config.render_colons { ":" } else { "" }; - let label = - InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location); + let label = render_label(¶m_name, config, linked_location); InlayHint { range, kind: InlayKind::Parameter, @@ -64,6 +64,16 @@ pub(super) fn hints( Some(()) } +pub(super) fn render_label( + param_name: impl Display, + config: &InlayHintsConfig, + linked_location: Option<FileRange>, +) -> InlayHintLabel { + let colon = if config.render_colons { ":" } else { "" }; + + InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location) +} + fn get_callable( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, @@ -113,7 +123,7 @@ fn should_hide_param_name_hint( }; let fn_name = fn_name.as_deref(); is_param_name_suffix_of_fn_name(param_name, callable, fn_name) - || is_argument_similar_to_param_name(argument, param_name) + || is_argument_expr_similar_to_param_name(argument, param_name) || param_name.starts_with("ra_fixture") || (callable.n_params() == 1 && is_obvious_param(param_name)) || is_adt_constructor_similar_to_param_name(sema, argument, param_name) @@ -143,14 +153,17 @@ fn is_param_name_suffix_of_fn_name( } } -fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { - // check whether param_name and argument are the same or - // whether param_name is a prefix/suffix of argument(split at `_`) +fn is_argument_expr_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { let argument = match get_string_representation(argument) { Some(argument) => argument, None => return false, }; + is_argument_similar_to_param_name(&argument, param_name) +} +/// Check whether param_name and argument are the same or +/// whether param_name is a prefix/suffix of argument(split at `_`). +pub(super) fn is_argument_similar_to_param_name(argument: &str, param_name: &str) -> bool { // std is honestly too panic happy... let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at)); diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index a2ac62341df..f0b35903f38 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -8,7 +8,7 @@ //! in this crate. // For proving that RootDatabase is RefUnwindSafe. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "128"] @@ -89,8 +89,8 @@ pub use crate::{ }, inlay_hints::{ AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, - InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, - InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, + GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, + InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, }, join_lines::JoinLinesConfig, markup::Markup, diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 2feea09840f..a68ee4f8671 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -78,7 +78,6 @@ impl RunnableKind { } impl Runnable { - // test package::module::testname pub fn label(&self, target: Option<&str>) -> String { match &self.kind { RunnableKind::Test { test_id, .. } => format!("test {test_id}"), @@ -86,7 +85,7 @@ impl Runnable { RunnableKind::Bench { test_id } => format!("bench {test_id}"), RunnableKind::DocTest { test_id, .. } => format!("doctest {test_id}"), RunnableKind::Bin => { - target.map_or_else(|| "run binary".to_owned(), |t| format!("run {t}")) + format!("run {}", target.unwrap_or("binary")) } } } @@ -513,11 +512,11 @@ impl TestAttr { } } -const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; -const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = - &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; - fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { + const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"]; + const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = + &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; + docs_from_attrs(attrs).map_or(false, |doc| { let mut in_code_block = false; diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 89c725a6c47..c5eaacdb10d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -272,7 +272,7 @@ fn signature_help_for_generics( arg_list: ast::GenericArgList, token: SyntaxToken, ) -> Option<SignatureHelp> { - let (mut generics_def, mut active_parameter, first_arg_is_non_lifetime) = + let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) = generic_def_for_node(sema, &arg_list, &token)?; let mut res = SignatureHelp { doc: None, @@ -290,6 +290,12 @@ fn signature_help_for_generics( hir::GenericDef::Adt(hir::Adt::Enum(it)) => { res.doc = it.docs(db); format_to!(res.signature, "enum {}", it.name(db).display(db)); + if let Some(variant) = variant { + // In paths, generics of an enum can be specified *after* one of its variants. + // eg. `None::<u8>` + // We'll use the signature of the enum, but include the docs of the variant. + res.doc = variant.docs(db); + } } hir::GenericDef::Adt(hir::Adt::Struct(it)) => { res.doc = it.docs(db); @@ -311,15 +317,6 @@ fn signature_help_for_generics( res.doc = it.docs(db); format_to!(res.signature, "type {}", it.name(db).display(db)); } - hir::GenericDef::Variant(it) => { - // In paths, generics of an enum can be specified *after* one of its variants. - // eg. `None::<u8>` - // We'll use the signature of the enum, but include the docs of the variant. - res.doc = it.docs(db); - let enum_ = it.parent_enum(db); - format_to!(res.signature, "enum {}", enum_.name(db).display(db)); - generics_def = enum_.into(); - } // These don't have generic args that can be specified hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None, } diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 0d2311b6e98..5eb5c87f13e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -131,6 +131,11 @@ impl StaticIndex<'_> { discriminant_hints: crate::DiscriminantHints::Fieldless, type_hints: true, parameter_hints: true, + generic_parameter_hints: crate::GenericParameterHints { + type_hints: false, + lifetime_hints: false, + const_hints: true, + }, chaining_hints: true, closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, lifetime_elision_hints: crate::LifetimeElisionHints::Never, diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs index 8e7767c8e5d..b998c0bfc65 100644 --- a/src/tools/rust-analyzer/crates/ide/src/status.rs +++ b/src/tools/rust-analyzer/crates/ide/src/status.rs @@ -20,7 +20,6 @@ use ide_db::{ }; use itertools::Itertools; use profile::{memory_usage, Bytes}; -use std::env; use stdx::format_to; use syntax::{ast, Parse, SyntaxNode}; use triomphe::Arc; @@ -44,9 +43,6 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db))); format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db))); format_to!(buf, "{} in total\n", memory_usage()); - if env::var("RA_COUNT").is_ok() { - format_to!(buf, "\nCounts:\n{}", profile::countme::get_all()); - } format_to!(buf, "\nDebug info:\n"); format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db))); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index 573b3d4bd52..17411fefbd9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -94,10 +94,20 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="brace">}</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> + <span class="brace">}</span><span class="semicolon">;</span> +<span class="brace">}</span> <span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="string_literal macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="keyword">struct</span> <span class="struct declaration">S</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> + <span class="keyword">struct</span> <span class="struct declaration">TestLocal</span><span class="semicolon">;</span> + <span class="comment">// regression test, TestLocal here used to not resolve</span> + <span class="keyword">let</span> <span class="punctuation">_</span><span class="colon">:</span> <span class="struct">S</span><span class="angle"><</span><span class="macro">id</span><span class="macro_bang">!</span><span class="bracket macro">[</span><span class="struct macro">TestLocal</span><span class="bracket macro">]</span><span class="angle">></span><span class="semicolon">;</span> + <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">92</span><span class="comma macro">,</span><span class="parenthesis macro">)</span><span class="operator macro">.</span><span class="field library macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index 08acfca2cb6..5f711600a29 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -102,10 +102,20 @@ macro without_args { } } +macro_rules! id { + ($($tt:tt)*) => { + $($tt)* + }; +} include!(concat!("foo/", "foo.rs")); +struct S<T>(T); fn main() { + struct TestLocal; + // regression test, TestLocal here used to not resolve + let _: S<id![TestLocal]>; + format_args!("Hello, {}!", (92,).0); dont_color_me_braces!(); noop!(noop!(1)); diff --git a/src/tools/rust-analyzer/crates/limit/src/lib.rs b/src/tools/rust-analyzer/crates/limit/src/lib.rs index 27471db6a34..c1caeed2f87 100644 --- a/src/tools/rust-analyzer/crates/limit/src/lib.rs +++ b/src/tools/rust-analyzer/crates/limit/src/lib.rs @@ -1,7 +1,5 @@ //! limit defines a struct to enforce limits. -#![warn(rust_2018_idioms, unused_lifetimes)] - #[cfg(feature = "tracking")] use std::sync::atomic::AtomicUsize; diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml index 2046fa943a8..18444018e1b 100644 --- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml +++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml @@ -16,6 +16,7 @@ cov-mark = "2.0.0-pre.1" rustc-hash.workspace = true smallvec.workspace = true tracing.workspace = true +arrayvec.workspace = true # local deps syntax.workspace = true diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs index 19ba5c7a156..27dbc84a2b1 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs @@ -170,7 +170,7 @@ fn invocation_fixtures( Op::Literal(it) => token_trees.push(tt::Leaf::from(it.clone()).into()), Op::Ident(it) => token_trees.push(tt::Leaf::from(it.clone()).into()), Op::Punct(puncts) => { - for punct in puncts { + for punct in puncts.as_slice() { token_trees.push(tt::Leaf::from(*punct).into()); } } @@ -187,7 +187,7 @@ fn invocation_fixtures( } if i + 1 != cnt { if let Some(sep) = separator { - match sep { + match &**sep { Separator::Literal(it) => { token_trees.push(tt::Leaf::Literal(it.clone()).into()) } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs index 0cec4e70daa..b20d5579ca6 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs @@ -59,17 +59,17 @@ //! eof: [a $( a )* a b ·] //! ``` -use std::rc::Rc; +use std::{rc::Rc, sync::Arc}; use smallvec::{smallvec, SmallVec}; use span::{Edition, Span}; use syntax::SmolStr; -use tt::DelimSpan; +use tt::{iter::TtIter, DelimSpan}; use crate::{ expander::{Binding, Bindings, ExpandResult, Fragment}, + expect_fragment, parser::{MetaVarKind, Op, RepeatKind, Separator}, - tt_iter::TtIter, ExpandError, MetaTemplate, ValueResult, }; @@ -315,7 +315,7 @@ struct MatchState<'t> { up: Option<Box<MatchState<'t>>>, /// The separator if we are in a repetition. - sep: Option<Separator>, + sep: Option<Arc<Separator>>, /// The KleeneOp of this sequence if we are in a repetition. sep_kind: Option<RepeatKind>, @@ -406,7 +406,7 @@ fn match_loop_inner<'t>( if item.sep.is_some() && !item.sep_matched { let sep = item.sep.as_ref().unwrap(); let mut fork = src.clone(); - if fork.expect_separator(sep) { + if expect_separator(&mut fork, sep) { // HACK: here we use `meta_result` to pass `TtIter` back to caller because // it might have been advanced multiple times. `ValueResult` is // insignificant. @@ -746,7 +746,7 @@ fn match_meta_var( ) -> ExpandResult<Option<Fragment>> { let fragment = match kind { MetaVarKind::Path => { - return input.expect_fragment(parser::PrefixEntryPoint::Path, edition).map(|it| { + return expect_fragment(input, parser::PrefixEntryPoint::Path, edition).map(|it| { it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path) }); } @@ -765,7 +765,7 @@ fn match_meta_var( } _ => {} }; - return input.expect_fragment(parser::PrefixEntryPoint::Expr, edition).map(|tt| { + return expect_fragment(input, parser::PrefixEntryPoint::Expr, edition).map(|tt| { tt.map(|tt| match tt { tt::TokenTree::Leaf(leaf) => tt::Subtree { delimiter: tt::Delimiter::invisible_spanned(*leaf.span()), @@ -787,14 +787,13 @@ fn match_meta_var( .expect_ident() .map(|ident| tt::Leaf::from(ident.clone()).into()) .map_err(|()| ExpandError::binding_error("expected ident")), - MetaVarKind::Tt => input - .expect_tt() - .map_err(|()| ExpandError::binding_error("expected token tree")), - MetaVarKind::Lifetime => input - .expect_lifetime() + MetaVarKind::Tt => { + expect_tt(input).map_err(|()| ExpandError::binding_error("expected token tree")) + } + MetaVarKind::Lifetime => expect_lifetime(input) .map_err(|()| ExpandError::binding_error("expected lifetime")), MetaVarKind::Literal => { - let neg = input.eat_char('-'); + let neg = eat_char(input, '-'); input .expect_literal() .map(|literal| { @@ -822,7 +821,7 @@ fn match_meta_var( MetaVarKind::Item => parser::PrefixEntryPoint::Item, MetaVarKind::Vis => parser::PrefixEntryPoint::Vis, }; - input.expect_fragment(fragment, edition).map(|it| it.map(Fragment::Tokens)) + expect_fragment(input, fragment, edition).map(|it| it.map(Fragment::Tokens)) } fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) { @@ -905,86 +904,84 @@ impl<'a> Iterator for OpDelimitedIter<'a> { } } -impl TtIter<'_, Span> { - fn expect_separator(&mut self, separator: &Separator) -> bool { - let mut fork = self.clone(); - let ok = match separator { - Separator::Ident(lhs) => match fork.expect_ident_or_underscore() { - Ok(rhs) => rhs.text == lhs.text, - Err(_) => false, - }, - Separator::Literal(lhs) => match fork.expect_literal() { - Ok(rhs) => match rhs { - tt::Leaf::Literal(rhs) => rhs.text == lhs.text, - tt::Leaf::Ident(rhs) => rhs.text == lhs.text, - tt::Leaf::Punct(_) => false, - }, - Err(_) => false, +fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) -> bool { + let mut fork = iter.clone(); + let ok = match separator { + Separator::Ident(lhs) => match fork.expect_ident_or_underscore() { + Ok(rhs) => rhs.text == lhs.text, + Err(_) => false, + }, + Separator::Literal(lhs) => match fork.expect_literal() { + Ok(rhs) => match rhs { + tt::Leaf::Literal(rhs) => rhs.text == lhs.text, + tt::Leaf::Ident(rhs) => rhs.text == lhs.text, + tt::Leaf::Punct(_) => false, }, - Separator::Puncts(lhs) => match fork.expect_glued_punct() { - Ok(rhs) => { - let lhs = lhs.iter().map(|it| it.char); - let rhs = rhs.iter().map(|it| it.char); - lhs.eq(rhs) - } - Err(_) => false, - }, - }; - if ok { - *self = fork; - } - ok - } - - fn expect_tt(&mut self) -> Result<tt::TokenTree<Span>, ()> { - if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = self.peek_n(0) { - if punct.char == '\'' { - self.expect_lifetime() - } else { - let puncts = self.expect_glued_punct()?; - let delimiter = tt::Delimiter { - open: puncts.first().unwrap().span, - close: puncts.last().unwrap().span, - kind: tt::DelimiterKind::Invisible, - }; - let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect(); - Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter, token_trees })) + Err(_) => false, + }, + Separator::Puncts(lhs) => match fork.expect_glued_punct() { + Ok(rhs) => { + let lhs = lhs.iter().map(|it| it.char); + let rhs = rhs.iter().map(|it| it.char); + lhs.eq(rhs) } - } else { - self.next().ok_or(()).cloned() - } + Err(_) => false, + }, + }; + if ok { + *iter = fork; } + ok +} - fn expect_lifetime(&mut self) -> Result<tt::TokenTree<Span>, ()> { - let punct = self.expect_single_punct()?; - if punct.char != '\'' { - return Err(()); - } - let ident = self.expect_ident_or_underscore()?; - - Ok(tt::Subtree { - delimiter: tt::Delimiter { - open: punct.span, - close: ident.span, +fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> { + if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = iter.peek_n(0) { + if punct.char == '\'' { + expect_lifetime(iter) + } else { + let puncts = iter.expect_glued_punct()?; + let delimiter = tt::Delimiter { + open: puncts.first().unwrap().span, + close: puncts.last().unwrap().span, kind: tt::DelimiterKind::Invisible, - }, - token_trees: Box::new([ - tt::Leaf::Punct(*punct).into(), - tt::Leaf::Ident(ident.clone()).into(), - ]), + }; + let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect(); + Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter, token_trees })) } - .into()) + } else { + iter.next().ok_or(()).cloned() } +} - fn eat_char(&mut self, c: char) -> Option<tt::TokenTree<Span>> { - let mut fork = self.clone(); - match fork.expect_char(c) { - Ok(_) => { - let tt = self.next().cloned(); - *self = fork; - tt - } - Err(_) => None, +fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<tt::TokenTree<S>, ()> { + let punct = iter.expect_single_punct()?; + if punct.char != '\'' { + return Err(()); + } + let ident = iter.expect_ident_or_underscore()?; + + Ok(tt::Subtree { + delimiter: tt::Delimiter { + open: punct.span, + close: ident.span, + kind: tt::DelimiterKind::Invisible, + }, + token_trees: Box::new([ + tt::Leaf::Punct(*punct).into(), + tt::Leaf::Ident(ident.clone()).into(), + ]), + } + .into()) +} + +fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) -> Option<tt::TokenTree<S>> { + let mut fork = iter.clone(); + match fork.expect_char(c) { + Ok(_) => { + let tt = iter.next().cloned(); + *iter = fork; + tt } + Err(_) => None, } } diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 0f689a2692c..c09cbd1d071 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -195,7 +195,7 @@ fn expand_subtree( .into(), ), Op::Punct(puncts) => { - for punct in puncts { + for punct in puncts.as_slice() { arena.push( tt::Leaf::from({ let mut it = *punct; @@ -222,7 +222,7 @@ fn expand_subtree( } Op::Repeat { tokens: subtree, kind, separator } => { let ExpandResult { value: fragment, err: e } = - expand_repeat(ctx, subtree, *kind, separator, arena, marker); + expand_repeat(ctx, subtree, *kind, separator.as_deref(), arena, marker); err = err.or(e); push_fragment(ctx, arena, fragment) } @@ -383,7 +383,7 @@ fn expand_repeat( ctx: &mut ExpandCtx<'_>, template: &MetaTemplate, kind: RepeatKind, - separator: &Option<Separator>, + separator: Option<&Separator>, arena: &mut Vec<tt::TokenTree<Span>>, marker: impl Fn(&mut Span) + Copy, ) -> ExpandResult<Fragment> { diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index ed3200964df..b06c6cee12d 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -6,26 +6,21 @@ //! The tests for this functionality live in another crate: //! `hir_def::macro_expansion_tests::mbe`. -#![warn(rust_2018_idioms, unused_lifetimes)] - mod expander; mod parser; mod syntax_bridge; mod to_parser_input; -mod tt_iter; #[cfg(test)] mod benchmark; use span::{Edition, Span, SyntaxContextId}; use stdx::impl_from; +use tt::iter::TtIter; use std::fmt; -use crate::{ - parser::{MetaTemplate, MetaVarKind, Op}, - tt_iter::TtIter, -}; +use crate::parser::{MetaTemplate, MetaVarKind, Op}; // FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces pub use ::parser::TopEntryPoint; @@ -161,7 +156,7 @@ impl DeclarativeMacro { let mut err = None; while src.len() > 0 { - let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { + let rule = match Rule::parse(edition, &mut src, new_meta_vars) { Ok(it) => it, Err(e) => { err = Some(Box::new(e)); @@ -189,19 +184,34 @@ impl DeclarativeMacro { /// The new, unstable `macro m {}` flavor. pub fn parse_macro2( - tt: &tt::Subtree<Span>, + args: Option<&tt::Subtree<Span>>, + body: &tt::Subtree<Span>, edition: impl Copy + Fn(SyntaxContextId) -> Edition, // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) new_meta_vars: bool, ) -> DeclarativeMacro { - let mut src = TtIter::new(tt); let mut rules = Vec::new(); let mut err = None; - if tt::DelimiterKind::Brace == tt.delimiter.kind { + if let Some(args) = args { + cov_mark::hit!(parse_macro_def_simple); + + let rule = (|| { + let lhs = MetaTemplate::parse_pattern(edition, args)?; + let rhs = MetaTemplate::parse_template(edition, body, new_meta_vars)?; + + Ok(crate::Rule { lhs, rhs }) + })(); + + match rule { + Ok(rule) => rules.push(rule), + Err(e) => err = Some(Box::new(e)), + } + } else { cov_mark::hit!(parse_macro_def_rules); + let mut src = TtIter::new(body); while src.len() > 0 { - let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { + let rule = match Rule::parse(edition, &mut src, new_meta_vars) { Ok(it) => it, Err(e) => { err = Some(Box::new(e)); @@ -218,19 +228,6 @@ impl DeclarativeMacro { break; } } - } else { - cov_mark::hit!(parse_macro_def_simple); - match Rule::parse(edition, &mut src, false, new_meta_vars) { - Ok(rule) => { - if src.len() != 0 { - err = Some(Box::new(ParseError::expected("remaining tokens in macro def"))); - } - rules.push(rule); - } - Err(e) => { - err = Some(Box::new(e)); - } - } } for Rule { lhs, .. } in &rules { @@ -247,6 +244,10 @@ impl DeclarativeMacro { self.err.as_deref() } + pub fn num_rules(&self) -> usize { + self.rules.len() + } + pub fn expand( &self, tt: &tt::Subtree<Span>, @@ -263,14 +264,11 @@ impl Rule { fn parse( edition: impl Copy + Fn(SyntaxContextId) -> Edition, src: &mut TtIter<'_, Span>, - expect_arrow: bool, new_meta_vars: bool, ) -> Result<Self, ParseError> { let lhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; - if expect_arrow { - src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?; - src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?; - } + src.expect_char('=').map_err(|()| ParseError::expected("expected `=`"))?; + src.expect_char('>').map_err(|()| ParseError::expected("expected `>`"))?; let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; let lhs = MetaTemplate::parse_pattern(edition, lhs)?; @@ -361,3 +359,60 @@ impl<T: Default, E> From<Result<T, E>> for ValueResult<T, E> { result.map_or_else(Self::only_err, Self::ok) } } + +fn expect_fragment<S: Copy + fmt::Debug>( + tt_iter: &mut TtIter<'_, S>, + entry_point: ::parser::PrefixEntryPoint, + edition: ::parser::Edition, +) -> ExpandResult<Option<tt::TokenTree<S>>> { + use ::parser; + let buffer = tt::buffer::TokenBuffer::from_tokens(tt_iter.as_slice()); + let parser_input = to_parser_input::to_parser_input(&buffer); + let tree_traversal = entry_point.parse(&parser_input, edition); + let mut cursor = buffer.begin(); + let mut error = false; + for step in tree_traversal.iter() { + match step { + parser::Step::Token { kind, mut n_input_tokens } => { + if kind == ::parser::SyntaxKind::LIFETIME_IDENT { + n_input_tokens = 2; + } + for _ in 0..n_input_tokens { + cursor = cursor.bump_subtree(); + } + } + parser::Step::FloatSplit { .. } => { + // FIXME: We need to split the tree properly here, but mutating the token trees + // in the buffer is somewhat tricky to pull off. + cursor = cursor.bump_subtree(); + } + parser::Step::Enter { .. } | parser::Step::Exit => (), + parser::Step::Error { .. } => error = true, + } + } + + let err = if error || !cursor.is_root() { + Some(ExpandError::binding_error(format!("expected {entry_point:?}"))) + } else { + None + }; + + let mut curr = buffer.begin(); + let mut res = vec![]; + + while curr != cursor { + let Some(token) = curr.token_tree() else { break }; + res.push(token.cloned()); + curr = curr.bump(); + } + + *tt_iter = TtIter::new_iter(tt_iter.as_slice()[res.len()..].iter()); + let res = match &*res { + [] | [_] => res.pop(), + [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree { + delimiter: Delimiter::invisible_spanned(first.first_span()), + token_trees: res.into_boxed_slice(), + })), + }; + ExpandResult { value: res, err } +} diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs index bbe00f0afca..5c499c06b15 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs @@ -1,11 +1,14 @@ //! Parser recognizes special macro syntax, `$var` and `$(repeat)*`, in token //! trees. -use smallvec::{smallvec, SmallVec}; +use std::sync::Arc; + +use arrayvec::ArrayVec; use span::{Edition, Span, SyntaxContextId}; use syntax::SmolStr; +use tt::iter::TtIter; -use crate::{tt_iter::TtIter, ParseError}; +use crate::ParseError; /// Consider /// @@ -86,14 +89,14 @@ pub(crate) enum Op { Repeat { tokens: MetaTemplate, kind: RepeatKind, - separator: Option<Separator>, + separator: Option<Arc<Separator>>, }, Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter<Span>, }, Literal(tt::Literal<Span>), - Punct(SmallVec<[tt::Punct<Span>; 3]>), + Punct(Box<ArrayVec<tt::Punct<Span>, 3>>), Ident(tt::Ident<Span>), } @@ -126,7 +129,7 @@ pub(crate) enum MetaVarKind { pub(crate) enum Separator { Literal(tt::Literal<Span>), Ident(tt::Ident<Span>), - Puncts(SmallVec<[tt::Punct<Span>; 3]>), + Puncts(ArrayVec<tt::Punct<Span>, 3>), } // Note that when we compare a Separator, we just care about its textual value. @@ -165,7 +168,13 @@ fn next_op( src.next().expect("first token already peeked"); // Note that the '$' itself is a valid token inside macro_rules. let second = match src.next() { - None => return Ok(Op::Punct(smallvec![*p])), + None => { + return Ok(Op::Punct({ + let mut res = ArrayVec::new(); + res.push(*p); + Box::new(res) + })) + } Some(it) => it, }; match second { @@ -173,7 +182,7 @@ fn next_op( tt::DelimiterKind::Parenthesis => { let (separator, kind) = parse_repeat(src)?; let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?; - Op::Repeat { tokens, separator, kind } + Op::Repeat { tokens, separator: separator.map(Arc::new), kind } } tt::DelimiterKind::Brace => match mode { Mode::Template => { @@ -216,7 +225,11 @@ fn next_op( "`$$` is not allowed on the pattern side", )) } - Mode::Template => Op::Punct(smallvec![*punct]), + Mode::Template => Op::Punct({ + let mut res = ArrayVec::new(); + res.push(*punct); + Box::new(res) + }), }, tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => { return Err(ParseError::expected("expected ident")) @@ -238,7 +251,7 @@ fn next_op( tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => { // There's at least one punct so this shouldn't fail. let puncts = src.expect_glued_punct().unwrap(); - Op::Punct(puncts) + Op::Punct(Box::new(puncts)) } tt::TokenTree::Subtree(subtree) => { @@ -290,7 +303,7 @@ fn is_boolean_literal(lit: &tt::Literal<Span>) -> bool { } fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, RepeatKind), ParseError> { - let mut separator = Separator::Puncts(SmallVec::new()); + let mut separator = Separator::Puncts(ArrayVec::new()); for tt in src { let tt = match tt { tt::TokenTree::Leaf(leaf) => leaf, @@ -312,7 +325,7 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat '+' => RepeatKind::OneOrMore, '?' => RepeatKind::ZeroOrOne, _ => match &mut separator { - Separator::Puncts(puncts) if puncts.len() != 3 => { + Separator::Puncts(puncts) if puncts.len() < 3 => { puncts.push(*punct); continue; } diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs index c8ff8c35e93..73a04f00d93 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs @@ -11,9 +11,12 @@ use syntax::{ SyntaxKind::*, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T, }; -use tt::buffer::{Cursor, TokenBuffer}; +use tt::{ + buffer::{Cursor, TokenBuffer}, + iter::TtIter, +}; -use crate::{to_parser_input::to_parser_input, tt_iter::TtIter}; +use crate::to_parser_input::to_parser_input; #[cfg(test)] mod tests; @@ -213,7 +216,7 @@ where let mut res = Vec::new(); while iter.peek_n(0).is_some() { - let expanded = iter.expect_fragment(parser::PrefixEntryPoint::Expr, edition); + let expanded = crate::expect_fragment(&mut iter, parser::PrefixEntryPoint::Expr, edition); res.push(match expanded.value { None => break, diff --git a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs deleted file mode 100644 index 9c7d7af7b14..00000000000 --- a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! A "Parser" structure for token trees. We use this when parsing a declarative -//! macro definition into a list of patterns and templates. - -use core::fmt; - -use smallvec::{smallvec, SmallVec}; -use syntax::SyntaxKind; - -use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult}; - -#[derive(Debug, Clone)] -pub(crate) struct TtIter<'a, S> { - pub(crate) inner: std::slice::Iter<'a, tt::TokenTree<S>>, -} - -impl<'a, S: Copy> TtIter<'a, S> { - pub(crate) fn new(subtree: &'a tt::Subtree<S>) -> TtIter<'a, S> { - TtIter { inner: subtree.token_trees.iter() } - } - - pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ()> { - match self.next() { - Some(&tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) if c == char => { - Ok(()) - } - _ => Err(()), - } - } - - pub(crate) fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> { - match self.next() { - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. }))) - if chars.contains(c) => - { - Ok(()) - } - _ => Err(()), - } - } - - pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree<S>, ()> { - match self.next() { - Some(tt::TokenTree::Subtree(it)) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_leaf(&mut self) -> Result<&'a tt::Leaf<S>, ()> { - match self.next() { - Some(tt::TokenTree::Leaf(it)) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_dollar(&mut self) -> Result<(), ()> { - match self.expect_leaf()? { - tt::Leaf::Punct(tt::Punct { char: '$', .. }) => Ok(()), - _ => Err(()), - } - } - - pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident<S>, ()> { - match self.expect_leaf()? { - tt::Leaf::Ident(it) if it.text != "_" => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_ident_or_underscore(&mut self) -> Result<&'a tt::Ident<S>, ()> { - match self.expect_leaf()? { - tt::Leaf::Ident(it) => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Leaf<S>, ()> { - let it = self.expect_leaf()?; - match it { - tt::Leaf::Literal(_) => Ok(it), - tt::Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it), - _ => Err(()), - } - } - - pub(crate) fn expect_single_punct(&mut self) -> Result<&'a tt::Punct<S>, ()> { - match self.expect_leaf()? { - tt::Leaf::Punct(it) => Ok(it), - _ => Err(()), - } - } - - /// Returns consecutive `Punct`s that can be glued together. - /// - /// This method currently may return a single quotation, which is part of lifetime ident and - /// conceptually not a punct in the context of mbe. Callers should handle this. - pub(crate) fn expect_glued_punct(&mut self) -> Result<SmallVec<[tt::Punct<S>; 3]>, ()> { - let tt::TokenTree::Leaf(tt::Leaf::Punct(first)) = self.next().ok_or(())?.clone() else { - return Err(()); - }; - - if first.spacing == tt::Spacing::Alone { - return Ok(smallvec![first]); - } - - let (second, third) = match (self.peek_n(0), self.peek_n(1)) { - ( - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), - Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))), - ) if p2.spacing == tt::Spacing::Joint => (p2, Some(p3)), - (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2, None), - _ => return Ok(smallvec![first]), - }; - - match (first.char, second.char, third.map(|it| it.char)) { - ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => { - let _ = self.next().unwrap(); - let _ = self.next().unwrap(); - Ok(smallvec![first, *second, *third.unwrap()]) - } - ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) - | ('-' | '=' | '>', '>', _) - | ('<', '-', _) - | (':', ':', _) - | ('.', '.', _) - | ('&', '&', _) - | ('<', '<', _) - | ('|', '|', _) => { - let _ = self.next().unwrap(); - Ok(smallvec![first, *second]) - } - _ => Ok(smallvec![first]), - } - } - pub(crate) fn peek_n(&self, n: usize) -> Option<&'a tt::TokenTree<S>> { - self.inner.as_slice().get(n) - } -} - -impl<'a, S: Copy + fmt::Debug> TtIter<'a, S> { - pub(crate) fn expect_fragment( - &mut self, - entry_point: parser::PrefixEntryPoint, - edition: parser::Edition, - ) -> ExpandResult<Option<tt::TokenTree<S>>> { - let buffer = tt::buffer::TokenBuffer::from_tokens(self.inner.as_slice()); - let parser_input = to_parser_input(&buffer); - let tree_traversal = entry_point.parse(&parser_input, edition); - let mut cursor = buffer.begin(); - let mut error = false; - for step in tree_traversal.iter() { - match step { - parser::Step::Token { kind, mut n_input_tokens } => { - if kind == SyntaxKind::LIFETIME_IDENT { - n_input_tokens = 2; - } - for _ in 0..n_input_tokens { - cursor = cursor.bump_subtree(); - } - } - parser::Step::FloatSplit { .. } => { - // FIXME: We need to split the tree properly here, but mutating the token trees - // in the buffer is somewhat tricky to pull off. - cursor = cursor.bump_subtree(); - } - parser::Step::Enter { .. } | parser::Step::Exit => (), - parser::Step::Error { .. } => error = true, - } - } - - let err = if error || !cursor.is_root() { - Some(ExpandError::binding_error(format!("expected {entry_point:?}"))) - } else { - None - }; - - let mut curr = buffer.begin(); - let mut res = vec![]; - - while curr != cursor { - let Some(token) = curr.token_tree() else { break }; - res.push(token.cloned()); - curr = curr.bump(); - } - - self.inner = self.inner.as_slice()[res.len()..].iter(); - let res = match &*res { - [] | [_] => res.pop(), - [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree { - delimiter: tt::Delimiter::invisible_spanned(first.first_span()), - token_trees: res.into_boxed_slice(), - })), - }; - ExpandResult { value: res, err } - } -} - -impl<'a, S> Iterator for TtIter<'a, S> { - type Item = &'a tt::TokenTree<S>; - fn next(&mut self) -> Option<Self::Item> { - self.inner.next() - } - - fn size_hint(&self) -> (usize, Option<usize>) { - self.inner.size_hint() - } -} - -impl<S> std::iter::ExactSizeIterator for TtIter<'_, S> {} diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml index 1f84e3f3af3..54b57c201be 100644 --- a/src/tools/rust-analyzer/crates/parser/Cargo.toml +++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml @@ -21,7 +21,6 @@ tracing = { workspace = true, optional = true } expect-test = "1.4.0" stdx.workspace = true -sourcegen.workspace = true [features] default = ["tracing"] diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 25c00ccf5f3..99bbf47654b 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -372,13 +372,11 @@ fn macro_def(p: &mut Parser<'_>, m: Marker) { // macro m { ($i:ident) => {} } token_tree(p); } else if p.at(T!['(']) { - let m = p.start(); token_tree(p); match p.current() { T!['{'] | T!['['] | T!['('] => token_tree(p), _ => p.error("expected `{`, `[`, `(`"), } - m.complete(p, TOKEN_TREE); } else { p.error("unmatched `(`"); } diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs index c2f9ea47728..738ed239a7c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lib.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs @@ -17,7 +17,6 @@ //! //! [`Parser`]: crate::parser::Parser -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(rustdoc::private_intra_doc_links)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index ef83420c523..ad3398453be 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -1,4 +1,4 @@ -//! Generated by `sourcegen_ast`, do not edit by hand. +//! Generated by `cargo codegen grammar`, do not edit by hand. #![allow(bad_style, missing_docs, unreachable_pub)] #[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."] diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs index 0e040965261..a38689791c4 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests.rs +++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs @@ -1,5 +1,4 @@ mod prefix_entries; -mod sourcegen_inline_tests; mod top_entries; use std::{ diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast index 01de13a907d..f73229b2e30 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast @@ -5,15 +5,14 @@ SOURCE_FILE NAME IDENT "m" TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "i" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" + L_PAREN "(" + DOLLAR "$" + IDENT "i" + COLON ":" + IDENT "ident" + R_PAREN ")" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast index a95bc23016b..3d9322947b3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast @@ -39,16 +39,15 @@ SOURCE_FILE NAME IDENT "m" TOKEN_TREE - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - COLON ":" - IDENT "ident" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" - R_CURLY "}" + L_PAREN "(" + DOLLAR "$" + COLON ":" + IDENT "ident" + R_PAREN ")" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" WHITESPACE "\n" FN VISIBILITY diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast index 3915ed75064..1415a866b69 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast @@ -5,51 +5,50 @@ SOURCE_FILE NAME IDENT "parse_use_trees" TOKEN_TREE + L_PAREN "(" + DOLLAR "$" TOKEN_TREE L_PAREN "(" DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "s" - COLON ":" - IDENT "expr" - R_PAREN ")" + IDENT "s" + COLON ":" + IDENT "expr" + R_PAREN ")" + COMMA "," + STAR "*" + WHITESPACE " " + DOLLAR "$" + TOKEN_TREE + L_PAREN "(" COMMA "," - STAR "*" - WHITESPACE " " + R_PAREN ")" + STAR "*" + R_PAREN ")" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + WHITESPACE "\n " + IDENT "vec" + BANG "!" + TOKEN_TREE + L_BRACK "[" + WHITESPACE "\n " DOLLAR "$" TOKEN_TREE L_PAREN "(" + IDENT "parse_use_tree" + TOKEN_TREE + L_PAREN "(" + DOLLAR "$" + IDENT "s" + R_PAREN ")" COMMA "," R_PAREN ")" STAR "*" - R_PAREN ")" - WHITESPACE " " - TOKEN_TREE - L_CURLY "{" WHITESPACE "\n " - IDENT "vec" - BANG "!" - TOKEN_TREE - L_BRACK "[" - WHITESPACE "\n " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - IDENT "parse_use_tree" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "s" - R_PAREN ")" - COMMA "," - R_PAREN ")" - STAR "*" - WHITESPACE "\n " - R_BRACK "]" - WHITESPACE "\n" - R_CURLY "}" + R_BRACK "]" + WHITESPACE "\n" + R_CURLY "}" WHITESPACE "\n\n" FN ATTR @@ -80,79 +79,62 @@ SOURCE_FILE NAME IDENT "test_merge" TOKEN_TREE + L_PAREN "(" TOKEN_TREE - L_PAREN "(" + L_BRACK "[" + DOLLAR "$" TOKEN_TREE - L_BRACK "[" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "input" - COLON ":" - IDENT "expr" - R_PAREN ")" - COMMA "," - STAR "*" - WHITESPACE " " + L_PAREN "(" DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - COMMA "," - R_PAREN ")" - STAR "*" - R_BRACK "]" + IDENT "input" + COLON ":" + IDENT "expr" + R_PAREN ")" COMMA "," + STAR "*" WHITESPACE " " + DOLLAR "$" TOKEN_TREE - L_BRACK "[" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "output" - COLON ":" - IDENT "expr" - R_PAREN ")" + L_PAREN "(" COMMA "," - STAR "*" - WHITESPACE " " - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - COMMA "," - R_PAREN ")" - STAR "*" - R_BRACK "]" - R_PAREN ")" + R_PAREN ")" + STAR "*" + R_BRACK "]" + COMMA "," WHITESPACE " " TOKEN_TREE - L_CURLY "{" - WHITESPACE "\n " - IDENT "assert_eq" - BANG "!" + L_BRACK "[" + DOLLAR "$" + TOKEN_TREE + L_PAREN "(" + DOLLAR "$" + IDENT "output" + COLON ":" + IDENT "expr" + R_PAREN ")" + COMMA "," + STAR "*" + WHITESPACE " " + DOLLAR "$" TOKEN_TREE L_PAREN "(" - WHITESPACE "\n " - IDENT "merge_use_trees" - TOKEN_TREE - L_PAREN "(" - IDENT "parse_use_trees" - BANG "!" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - TOKEN_TREE - L_PAREN "(" - DOLLAR "$" - IDENT "input" - COMMA "," - R_PAREN ")" - STAR "*" - R_PAREN ")" - R_PAREN ")" COMMA "," - WHITESPACE "\n " + R_PAREN ")" + STAR "*" + R_BRACK "]" + R_PAREN ")" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + WHITESPACE "\n " + IDENT "assert_eq" + BANG "!" + TOKEN_TREE + L_PAREN "(" + WHITESPACE "\n " + IDENT "merge_use_trees" + TOKEN_TREE + L_PAREN "(" IDENT "parse_use_trees" BANG "!" TOKEN_TREE @@ -161,17 +143,33 @@ SOURCE_FILE TOKEN_TREE L_PAREN "(" DOLLAR "$" - IDENT "output" + IDENT "input" COMMA "," R_PAREN ")" STAR "*" R_PAREN ")" - COMMA "," - WHITESPACE "\n " R_PAREN ")" - SEMICOLON ";" - WHITESPACE "\n " - R_CURLY "}" + COMMA "," + WHITESPACE "\n " + IDENT "parse_use_trees" + BANG "!" + TOKEN_TREE + L_PAREN "(" + DOLLAR "$" + TOKEN_TREE + L_PAREN "(" + DOLLAR "$" + IDENT "output" + COMMA "," + R_PAREN ")" + STAR "*" + R_PAREN ")" + COMMA "," + WHITESPACE "\n " + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + R_CURLY "}" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/paths/src/lib.rs b/src/tools/rust-analyzer/crates/paths/src/lib.rs index 33c3f83db50..885f071889e 100644 --- a/src/tools/rust-analyzer/crates/paths/src/lib.rs +++ b/src/tools/rust-analyzer/crates/paths/src/lib.rs @@ -1,8 +1,6 @@ //! Thin wrappers around `std::path`/`camino::path`, distinguishing between absolute and //! relative paths. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{ borrow::Borrow, ffi::OsStr, diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml index f30f6a0f23b..7f633d91ecc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml @@ -12,15 +12,11 @@ rust-version.workspace = true doctest = false [dependencies] -object.workspace = true serde.workspace = true serde_json = { workspace = true, features = ["unbounded_depth"] } tracing.workspace = true -triomphe.workspace = true rustc-hash.workspace = true -memmap2 = "0.5.4" -snap = "1.1.0" -indexmap = "2.1.0" +indexmap.workspace = true # local deps paths = { workspace = true, features = ["serde1"] } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/json.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/json.rs new file mode 100644 index 00000000000..ec89f6a9e65 --- /dev/null +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/json.rs @@ -0,0 +1,35 @@ +//! Protocol functions for json. +use std::io::{self, BufRead, Write}; + +pub fn read_json<'a>( + inp: &mut impl BufRead, + buf: &'a mut String, +) -> io::Result<Option<&'a String>> { + loop { + buf.clear(); + + inp.read_line(buf)?; + buf.pop(); // Remove trailing '\n' + + if buf.is_empty() { + return Ok(None); + } + + // Some ill behaved macro try to use stdout for debugging + // We ignore it here + if !buf.starts_with('{') { + tracing::error!("proc-macro tried to print : {}", buf); + continue; + } + + return Ok(Some(buf)); + } +} + +pub fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { + tracing::debug!("> {}", msg); + out.write_all(msg.as_bytes())?; + out.write_all(b"\n")?; + out.flush()?; + Ok(()) +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 8970bdd0121..3a915e668bb 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -5,34 +5,27 @@ //! is used to provide basic infrastructure for communication between two //! processes: Client (RA itself), Server (the external program) -#![warn(rust_2018_idioms, unused_lifetimes)] - +pub mod json; pub mod msg; mod process; -mod version; use base_db::Env; -use indexmap::IndexSet; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; use span::Span; -use std::{ - fmt, io, - sync::{Arc, Mutex}, -}; +use std::{fmt, io, sync::Arc}; +use tt::SmolStr; use serde::{Deserialize, Serialize}; use crate::{ msg::{ deserialize_span_data_index_map, flat::serialize_span_data_index_map, ExpandMacro, - ExpnGlobals, FlatTree, PanicMessage, HAS_GLOBAL_SPANS, RUST_ANALYZER_SPAN_SUPPORT, + ExpnGlobals, FlatTree, PanicMessage, SpanDataIndexMap, HAS_GLOBAL_SPANS, + RUST_ANALYZER_SPAN_SUPPORT, }, process::ProcMacroProcessSrv, }; -pub use version::{read_dylib_info, read_version, RustCInfo}; - #[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum ProcMacroKind { CustomDerive, @@ -51,9 +44,7 @@ pub struct ProcMacroServer { /// /// That means that concurrent salsa requests may block each other when expanding proc macros, /// which is unfortunate, but simple and good enough for the time being. - /// - /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here. - process: Arc<Mutex<ProcMacroProcessSrv>>, + process: Arc<ProcMacroProcessSrv>, path: AbsPathBuf, } @@ -73,9 +64,9 @@ impl MacroDylib { /// we share a single expander process for all macros. #[derive(Debug, Clone)] pub struct ProcMacro { - process: Arc<Mutex<ProcMacroProcessSrv>>, - dylib_path: AbsPathBuf, - name: String, + process: Arc<ProcMacroProcessSrv>, + dylib_path: Arc<AbsPathBuf>, + name: SmolStr, kind: ProcMacroKind, } @@ -84,7 +75,7 @@ impl PartialEq for ProcMacro { fn eq(&self, other: &Self) -> bool { self.name == other.name && self.kind == other.kind - && self.dylib_path == other.dylib_path + && Arc::ptr_eq(&self.dylib_path, &other.dylib_path) && Arc::ptr_eq(&self.process, &other.process) } } @@ -92,7 +83,6 @@ impl PartialEq for ProcMacro { #[derive(Clone, Debug)] pub struct ServerError { pub message: String, - // io::Error isn't Clone for some reason pub io: Option<Arc<io::Error>>, } @@ -107,21 +97,15 @@ impl fmt::Display for ServerError { } } -pub struct MacroPanic { - pub message: String, -} - impl ProcMacroServer { /// Spawns an external process as the proc macro server and returns a client connected to it. pub fn spawn( process_path: &AbsPath, - env: &FxHashMap<String, String>, + env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)> + + Clone, ) -> io::Result<ProcMacroServer> { let process = ProcMacroProcessSrv::run(process_path, env)?; - Ok(ProcMacroServer { - process: Arc::new(Mutex::new(process)), - path: process_path.to_owned(), - }) + Ok(ProcMacroServer { process: Arc::new(process), path: process_path.to_owned() }) } pub fn path(&self) -> &AbsPath { @@ -130,22 +114,26 @@ impl ProcMacroServer { pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> { let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered(); - let macros = - self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; + let macros = self.process.find_proc_macros(&dylib.path)?; + let dylib_path = Arc::new(dylib.path); match macros { Ok(macros) => Ok(macros .into_iter() .map(|(name, kind)| ProcMacro { process: self.process.clone(), - name, + name: name.into(), kind, - dylib_path: dylib.path.clone(), + dylib_path: dylib_path.clone(), }) .collect()), Err(message) => Err(ServerError { message, io: None }), } } + + pub fn exited(&self) -> Option<&ServerError> { + self.process.exited() + } } impl ProcMacro { @@ -166,38 +154,37 @@ impl ProcMacro { call_site: Span, mixed_site: Span, ) -> Result<Result<tt::Subtree<Span>, PanicMessage>, ServerError> { - let version = self.process.lock().unwrap_or_else(|e| e.into_inner()).version(); + let version = self.process.version(); let current_dir = env.get("CARGO_MANIFEST_DIR"); - let mut span_data_table = IndexSet::default(); + let mut span_data_table = SpanDataIndexMap::default(); let def_site = span_data_table.insert_full(def_site).0; let call_site = span_data_table.insert_full(call_site).0; let mixed_site = span_data_table.insert_full(mixed_site).0; let task = ExpandMacro { - macro_body: FlatTree::new(subtree, version, &mut span_data_table), - macro_name: self.name.to_string(), - attributes: attr.map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), + data: msg::ExpandMacroData { + macro_body: FlatTree::new(subtree, version, &mut span_data_table), + macro_name: self.name.to_string(), + attributes: attr + .map(|subtree| FlatTree::new(subtree, version, &mut span_data_table)), + has_global_spans: ExpnGlobals { + serialize: version >= HAS_GLOBAL_SPANS, + def_site, + call_site, + mixed_site, + }, + span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT { + serialize_span_data_index_map(&span_data_table) + } else { + Vec::new() + }, + }, lib: self.dylib_path.to_path_buf().into(), env: env.into(), current_dir, - has_global_spans: ExpnGlobals { - serialize: version >= HAS_GLOBAL_SPANS, - def_site, - call_site, - mixed_site, - }, - span_data_table: if version >= RUST_ANALYZER_SPAN_SUPPORT { - serialize_span_data_index_map(&span_data_table) - } else { - Vec::new() - }, }; - let response = self - .process - .lock() - .unwrap_or_else(|e| e.into_inner()) - .send_task(msg::Request::ExpandMacro(Box::new(task)))?; + let response = self.process.send_task(msg::Request::ExpandMacro(Box::new(task)))?; match response { msg::Response::ExpandMacro(it) => { diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs index ad0e1f187b6..fa3ba9bbfcd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs @@ -72,6 +72,16 @@ pub struct PanicMessage(pub String); #[derive(Debug, Serialize, Deserialize)] pub struct ExpandMacro { + pub lib: Utf8PathBuf, + /// Environment variables to set during macro expansion. + pub env: Vec<(String, String)>, + pub current_dir: Option<String>, + #[serde(flatten)] + pub data: ExpandMacroData, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ExpandMacroData { /// Argument of macro call. /// /// In custom derive this will be a struct or enum; in attribute-like macro - underlying @@ -86,13 +96,6 @@ pub struct ExpandMacro { /// Possible attributes for the attribute-like macros. pub attributes: Option<FlatTree>, - - pub lib: Utf8PathBuf, - - /// Environment variables to set during macro expansion. - pub env: Vec<(String, String)>, - - pub current_dir: Option<String>, /// marker for serde skip stuff #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")] #[serde(default)] @@ -119,8 +122,12 @@ impl ExpnGlobals { } pub trait Message: Serialize + DeserializeOwned { - fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result<Option<Self>> { - Ok(match read_json(inp, buf)? { + fn read<R: BufRead>( + from_proto: ProtocolRead<R>, + inp: &mut R, + buf: &mut String, + ) -> io::Result<Option<Self>> { + Ok(match from_proto(inp, buf)? { None => None, Some(text) => { let mut deserializer = serde_json::Deserializer::from_str(text); @@ -131,44 +138,20 @@ pub trait Message: Serialize + DeserializeOwned { } }) } - fn write(self, out: &mut impl Write) -> io::Result<()> { + fn write<W: Write>(self, to_proto: ProtocolWrite<W>, out: &mut W) -> io::Result<()> { let text = serde_json::to_string(&self)?; - write_json(out, &text) + to_proto(out, &text) } } impl Message for Request {} impl Message for Response {} -fn read_json<'a>(inp: &mut impl BufRead, buf: &'a mut String) -> io::Result<Option<&'a String>> { - loop { - buf.clear(); - - inp.read_line(buf)?; - buf.pop(); // Remove trailing '\n' - - if buf.is_empty() { - return Ok(None); - } - - // Some ill behaved macro try to use stdout for debugging - // We ignore it here - if !buf.starts_with('{') { - tracing::error!("proc-macro tried to print : {}", buf); - continue; - } - - return Ok(Some(buf)); - } -} - -fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { - tracing::debug!("> {}", msg); - out.write_all(msg.as_bytes())?; - out.write_all(b"\n")?; - out.flush()?; - Ok(()) -} +#[allow(type_alias_bounds)] +type ProtocolRead<R: BufRead> = + for<'i, 'buf> fn(inp: &'i mut R, buf: &'buf mut String) -> io::Result<Option<&'buf String>>; +#[allow(type_alias_bounds)] +type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) -> io::Result<()>; #[cfg(test)] mod tests { @@ -268,25 +251,30 @@ mod tests { let tt = fixture_token_tree(); let mut span_data_table = Default::default(); let task = ExpandMacro { - macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table), - macro_name: Default::default(), - attributes: None, + data: ExpandMacroData { + macro_body: FlatTree::new(&tt, CURRENT_API_VERSION, &mut span_data_table), + macro_name: Default::default(), + attributes: None, + has_global_spans: ExpnGlobals { + serialize: true, + def_site: 0, + call_site: 0, + mixed_site: 0, + }, + span_data_table: Vec::new(), + }, lib: Utf8PathBuf::from_path_buf(std::env::current_dir().unwrap()).unwrap(), env: Default::default(), current_dir: Default::default(), - has_global_spans: ExpnGlobals { - serialize: true, - def_site: 0, - call_site: 0, - mixed_site: 0, - }, - span_data_table: Vec::new(), }; let json = serde_json::to_string(&task).unwrap(); // println!("{}", json); let back: ExpandMacro = serde_json::from_str(&json).unwrap(); - assert_eq!(tt, back.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); + assert_eq!( + tt, + back.data.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table) + ); } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs index 99cdbd930e1..11fd7596f2b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs @@ -37,7 +37,6 @@ use std::collections::VecDeque; -use indexmap::IndexSet; use la_arena::RawIdx; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -46,7 +45,8 @@ use text_size::TextRange; use crate::msg::ENCODE_CLOSE_SPAN_VERSION; -pub type SpanDataIndexMap = IndexSet<Span>; +pub type SpanDataIndexMap = + indexmap::IndexSet<Span, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; pub fn serialize_span_data_index_map(map: &SpanDataIndexMap) -> Vec<u32> { map.iter() @@ -328,7 +328,7 @@ impl InternableSpan for TokenId { } } impl InternableSpan for Span { - type Table = IndexSet<Span>; + type Table = SpanDataIndexMap; fn token_id_of(table: &mut Self::Table, span: Self) -> TokenId { TokenId(table.insert_full(span).0 as u32) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs index 718a96dc80f..c965257a5c5 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs @@ -2,46 +2,53 @@ use std::{ io::{self, BufRead, BufReader, Read, Write}, + panic::AssertUnwindSafe, process::{Child, ChildStdin, ChildStdout, Command, Stdio}, - sync::Arc, + sync::{Arc, Mutex, OnceLock}, }; use paths::AbsPath; -use rustc_hash::FxHashMap; use stdx::JodChild; use crate::{ + json::{read_json, write_json}, msg::{Message, Request, Response, SpanMode, CURRENT_API_VERSION, RUST_ANALYZER_SPAN_SUPPORT}, ProcMacroKind, ServerError, }; #[derive(Debug)] pub(crate) struct ProcMacroProcessSrv { + /// The state of the proc-macro server process, the protocol is currently strictly sequential + /// hence the lock on the state. + state: Mutex<ProcessSrvState>, + version: u32, + mode: SpanMode, + /// Populated when the server exits. + exited: OnceLock<AssertUnwindSafe<ServerError>>, +} + +#[derive(Debug)] +struct ProcessSrvState { process: Process, stdin: ChildStdin, stdout: BufReader<ChildStdout>, - /// Populated when the server exits. - server_exited: Option<ServerError>, - version: u32, - mode: SpanMode, } impl ProcMacroProcessSrv { pub(crate) fn run( process_path: &AbsPath, - env: &FxHashMap<String, String>, + env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)> + + Clone, ) -> io::Result<ProcMacroProcessSrv> { let create_srv = |null_stderr| { - let mut process = Process::run(process_path, env, null_stderr)?; + let mut process = Process::run(process_path, env.clone(), null_stderr)?; let (stdin, stdout) = process.stdio().expect("couldn't access child stdio"); io::Result::Ok(ProcMacroProcessSrv { - process, - stdin, - stdout, - server_exited: None, + state: Mutex::new(ProcessSrvState { process, stdin, stdout }), version: 0, mode: SpanMode::Id, + exited: OnceLock::new(), }) }; let mut srv = create_srv(true)?; @@ -72,11 +79,15 @@ impl ProcMacroProcessSrv { } } + pub(crate) fn exited(&self) -> Option<&ServerError> { + self.exited.get().map(|it| &it.0) + } + pub(crate) fn version(&self) -> u32 { self.version } - pub(crate) fn version_check(&mut self) -> Result<u32, ServerError> { + fn version_check(&self) -> Result<u32, ServerError> { let request = Request::ApiVersionCheck {}; let response = self.send_task(request)?; @@ -86,7 +97,7 @@ impl ProcMacroProcessSrv { } } - fn enable_rust_analyzer_spans(&mut self) -> Result<SpanMode, ServerError> { + fn enable_rust_analyzer_spans(&self) -> Result<SpanMode, ServerError> { let request = Request::SetConfig(crate::msg::ServerConfig { span_mode: crate::msg::SpanMode::RustAnalyzer, }); @@ -99,7 +110,7 @@ impl ProcMacroProcessSrv { } pub(crate) fn find_proc_macros( - &mut self, + &self, dylib_path: &AbsPath, ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> { let request = Request::ListMacros { dylib_path: dylib_path.to_path_buf().into() }; @@ -112,36 +123,53 @@ impl ProcMacroProcessSrv { } } - pub(crate) fn send_task(&mut self, req: Request) -> Result<Response, ServerError> { - if let Some(server_error) = &self.server_exited { - return Err(server_error.clone()); + pub(crate) fn send_task(&self, req: Request) -> Result<Response, ServerError> { + if let Some(server_error) = self.exited.get() { + return Err(server_error.0.clone()); } + let state = &mut *self.state.lock().unwrap(); let mut buf = String::new(); - send_request(&mut self.stdin, &mut self.stdout, req, &mut buf).map_err(|e| { - if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { - match self.process.child.try_wait() { - Ok(None) => e, - Ok(Some(status)) => { - let mut msg = String::new(); - if !status.success() { - if let Some(stderr) = self.process.child.stderr.as_mut() { - _ = stderr.read_to_string(&mut msg); + send_request(&mut state.stdin, &mut state.stdout, req, &mut buf) + .and_then(|res| { + res.ok_or_else(|| { + let message = "proc-macro server did not respond with data".to_owned(); + ServerError { + io: Some(Arc::new(io::Error::new( + io::ErrorKind::BrokenPipe, + message.clone(), + ))), + message, + } + }) + }) + .map_err(|e| { + if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) { + match state.process.child.try_wait() { + Ok(None) | Err(_) => e, + Ok(Some(status)) => { + let mut msg = String::new(); + if !status.success() { + if let Some(stderr) = state.process.child.stderr.as_mut() { + _ = stderr.read_to_string(&mut msg); + } } + let server_error = ServerError { + message: format!( + "proc-macro server exited with {status}{}{msg}", + if msg.is_empty() { "" } else { ": " } + ), + io: None, + }; + // `AssertUnwindSafe` is fine here, we already correct initialized + // server_error at this point. + self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone() } - let server_error = ServerError { - message: format!("server exited with {status}: {msg}"), - io: None, - }; - self.server_exited = Some(server_error.clone()); - server_error } - Err(_) => e, + } else { + e } - } else { - e - } - }) + }) } } @@ -153,7 +181,7 @@ struct Process { impl Process { fn run( path: &AbsPath, - env: &FxHashMap<String, String>, + env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>, null_stderr: bool, ) -> io::Result<Process> { let child = JodChild(mk_child(path, env, null_stderr)?); @@ -171,7 +199,7 @@ impl Process { fn mk_child( path: &AbsPath, - env: &FxHashMap<String, String>, + env: impl IntoIterator<Item = (impl AsRef<std::ffi::OsStr>, impl AsRef<std::ffi::OsStr>)>, null_stderr: bool, ) -> io::Result<Child> { let mut cmd = Command::new(path); @@ -195,14 +223,14 @@ fn send_request( mut reader: &mut impl BufRead, req: Request, buf: &mut String, -) -> Result<Response, ServerError> { - req.write(&mut writer).map_err(|err| ServerError { +) -> Result<Option<Response>, ServerError> { + req.write(write_json, &mut writer).map_err(|err| ServerError { message: "failed to write request".into(), io: Some(Arc::new(err)), })?; - let res = Response::read(&mut reader, buf).map_err(|err| ServerError { + let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError { message: "failed to read response".into(), io: Some(Arc::new(err)), })?; - res.ok_or_else(|| ServerError { message: "server exited".into(), io: None }) + Ok(res) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs index df0ae3171f5..174f9c52462 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs @@ -6,6 +6,8 @@ #[cfg(feature = "in-rust-tree")] extern crate rustc_driver as _; +use proc_macro_api::json::{read_json, write_json}; + use std::io; fn main() -> std::io::Result<()> { @@ -26,19 +28,49 @@ fn main() -> std::io::Result<()> { #[cfg(not(any(feature = "sysroot-abi", rust_analyzer)))] fn run() -> io::Result<()> { - eprintln!("proc-macro-srv-cli requires the `sysroot-abi` feature to be enabled"); - std::process::exit(70); + let err = "proc-macro-srv-cli needs to be compiled with the `sysroot-abi` feature to function"; + eprintln!("{err}"); + use proc_macro_api::msg::{self, Message}; + + let read_request = + |buf: &mut String| msg::Request::read(read_json, &mut io::stdin().lock(), buf); + + let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); + + let mut buf = String::new(); + + while let Some(req) = read_request(&mut buf)? { + let res = match req { + msg::Request::ListMacros { .. } => msg::Response::ListMacros(Err(err.to_owned())), + msg::Request::ExpandMacro(_) => { + msg::Response::ExpandMacro(Err(msg::PanicMessage(err.to_owned()))) + } + msg::Request::ApiVersionCheck {} => { + msg::Response::ApiVersionCheck(proc_macro_api::msg::CURRENT_API_VERSION) + } + msg::Request::SetConfig(_) => { + msg::Response::SetConfig(proc_macro_api::msg::ServerConfig { + span_mode: msg::SpanMode::Id, + }) + } + }; + write_response(res)? + } + Ok(()) } #[cfg(any(feature = "sysroot-abi", rust_analyzer))] fn run() -> io::Result<()> { use proc_macro_api::msg::{self, Message}; + use proc_macro_srv::EnvSnapshot; - let read_request = |buf: &mut String| msg::Request::read(&mut io::stdin().lock(), buf); + let read_request = + |buf: &mut String| msg::Request::read(read_json, &mut io::stdin().lock(), buf); - let write_response = |msg: msg::Response| msg.write(&mut io::stdout().lock()); + let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock()); - let mut srv = proc_macro_srv::ProcMacroSrv::default(); + let env = EnvSnapshot::new(); + let mut srv = proc_macro_srv::ProcMacroSrv::new(&env); let mut buf = String::new(); while let Some(req) = read_request(&mut buf)? { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index f8db1c6a30b..735f781c439 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -13,8 +13,9 @@ doctest = false [dependencies] object.workspace = true -libloading = "0.8.0" -memmap2 = "0.5.4" +libloading.workspace = true +memmap2.workspace = true +snap.workspace = true stdx.workspace = true tt.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs index 874d1c6cd38..9a17cfc9f36 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs @@ -1,27 +1,15 @@ //! Determine rustc version `proc-macro-srv` (and thus the sysroot ABI) is //! build with and make it accessible at runtime for ABI selection. -use std::{env, fs::File, io::Write, path::PathBuf, process::Command}; +use std::{env, process::Command}; fn main() { - println!("cargo:rustc-check-cfg=cfg(rust_analyzer)"); - - let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - path.push("rustc_version.rs"); - let mut f = File::create(&path).unwrap(); + println!("cargo::rustc-check-cfg=cfg(rust_analyzer)"); let rustc = env::var("RUSTC").expect("proc-macro-srv's build script expects RUSTC to be set"); let output = Command::new(rustc).arg("--version").output().expect("rustc --version must run"); let version_string = std::str::from_utf8(&output.stdout[..]) .expect("rustc --version output must be UTF-8") .trim(); - - write!( - f, - " - #[allow(dead_code)] - pub(crate) const RUSTC_VERSION_STRING: &str = {version_string:?}; - " - ) - .unwrap(); + println!("cargo::rustc-env=RUSTC_VERSION={}", version_string); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs index 6a0ae362d88..ff2f5d18639 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/build.rs @@ -8,7 +8,7 @@ //! 1.58) and future ABIs (stage1, nightly) use std::{ - env, fs, + env, path::{Path, PathBuf}, process::Command, }; @@ -30,8 +30,7 @@ fn main() { if !has_features { println!("proc-macro-test testing only works on nightly toolchains"); - let info_path = out_dir.join("proc_macro_test_location.txt"); - fs::File::create(info_path).unwrap(); + println!("cargo::rustc-env=PROC_MACRO_TEST_LOCATION=\"\""); return; } @@ -121,6 +120,5 @@ fn main() { // This file is under `target_dir` and is already under `OUT_DIR`. let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found"); - let info_path = out_dir.join("proc_macro_test_location.txt"); - fs::write(info_path, artifact_path.to_str().unwrap()).unwrap(); + println!("cargo::rustc-env=PROC_MACRO_TEST_LOCATION={}", artifact_path.display()); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs index 5f8530d08c4..a1707364f3c 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs @@ -1,6 +1,6 @@ //! Exports a few trivial procedural macros for testing. -#![warn(rust_2018_idioms, unused_lifetimes)] + #![feature(proc_macro_span, proc_macro_def_site)] #![allow(clippy::all)] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/src/lib.rs index 739c6ec6f44..6464adb2ca7 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/src/lib.rs @@ -1,6 +1,3 @@ //! Exports a few trivial procedural macros for testing. -#![warn(rust_2018_idioms, unused_lifetimes)] - -pub static PROC_MACRO_TEST_LOCATION: &str = - include_str!(concat!(env!("OUT_DIR"), "/proc_macro_test_location.txt")); +pub static PROC_MACRO_TEST_LOCATION: &str = env!("PROC_MACRO_TEST_LOCATION"); diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index 22c34ff1678..78ae4574c40 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -1,13 +1,15 @@ //! Handles dynamic library loading for proc macro +mod version; + +use proc_macro::bridge; use std::{fmt, fs::File, io}; use libloading::Library; use memmap2::Mmap; use object::Object; use paths::{AbsPath, Utf8Path, Utf8PathBuf}; -use proc_macro::bridge; -use proc_macro_api::{read_dylib_info, ProcMacroKind}; +use proc_macro_api::ProcMacroKind; use crate::ProcMacroSrvSpan; @@ -119,33 +121,45 @@ impl ProcMacroLibraryLibloading { let abs_file: &AbsPath = file .try_into() .map_err(|_| invalid_data_err(format!("expected an absolute path, got {file}")))?; - let version_info = read_dylib_info(abs_file)?; + let version_info = version::read_dylib_info(abs_file)?; let lib = load_library(file).map_err(invalid_data_err)?; - let proc_macros = - crate::proc_macros::ProcMacros::from_lib(&lib, symbol_name, version_info)?; + let proc_macros = crate::proc_macros::ProcMacros::from_lib( + &lib, + symbol_name, + &version_info.version_string, + )?; Ok(ProcMacroLibraryLibloading { _lib: lib, proc_macros }) } } -pub struct Expander { +pub(crate) struct Expander { inner: ProcMacroLibraryLibloading, + path: Utf8PathBuf, +} + +impl Drop for Expander { + fn drop(&mut self) { + #[cfg(windows)] + std::fs::remove_file(&self.path).ok(); + _ = self.path; + } } impl Expander { - pub fn new(lib: &Utf8Path) -> Result<Expander, LoadProcMacroDylibError> { + pub(crate) fn new(lib: &Utf8Path) -> Result<Expander, LoadProcMacroDylibError> { // Some libraries for dynamic loading require canonicalized path even when it is // already absolute let lib = lib.canonicalize_utf8()?; - let lib = ensure_file_with_lock_free_access(&lib)?; + let path = ensure_file_with_lock_free_access(&lib)?; - let library = ProcMacroLibraryLibloading::open(lib.as_ref())?; + let library = ProcMacroLibraryLibloading::open(path.as_ref())?; - Ok(Expander { inner: library }) + Ok(Expander { inner: library, path }) } - pub fn expand<S: ProcMacroSrvSpan>( + pub(crate) fn expand<S: ProcMacroSrvSpan>( &self, macro_name: &str, macro_body: tt::Subtree<S>, @@ -164,7 +178,7 @@ impl Expander { result.map_err(|e| e.into_string().unwrap_or_default()) } - pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { + pub(crate) fn list_macros(&self) -> Vec<(String, ProcMacroKind)> { self.inner.proc_macros.list_macros() } } @@ -193,7 +207,7 @@ fn ensure_file_with_lock_free_access(path: &Utf8Path) -> io::Result<Utf8PathBuf> unique_name.push_str(file_name); to.push(unique_name); - std::fs::copy(path, &to).unwrap(); + std::fs::copy(path, &to)?; Ok(to) } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs index 09b81250715..1f7ef7914ba 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/version.rs @@ -11,6 +11,7 @@ use paths::AbsPath; use snap::read::FrameDecoder as SnapDecoder; #[derive(Debug)] +#[allow(dead_code)] pub struct RustCInfo { pub version: (usize, usize, usize), pub channel: String, @@ -164,3 +165,16 @@ pub fn read_version(dylib_path: &AbsPath) -> io::Result<String> { let version_string = String::from_utf8(version_string_utf8); version_string.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) } + +#[test] +fn test_version_check() { + let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path()); + let info = read_dylib_info(&path).unwrap(); + assert_eq!( + info.version_string, + crate::RUSTC_VERSION_STRING, + "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", + info.version_string, + crate::RUSTC_VERSION_STRING, + ); +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 2472c1e3119..e6281035e1a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -13,7 +13,6 @@ #![cfg(any(feature = "sysroot-abi", rust_analyzer))] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unreachable_pub, internal_features)] extern crate proc_macro; @@ -27,13 +26,15 @@ extern crate rustc_lexer; mod dylib; mod proc_macros; -mod server; +mod server_impl; use std::{ collections::{hash_map::Entry, HashMap}, env, ffi::OsString, - fs, thread, + fs, + path::{Path, PathBuf}, + thread, time::SystemTime, }; @@ -47,46 +48,25 @@ use proc_macro_api::{ }; use span::Span; -use crate::server::TokenStream; +use crate::server_impl::TokenStream; -// see `build.rs` -include!(concat!(env!("OUT_DIR"), "/rustc_version.rs")); +pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION"); -trait ProcMacroSrvSpan: Copy { - type Server: proc_macro::bridge::server::Server<TokenStream = TokenStream<Self>>; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; +pub struct ProcMacroSrv<'env> { + expanders: HashMap<(Utf8PathBuf, SystemTime), dylib::Expander>, + span_mode: SpanMode, + env: &'env EnvSnapshot, } -impl ProcMacroSrvSpan for TokenId { - type Server = server::token_id::TokenIdServer; - - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { - Self::Server { interner: &server::SYMBOL_INTERNER, call_site, def_site, mixed_site } +impl<'env> ProcMacroSrv<'env> { + pub fn new(env: &'env EnvSnapshot) -> Self { + Self { expanders: Default::default(), span_mode: Default::default(), env } } } -impl ProcMacroSrvSpan for Span { - type Server = server::rust_analyzer_span::RaSpanServer; - fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { - Self::Server { - interner: &server::SYMBOL_INTERNER, - call_site, - def_site, - mixed_site, - tracked_env_vars: Default::default(), - tracked_paths: Default::default(), - } - } -} - -#[derive(Default)] -pub struct ProcMacroSrv { - expanders: HashMap<(Utf8PathBuf, SystemTime), dylib::Expander>, - span_mode: SpanMode, -} const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024; -impl ProcMacroSrv { +impl<'env> ProcMacroSrv<'env> { pub fn set_span_mode(&mut self, span_mode: SpanMode) { self.span_mode = span_mode; } @@ -97,52 +77,24 @@ impl ProcMacroSrv { pub fn expand( &mut self, - task: msg::ExpandMacro, + msg::ExpandMacro { lib, env, current_dir, data }: msg::ExpandMacro, ) -> Result<(msg::FlatTree, Vec<u32>), msg::PanicMessage> { let span_mode = self.span_mode; - let expander = self.expander(task.lib.as_ref()).map_err(|err| { + let snapped_env = self.env; + let expander = self.expander(lib.as_ref()).map_err(|err| { debug_assert!(false, "should list macros before asking to expand"); msg::PanicMessage(format!("failed to load macro: {err}")) })?; - let prev_env = EnvSnapshot::new(); - for (k, v) in &task.env { - env::set_var(k, v); - } - let prev_working_dir = match &task.current_dir { - Some(dir) => { - let prev_working_dir = std::env::current_dir().ok(); - if let Err(err) = std::env::set_current_dir(dir) { - eprintln!("Failed to set the current working dir to {dir}. Error: {err:?}") - } - prev_working_dir - } - None => None, - }; - - let ExpnGlobals { def_site, call_site, mixed_site, .. } = task.has_global_spans; + let prev_env = EnvChange::apply(snapped_env, env, current_dir.as_ref().map(<_>::as_ref)); let result = match span_mode { - SpanMode::Id => { - expand_id(task, expander, def_site, call_site, mixed_site).map(|it| (it, vec![])) - } - SpanMode::RustAnalyzer => { - expand_ra_span(task, expander, def_site, call_site, mixed_site) - } + SpanMode::Id => expand_id(data, expander).map(|it| (it, vec![])), + SpanMode::RustAnalyzer => expand_ra_span(data, expander), }; prev_env.rollback(); - if let Some(dir) = prev_working_dir { - if let Err(err) = std::env::set_current_dir(&dir) { - eprintln!( - "Failed to set the current working dir to {}. Error: {:?}", - dir.display(), - err - ) - } - } - result.map_err(msg::PanicMessage) } @@ -169,33 +121,55 @@ impl ProcMacroSrv { } } +trait ProcMacroSrvSpan: Copy { + type Server: proc_macro::bridge::server::Server<TokenStream = TokenStream<Self>>; + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server; +} + +impl ProcMacroSrvSpan for TokenId { + type Server = server_impl::token_id::TokenIdServer; + + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + Self::Server { interner: &server_impl::SYMBOL_INTERNER, call_site, def_site, mixed_site } + } +} +impl ProcMacroSrvSpan for Span { + type Server = server_impl::rust_analyzer_span::RaSpanServer; + fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server { + Self::Server { + interner: &server_impl::SYMBOL_INTERNER, + call_site, + def_site, + mixed_site, + tracked_env_vars: Default::default(), + tracked_paths: Default::default(), + } + } +} + fn expand_id( - task: msg::ExpandMacro, + msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + span_data_table: _, + }: msg::ExpandMacroData, expander: &dylib::Expander, - def_site: usize, - call_site: usize, - mixed_site: usize, ) -> Result<msg::FlatTree, String> { let def_site = TokenId(def_site as u32); let call_site = TokenId(call_site as u32); let mixed_site = TokenId(mixed_site as u32); - let macro_body = task.macro_body.to_subtree_unresolved(CURRENT_API_VERSION); - let attributes = task.attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION)); + let macro_body = macro_body.to_subtree_unresolved(CURRENT_API_VERSION); + let attributes = attributes.map(|it| it.to_subtree_unresolved(CURRENT_API_VERSION)); let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) - .name(task.macro_name.clone()) + .name(macro_name.clone()) .spawn_scoped(s, || { expander - .expand( - &task.macro_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - ) + .expand(¯o_name, macro_body, attributes, def_site, call_site, mixed_site) .map(|it| msg::FlatTree::new_raw(&it, CURRENT_API_VERSION)) }); let res = match thread { @@ -212,35 +186,33 @@ fn expand_id( } fn expand_ra_span( - task: msg::ExpandMacro, + msg::ExpandMacroData { + macro_body, + macro_name, + attributes, + has_global_spans: ExpnGlobals { serialize: _, def_site, call_site, mixed_site }, + span_data_table, + }: msg::ExpandMacroData, expander: &dylib::Expander, - def_site: usize, - call_site: usize, - mixed_site: usize, ) -> Result<(msg::FlatTree, Vec<u32>), String> { - let mut span_data_table = deserialize_span_data_index_map(&task.span_data_table); + let mut span_data_table = deserialize_span_data_index_map(&span_data_table); let def_site = span_data_table[def_site]; let call_site = span_data_table[call_site]; let mixed_site = span_data_table[mixed_site]; - let macro_body = task.macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table); + let macro_body = macro_body.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table); let attributes = - task.attributes.map(|it| it.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); + attributes.map(|it| it.to_subtree_resolved(CURRENT_API_VERSION, &span_data_table)); + // Note, we spawn a new thread here so that thread locals allocation don't accumulate (this + // includes the proc-macro symbol interner) let result = thread::scope(|s| { let thread = thread::Builder::new() .stack_size(EXPANDER_STACK_SIZE) - .name(task.macro_name.clone()) + .name(macro_name.clone()) .spawn_scoped(s, || { expander - .expand( - &task.macro_name, - macro_body, - attributes, - def_site, - call_site, - mixed_site, - ) + .expand(¯o_name, macro_body, attributes, def_site, call_site, mixed_site) .map(|it| { ( msg::FlatTree::new(&it, CURRENT_API_VERSION, &mut span_data_table), @@ -271,31 +243,74 @@ impl PanicMessage { } } -struct EnvSnapshot { +pub struct EnvSnapshot { vars: HashMap<OsString, OsString>, } impl EnvSnapshot { - fn new() -> EnvSnapshot { + pub fn new() -> EnvSnapshot { EnvSnapshot { vars: env::vars_os().collect() } } +} + +struct EnvChange<'snap> { + changed_vars: Vec<String>, + prev_working_dir: Option<PathBuf>, + snap: &'snap EnvSnapshot, +} + +impl<'snap> EnvChange<'snap> { + fn apply( + snap: &'snap EnvSnapshot, + new_vars: Vec<(String, String)>, + current_dir: Option<&Path>, + ) -> EnvChange<'snap> { + let prev_working_dir = match current_dir { + Some(dir) => { + let prev_working_dir = std::env::current_dir().ok(); + if let Err(err) = std::env::set_current_dir(dir) { + eprintln!( + "Failed to set the current working dir to {}. Error: {err:?}", + dir.display() + ) + } + prev_working_dir + } + None => None, + }; + EnvChange { + snap, + changed_vars: new_vars + .into_iter() + .map(|(k, v)| { + env::set_var(&k, v); + k + }) + .collect(), + prev_working_dir, + } + } fn rollback(self) {} } -impl Drop for EnvSnapshot { +impl Drop for EnvChange<'_> { fn drop(&mut self) { - for (name, value) in env::vars_os() { - let old_value = self.vars.remove(&name); - if old_value != Some(value) { - match old_value { - None => env::remove_var(name), - Some(old_value) => env::set_var(name, old_value), - } + for name in self.changed_vars.drain(..) { + match self.snap.vars.get::<std::ffi::OsStr>(name.as_ref()) { + Some(prev_val) => env::set_var(name, prev_val), + None => env::remove_var(name), } } - for (name, old_value) in self.vars.drain() { - env::set_var(name, old_value) + + if let Some(dir) = &self.prev_working_dir { + if let Err(err) = std::env::set_current_dir(&dir) { + eprintln!( + "Failed to set the current working dir to {}. Error: {:?}", + dir.display(), + err + ) + } } } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs index 631fd84aa24..d48c5b30dee 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/proc_macros.rs @@ -1,8 +1,9 @@ //! Proc macro ABI -use libloading::Library; use proc_macro::bridge; -use proc_macro_api::{ProcMacroKind, RustCInfo}; +use proc_macro_api::ProcMacroKind; + +use libloading::Library; use crate::{dylib::LoadProcMacroDylibError, ProcMacroSrvSpan}; @@ -29,15 +30,15 @@ impl ProcMacros { pub(crate) fn from_lib( lib: &Library, symbol_name: String, - info: RustCInfo, + version_string: &str, ) -> Result<ProcMacros, LoadProcMacroDylibError> { - if info.version_string == crate::RUSTC_VERSION_STRING { + if version_string == crate::RUSTC_VERSION_STRING { let macros = unsafe { lib.get::<&&[bridge::client::ProcMacro]>(symbol_name.as_bytes()) }?; return Ok(Self { exported_macros: macros.to_vec() }); } - Err(LoadProcMacroDylibError::AbiMismatch(info.version_string)) + Err(LoadProcMacroDylibError::AbiMismatch(version_string.to_owned())) } pub(crate) fn expand<S: ProcMacroSrvSpan>( @@ -49,11 +50,12 @@ impl ProcMacros { call_site: S, mixed_site: S, ) -> Result<tt::Subtree<S>, crate::PanicMessage> { - let parsed_body = crate::server::TokenStream::with_subtree(macro_body); + let parsed_body = crate::server_impl::TokenStream::with_subtree(macro_body); - let parsed_attributes = attributes.map_or_else(crate::server::TokenStream::new, |attr| { - crate::server::TokenStream::with_subtree(attr) - }); + let parsed_attributes = attributes + .map_or_else(crate::server_impl::TokenStream::new, |attr| { + crate::server_impl::TokenStream::with_subtree(attr) + }); for proc_macro in &self.exported_macros { match proc_macro { @@ -117,16 +119,3 @@ impl ProcMacros { .collect() } } - -#[test] -fn test_version_check() { - let path = paths::AbsPathBuf::assert(crate::proc_macro_test_dylib_path()); - let info = proc_macro_api::read_dylib_info(&path).unwrap(); - assert_eq!( - info.version_string, - crate::RUSTC_VERSION_STRING, - "sysroot ABI mismatch: dylib rustc version (read from .rustc section): {:?} != proc-macro-srv version (read from 'rustc --version'): {:?}", - info.version_string, - crate::RUSTC_VERSION_STRING, - ); -} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index e8b340a43d3..e8b340a43d3 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 0350bde4122..bb174ba1b22 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -14,7 +14,7 @@ use proc_macro::bridge::{self, server}; use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER}; use tt::{TextRange, TextSize}; -use crate::server::{ +use crate::server_impl::{ delim_to_external, delim_to_internal, literal_with_stringify_parts, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; @@ -29,7 +29,7 @@ mod tt { pub type Ident = ::tt::Ident<super::Span>; } -type TokenStream = crate::server::TokenStream<Span>; +type TokenStream = crate::server_impl::TokenStream<Span>; #[derive(Clone)] pub struct SourceFile; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/symbol.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs index 540d06457f2..540d06457f2 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/symbol.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/symbol.rs diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index ad7bd954cf1..12edacbe39d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -7,7 +7,7 @@ use std::{ use proc_macro::bridge::{self, server}; -use crate::server::{ +use crate::server_impl::{ delim_to_external, delim_to_internal, literal_with_stringify_parts, token_stream::TokenStreamBuilder, Symbol, SymbolInternerRef, SYMBOL_INTERNER, }; @@ -31,7 +31,7 @@ type Spacing = tt::Spacing; #[allow(unused)] type Literal = tt::Literal; type Span = tt::TokenId; -type TokenStream = crate::server::TokenStream<Span>; +type TokenStream = crate::server_impl::TokenStream<Span>; #[derive(Clone)] pub struct SourceFile; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs index b1a448427c6..b1a448427c6 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index 6050bc9e36e..03b1117a5bd 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -5,10 +5,10 @@ use proc_macro_api::msg::TokenId; use span::{ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId}; use tt::TextRange; -use crate::{dylib, proc_macro_test_dylib_path, ProcMacroSrv}; +use crate::{dylib, proc_macro_test_dylib_path, EnvSnapshot, ProcMacroSrv}; -fn parse_string(call_site: TokenId, src: &str) -> crate::server::TokenStream<TokenId> { - crate::server::TokenStream::with_subtree( +fn parse_string(call_site: TokenId, src: &str) -> crate::server_impl::TokenStream<TokenId> { + crate::server_impl::TokenStream::with_subtree( mbe::parse_to_token_tree_static_span(call_site, src).unwrap(), ) } @@ -17,8 +17,8 @@ fn parse_string_spanned( anchor: SpanAnchor, call_site: SyntaxContextId, src: &str, -) -> crate::server::TokenStream<Span> { - crate::server::TokenStream::with_subtree( +) -> crate::server_impl::TokenStream<Span> { + crate::server_impl::TokenStream::with_subtree( mbe::parse_to_token_tree(anchor, call_site, src).unwrap(), ) } @@ -96,7 +96,8 @@ fn assert_expand_impl( pub(crate) fn list() -> Vec<String> { let dylib_path = proc_macro_test_dylib_path(); - let mut srv = ProcMacroSrv::default(); + let env = EnvSnapshot::new(); + let mut srv = ProcMacroSrv::new(&env); let res = srv.list_macros(&dylib_path).unwrap(); res.into_iter().map(|(name, kind)| format!("{name} [{kind:?}]")).collect() } diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml index 11a8e7af56a..5989dc6c962 100644 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml @@ -12,12 +12,8 @@ rust-version.workspace = true doctest = false [dependencies] -once_cell = "1.17.0" -tracing.workspace = true cfg-if = "1.0.0" -la-arena.workspace = true libc.workspace = true -countme = { version = "3.0.1", features = ["enable"] } jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = true } [target.'cfg(target_os = "linux")'.dependencies] diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs index 2ccb1cd06ae..205341f162d 100644 --- a/src/tools/rust-analyzer/crates/profile/src/lib.rs +++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs @@ -1,7 +1,5 @@ //! A collection of tools for profiling rust-analyzer. -#![warn(rust_2018_idioms, unused_lifetimes)] - #[cfg(feature = "cpu_profiler")] mod google_cpu_profiler; mod memory_usage; @@ -14,13 +12,6 @@ pub use crate::{ stop_watch::{StopWatch, StopWatchSpan}, }; -pub use countme; -/// Include `_c: Count<Self>` field in important structs to count them. -/// -/// To view the counts, run with `RA_COUNT=1`. The overhead of disabled count is -/// almost zero. -pub use countme::Count; - thread_local!(static IN_SCOPE: RefCell<bool> = const { RefCell::new(false) }); /// A wrapper around google_cpu_profiler. diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs index 990b59cad42..0a803959eed 100644 --- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs +++ b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs @@ -29,11 +29,10 @@ impl StopWatch { // When debugging rust-analyzer using rr, the perf-related syscalls cause it to abort. // We allow disabling perf by setting the env var `RA_DISABLE_PERF`. - use once_cell::sync::Lazy; - static PERF_ENABLED: Lazy<bool> = - Lazy::new(|| std::env::var_os("RA_DISABLE_PERF").is_none()); + use std::sync::OnceLock; + static PERF_ENABLED: OnceLock<bool> = OnceLock::new(); - if *PERF_ENABLED { + if *PERF_ENABLED.get_or_init(|| std::env::var_os("RA_DISABLE_PERF").is_none()) { let mut counter = perf_event::Builder::new() .build() .map_err(|err| eprintln!("Failed to create perf counter: {err}")) diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs index d2f423590e2..839d8e569fe 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs @@ -18,7 +18,6 @@ use itertools::Itertools; use la_arena::ArenaMap; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; -use semver::Version; use serde::Deserialize; use toolchain::Tool; @@ -64,10 +63,8 @@ impl WorkspaceBuildScripts { config: &CargoConfig, allowed_features: &FxHashSet<String>, manifest_path: &ManifestPath, - toolchain: Option<&Version>, sysroot: &Sysroot, ) -> io::Result<Command> { - const RUST_1_75: Version = Version::new(1, 75, 0); let mut cmd = match config.run_build_script_command.as_deref() { Some([program, args @ ..]) => { let mut cmd = Command::new(program); @@ -122,9 +119,7 @@ impl WorkspaceBuildScripts { cmd.arg("-Zscript"); } - if toolchain.map_or(false, |it| *it >= RUST_1_75) { - cmd.arg("--keep-going"); - } + cmd.arg("--keep-going"); cmd } @@ -148,7 +143,6 @@ impl WorkspaceBuildScripts { config: &CargoConfig, workspace: &CargoWorkspace, progress: &dyn Fn(String), - toolchain: Option<&Version>, sysroot: &Sysroot, ) -> io::Result<WorkspaceBuildScripts> { let current_dir = match &config.invocation_location { @@ -160,13 +154,8 @@ impl WorkspaceBuildScripts { .as_ref(); let allowed_features = workspace.workspace_features(); - let cmd = Self::build_command( - config, - &allowed_features, - workspace.manifest_path(), - toolchain, - sysroot, - )?; + let cmd = + Self::build_command(config, &allowed_features, workspace.manifest_path(), sysroot)?; Self::run_per_ws(cmd, workspace, current_dir, progress) } @@ -194,7 +183,6 @@ impl WorkspaceBuildScripts { &Default::default(), // This is not gonna be used anyways, so just construct a dummy here &ManifestPath::try_from(workspace_root.clone()).unwrap(), - None, &Sysroot::empty(), )?; // NB: Cargo.toml could have been modified between `cargo metadata` and diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs index 35643dcc028..92bf6a08f87 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs @@ -15,8 +15,6 @@ //! procedural macros). //! * Lowering of concrete model to a [`base_db::CrateGraph`] -#![warn(rust_2018_idioms, unused_lifetimes)] - mod build_scripts; mod cargo_workspace; mod cfg; diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index 17e40e74de3..5e27ce29873 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -450,16 +450,10 @@ impl ProjectWorkspace { match &self.kind { ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } | ProjectWorkspaceKind::Cargo { cargo, .. } => { - WorkspaceBuildScripts::run_for_workspace( - config, - cargo, - progress, - self.toolchain.as_ref(), - &self.sysroot, - ) - .with_context(|| { - format!("Failed to run build scripts for {}", cargo.workspace_root()) - }) + WorkspaceBuildScripts::run_for_workspace(config, cargo, progress, &self.sysroot) + .with_context(|| { + format!("Failed to run build scripts for {}", cargo.workspace_root()) + }) } ProjectWorkspaceKind::DetachedFile { cargo: None, .. } | ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 8ff7235b8fa..93fb55ede8e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -47,7 +47,6 @@ always-assert = "0.2.0" walkdir = "2.3.2" semver.workspace = true memchr = "2.7.1" -indexmap = { workspace = true, features = ["serde"] } cfg.workspace = true flycheck.workspace = true @@ -82,7 +81,6 @@ xshell.workspace = true test-utils.workspace = true test-fixture.workspace = true -sourcegen.workspace = true mbe.workspace = true [features] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index 774784f37b0..1985093bc5c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -2,7 +2,6 @@ //! //! Based on cli flags, either spawns an LSP server, or runs a batch analysis -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::print_stdout, clippy::print_stderr)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/capabilities.rs new file mode 100644 index 00000000000..212294b5d32 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/capabilities.rs @@ -0,0 +1,493 @@ +//! Advertises the capabilities of the LSP Server. +use ide_db::{line_index::WideEncoding, FxHashSet}; +use lsp_types::{ + CallHierarchyServerCapability, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, + CodeLensOptions, CompletionOptions, CompletionOptionsCompletionItem, DeclarationCapability, + DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationPattern, + FileOperationPatternKind, FileOperationRegistrationOptions, FoldingRangeProviderCapability, + HoverProviderCapability, ImplementationProviderCapability, InlayHintOptions, + InlayHintServerCapabilities, OneOf, PositionEncodingKind, RenameOptions, SaveOptions, + SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend, + SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, + TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability, + WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities, + WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities, +}; +use serde_json::json; + +use crate::{ + config::{Config, RustfmtConfig}, + line_index::PositionEncoding, + lsp::{ext, semantic_tokens}, +}; + +pub fn server_capabilities(config: &Config) -> ServerCapabilities { + ServerCapabilities { + position_encoding: match config.caps().negotiated_encoding() { + PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8), + PositionEncoding::Wide(wide) => match wide { + WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16), + WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32), + _ => None, + }, + }, + text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { + open_close: Some(true), + change: Some(TextDocumentSyncKind::INCREMENTAL), + will_save: None, + will_save_wait_until: None, + save: Some(SaveOptions::default().into()), + })), + hover_provider: Some(HoverProviderCapability::Simple(true)), + completion_provider: Some(CompletionOptions { + resolve_provider: config.caps().completions_resolve_provider(), + trigger_characters: Some(vec![ + ":".to_owned(), + ".".to_owned(), + "'".to_owned(), + "(".to_owned(), + ]), + all_commit_characters: None, + completion_item: config.caps().completion_item(), + work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, + }), + signature_help_provider: Some(SignatureHelpOptions { + trigger_characters: Some(vec!["(".to_owned(), ",".to_owned(), "<".to_owned()]), + retrigger_characters: None, + work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, + }), + declaration_provider: Some(DeclarationCapability::Simple(true)), + definition_provider: Some(OneOf::Left(true)), + type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), + implementation_provider: Some(ImplementationProviderCapability::Simple(true)), + references_provider: Some(OneOf::Left(true)), + document_highlight_provider: Some(OneOf::Left(true)), + document_symbol_provider: Some(OneOf::Left(true)), + workspace_symbol_provider: Some(OneOf::Left(true)), + code_action_provider: Some(config.caps().code_action_capabilities()), + code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), + document_formatting_provider: Some(OneOf::Left(true)), + document_range_formatting_provider: match config.rustfmt() { + RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), + _ => Some(OneOf::Left(false)), + }, + document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { + first_trigger_character: "=".to_owned(), + more_trigger_character: Some(more_trigger_character(config)), + }), + selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), + folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), + rename_provider: Some(OneOf::Right(RenameOptions { + prepare_provider: Some(true), + work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, + })), + linked_editing_range_provider: None, + document_link_provider: None, + color_provider: None, + execute_command_provider: None, + workspace: Some(WorkspaceServerCapabilities { + workspace_folders: Some(WorkspaceFoldersServerCapabilities { + supported: Some(true), + change_notifications: Some(OneOf::Left(true)), + }), + file_operations: Some(WorkspaceFileOperationsServerCapabilities { + did_create: None, + will_create: None, + did_rename: None, + will_rename: Some(FileOperationRegistrationOptions { + filters: vec![ + FileOperationFilter { + scheme: Some(String::from("file")), + pattern: FileOperationPattern { + glob: String::from("**/*.rs"), + matches: Some(FileOperationPatternKind::File), + options: None, + }, + }, + FileOperationFilter { + scheme: Some(String::from("file")), + pattern: FileOperationPattern { + glob: String::from("**"), + matches: Some(FileOperationPatternKind::Folder), + options: None, + }, + }, + ], + }), + did_delete: None, + will_delete: None, + }), + }), + call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), + semantic_tokens_provider: Some( + SemanticTokensOptions { + legend: SemanticTokensLegend { + token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(), + token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(), + }, + + full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), + range: Some(true), + work_done_progress_options: Default::default(), + } + .into(), + ), + moniker_provider: None, + inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( + InlayHintOptions { + work_done_progress_options: Default::default(), + resolve_provider: Some(true), + }, + ))), + inline_value_provider: None, + experimental: Some(json!({ + "externalDocs": true, + "hoverRange": true, + "joinLines": true, + "matchingBrace": true, + "moveItem": true, + "onEnter": true, + "openCargoToml": true, + "parentModule": true, + "runnables": { + "kinds": [ "cargo" ], + }, + "ssr": true, + "workspaceSymbolScopeKindFiltering": true, + })), + diagnostic_provider: None, + inline_completion_provider: None, + } +} + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct ClientCapabilities(lsp_types::ClientCapabilities); + +impl ClientCapabilities { + pub fn new(caps: lsp_types::ClientCapabilities) -> Self { + Self(caps) + } + + fn completions_resolve_provider(&self) -> Option<bool> { + self.completion_item_edit_resolve().then_some(true) + } + + fn experimental_bool(&self, index: &'static str) -> bool { + || -> _ { self.0.experimental.as_ref()?.get(index)?.as_bool() }().unwrap_or_default() + } + + fn experimental<T: serde::de::DeserializeOwned>(&self, index: &'static str) -> Option<T> { + serde_json::from_value(self.0.experimental.as_ref()?.get(index)?.clone()).ok() + } + + /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. + pub fn completion_item_edit_resolve(&self) -> bool { + (|| { + Some( + self.0 + .text_document + .as_ref()? + .completion + .as_ref()? + .completion_item + .as_ref()? + .resolve_support + .as_ref()? + .properties + .iter() + .any(|cap_string| cap_string.as_str() == "additionalTextEdits"), + ) + })() == Some(true) + } + + pub fn completion_label_details_support(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .completion + .as_ref()? + .completion_item + .as_ref()? + .label_details_support + .as_ref() + })() + .is_some() + } + + fn completion_item(&self) -> Option<CompletionOptionsCompletionItem> { + Some(CompletionOptionsCompletionItem { + label_details_support: Some(self.completion_label_details_support()), + }) + } + + fn code_action_capabilities(&self) -> CodeActionProviderCapability { + self.0 + .text_document + .as_ref() + .and_then(|it| it.code_action.as_ref()) + .and_then(|it| it.code_action_literal_support.as_ref()) + .map_or(CodeActionProviderCapability::Simple(true), |_| { + CodeActionProviderCapability::Options(CodeActionOptions { + // Advertise support for all built-in CodeActionKinds. + // Ideally we would base this off of the client capabilities + // but the client is supposed to fall back gracefully for unknown values. + code_action_kinds: Some(vec![ + CodeActionKind::EMPTY, + CodeActionKind::QUICKFIX, + CodeActionKind::REFACTOR, + CodeActionKind::REFACTOR_EXTRACT, + CodeActionKind::REFACTOR_INLINE, + CodeActionKind::REFACTOR_REWRITE, + ]), + resolve_provider: Some(true), + work_done_progress_options: Default::default(), + }) + }) + } + + pub fn negotiated_encoding(&self) -> PositionEncoding { + let client_encodings = match &self.0.general { + Some(general) => general.position_encodings.as_deref().unwrap_or_default(), + None => &[], + }; + + for enc in client_encodings { + if enc == &PositionEncodingKind::UTF8 { + return PositionEncoding::Utf8; + } else if enc == &PositionEncodingKind::UTF32 { + return PositionEncoding::Wide(WideEncoding::Utf32); + } + // NB: intentionally prefer just about anything else to utf-16. + } + + PositionEncoding::Wide(WideEncoding::Utf16) + } + + pub fn workspace_edit_resource_operations( + &self, + ) -> Option<&[lsp_types::ResourceOperationKind]> { + self.0.workspace.as_ref()?.workspace_edit.as_ref()?.resource_operations.as_deref() + } + + pub fn semantics_tokens_augments_syntax_tokens(&self) -> bool { + (|| -> _ { + self.0.text_document.as_ref()?.semantic_tokens.as_ref()?.augments_syntax_tokens + })() + .unwrap_or(false) + } + + pub fn did_save_text_document_dynamic_registration(&self) -> bool { + let caps = (|| -> _ { self.0.text_document.as_ref()?.synchronization.clone() })() + .unwrap_or_default(); + caps.did_save == Some(true) && caps.dynamic_registration == Some(true) + } + + pub fn did_change_watched_files_dynamic_registration(&self) -> bool { + (|| -> _ { + self.0.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration + })() + .unwrap_or_default() + } + + pub fn did_change_watched_files_relative_pattern_support(&self) -> bool { + (|| -> _ { + self.0.workspace.as_ref()?.did_change_watched_files.as_ref()?.relative_pattern_support + })() + .unwrap_or_default() + } + + pub fn location_link(&self) -> bool { + (|| -> _ { self.0.text_document.as_ref()?.definition?.link_support })().unwrap_or_default() + } + + pub fn line_folding_only(&self) -> bool { + (|| -> _ { self.0.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only })() + .unwrap_or_default() + } + + pub fn hierarchical_symbols(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .document_symbol + .as_ref()? + .hierarchical_document_symbol_support + })() + .unwrap_or_default() + } + + pub fn code_action_literals(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .code_action + .as_ref()? + .code_action_literal_support + .as_ref() + })() + .is_some() + } + + pub fn work_done_progress(&self) -> bool { + (|| -> _ { self.0.window.as_ref()?.work_done_progress })().unwrap_or_default() + } + + pub fn will_rename(&self) -> bool { + (|| -> _ { self.0.workspace.as_ref()?.file_operations.as_ref()?.will_rename })() + .unwrap_or_default() + } + + pub fn change_annotation_support(&self) -> bool { + (|| -> _ { + self.0.workspace.as_ref()?.workspace_edit.as_ref()?.change_annotation_support.as_ref() + })() + .is_some() + } + + pub fn code_action_resolve(&self) -> bool { + (|| -> _ { + Some( + self.0 + .text_document + .as_ref()? + .code_action + .as_ref()? + .resolve_support + .as_ref()? + .properties + .as_slice(), + ) + })() + .unwrap_or_default() + .iter() + .any(|it| it == "edit") + } + + pub fn signature_help_label_offsets(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .signature_help + .as_ref()? + .signature_information + .as_ref()? + .parameter_information + .as_ref()? + .label_offset_support + })() + .unwrap_or_default() + } + + pub fn code_action_group(&self) -> bool { + self.experimental_bool("codeActionGroup") + } + + pub fn commands(&self) -> Option<ext::ClientCommandOptions> { + self.experimental("commands") + } + + pub fn local_docs(&self) -> bool { + self.experimental_bool("localDocs") + } + + pub fn open_server_logs(&self) -> bool { + self.experimental_bool("openServerLogs") + } + + pub fn server_status_notification(&self) -> bool { + self.experimental_bool("serverStatusNotification") + } + + pub fn snippet_text_edit(&self) -> bool { + self.experimental_bool("snippetTextEdit") + } + + pub fn hover_actions(&self) -> bool { + self.experimental_bool("hoverActions") + } + + /// Whether the client supports colored output for full diagnostics from `checkOnSave`. + pub fn color_diagnostic_output(&self) -> bool { + self.experimental_bool("colorDiagnosticOutput") + } + + pub fn test_explorer(&self) -> bool { + self.experimental_bool("testExplorer") + } + + pub fn completion_snippet(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .completion + .as_ref()? + .completion_item + .as_ref()? + .snippet_support + })() + .unwrap_or_default() + } + + pub fn semantic_tokens_refresh(&self) -> bool { + (|| -> _ { self.0.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support })() + .unwrap_or_default() + } + + pub fn code_lens_refresh(&self) -> bool { + (|| -> _ { self.0.workspace.as_ref()?.code_lens.as_ref()?.refresh_support })() + .unwrap_or_default() + } + + pub fn inlay_hints_refresh(&self) -> bool { + (|| -> _ { self.0.workspace.as_ref()?.inlay_hint.as_ref()?.refresh_support })() + .unwrap_or_default() + } + + pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<String> { + self.0 + .text_document + .as_ref() + .and_then(|text| text.inlay_hint.as_ref()) + .and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref()) + .map(|inlay_resolve| inlay_resolve.properties.iter()) + .into_iter() + .flatten() + .cloned() + .collect::<FxHashSet<_>>() + } + + pub fn hover_markdown_support(&self) -> bool { + (|| -> _ { + Some(self.0.text_document.as_ref()?.hover.as_ref()?.content_format.as_ref()?.as_slice()) + })() + .unwrap_or_default() + .contains(&lsp_types::MarkupKind::Markdown) + } + + pub fn insert_replace_support(&self) -> bool { + (|| -> _ { + self.0 + .text_document + .as_ref()? + .completion + .as_ref()? + .completion_item + .as_ref()? + .insert_replace_support + })() + .unwrap_or_default() + } +} + +fn more_trigger_character(config: &Config) -> Vec<String> { + let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()]; + if config.snippet_cap().is_some() { + res.push("<".to_owned()); + } + res +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs deleted file mode 100644 index a207be3cac3..00000000000 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs +++ /dev/null @@ -1,230 +0,0 @@ -//! Advertises the capabilities of the LSP Server. -use ide_db::line_index::WideEncoding; -use lsp_types::{ - CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions, - CodeActionProviderCapability, CodeLensOptions, CompletionOptions, - CompletionOptionsCompletionItem, DeclarationCapability, DocumentOnTypeFormattingOptions, - FileOperationFilter, FileOperationPattern, FileOperationPatternKind, - FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability, - ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf, - PositionEncodingKind, RenameOptions, SaveOptions, SelectionRangeProviderCapability, - SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, - SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, - TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, - WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities, - WorkspaceServerCapabilities, -}; -use serde_json::json; - -use crate::{ - config::{Config, RustfmtConfig}, - line_index::PositionEncoding, - lsp::semantic_tokens, - lsp_ext::negotiated_encoding, -}; - -pub fn server_capabilities(config: &Config) -> ServerCapabilities { - ServerCapabilities { - position_encoding: match negotiated_encoding(config.caps()) { - PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8), - PositionEncoding::Wide(wide) => match wide { - WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16), - WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32), - _ => None, - }, - }, - text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions { - open_close: Some(true), - change: Some(TextDocumentSyncKind::INCREMENTAL), - will_save: None, - will_save_wait_until: None, - save: Some(SaveOptions::default().into()), - })), - hover_provider: Some(HoverProviderCapability::Simple(true)), - completion_provider: Some(CompletionOptions { - resolve_provider: completions_resolve_provider(config.caps()), - trigger_characters: Some(vec![ - ":".to_owned(), - ".".to_owned(), - "'".to_owned(), - "(".to_owned(), - ]), - all_commit_characters: None, - completion_item: completion_item(config), - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - }), - signature_help_provider: Some(SignatureHelpOptions { - trigger_characters: Some(vec!["(".to_owned(), ",".to_owned(), "<".to_owned()]), - retrigger_characters: None, - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - }), - declaration_provider: Some(DeclarationCapability::Simple(true)), - definition_provider: Some(OneOf::Left(true)), - type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), - implementation_provider: Some(ImplementationProviderCapability::Simple(true)), - references_provider: Some(OneOf::Left(true)), - document_highlight_provider: Some(OneOf::Left(true)), - document_symbol_provider: Some(OneOf::Left(true)), - workspace_symbol_provider: Some(OneOf::Left(true)), - code_action_provider: Some(code_action_capabilities(config.caps())), - code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), - document_formatting_provider: Some(OneOf::Left(true)), - document_range_formatting_provider: match config.rustfmt() { - RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), - _ => Some(OneOf::Left(false)), - }, - document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { - first_trigger_character: "=".to_owned(), - more_trigger_character: Some(more_trigger_character(config)), - }), - selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), - folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), - rename_provider: Some(OneOf::Right(RenameOptions { - prepare_provider: Some(true), - work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None }, - })), - linked_editing_range_provider: None, - document_link_provider: None, - color_provider: None, - execute_command_provider: None, - workspace: Some(WorkspaceServerCapabilities { - workspace_folders: Some(WorkspaceFoldersServerCapabilities { - supported: Some(true), - change_notifications: Some(OneOf::Left(true)), - }), - file_operations: Some(WorkspaceFileOperationsServerCapabilities { - did_create: None, - will_create: None, - did_rename: None, - will_rename: Some(FileOperationRegistrationOptions { - filters: vec![ - FileOperationFilter { - scheme: Some(String::from("file")), - pattern: FileOperationPattern { - glob: String::from("**/*.rs"), - matches: Some(FileOperationPatternKind::File), - options: None, - }, - }, - FileOperationFilter { - scheme: Some(String::from("file")), - pattern: FileOperationPattern { - glob: String::from("**"), - matches: Some(FileOperationPatternKind::Folder), - options: None, - }, - }, - ], - }), - did_delete: None, - will_delete: None, - }), - }), - call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)), - semantic_tokens_provider: Some( - SemanticTokensOptions { - legend: SemanticTokensLegend { - token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(), - token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(), - }, - - full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }), - range: Some(true), - work_done_progress_options: Default::default(), - } - .into(), - ), - moniker_provider: None, - inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( - InlayHintOptions { - work_done_progress_options: Default::default(), - resolve_provider: Some(true), - }, - ))), - inline_value_provider: None, - experimental: Some(json!({ - "externalDocs": true, - "hoverRange": true, - "joinLines": true, - "matchingBrace": true, - "moveItem": true, - "onEnter": true, - "openCargoToml": true, - "parentModule": true, - "runnables": { - "kinds": [ "cargo" ], - }, - "ssr": true, - "workspaceSymbolScopeKindFiltering": true, - })), - diagnostic_provider: None, - inline_completion_provider: None, - } -} - -fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> { - if completion_item_edit_resolve(client_caps) { - Some(true) - } else { - tracing::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled"); - None - } -} - -/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports. -pub(crate) fn completion_item_edit_resolve(caps: &ClientCapabilities) -> bool { - (|| { - Some( - caps.text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .resolve_support - .as_ref()? - .properties - .iter() - .any(|cap_string| cap_string.as_str() == "additionalTextEdits"), - ) - })() == Some(true) -} - -fn completion_item(config: &Config) -> Option<CompletionOptionsCompletionItem> { - Some(CompletionOptionsCompletionItem { - label_details_support: Some(config.completion_label_details_support()), - }) -} - -fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability { - client_caps - .text_document - .as_ref() - .and_then(|it| it.code_action.as_ref()) - .and_then(|it| it.code_action_literal_support.as_ref()) - .map_or(CodeActionProviderCapability::Simple(true), |_| { - CodeActionProviderCapability::Options(CodeActionOptions { - // Advertise support for all built-in CodeActionKinds. - // Ideally we would base this off of the client capabilities - // but the client is supposed to fall back gracefully for unknown values. - code_action_kinds: Some(vec![ - CodeActionKind::EMPTY, - CodeActionKind::QUICKFIX, - CodeActionKind::REFACTOR, - CodeActionKind::REFACTOR_EXTRACT, - CodeActionKind::REFACTOR_INLINE, - CodeActionKind::REFACTOR_REWRITE, - ]), - resolve_provider: Some(true), - work_done_progress_options: Default::default(), - }) - }) -} - -fn more_trigger_character(config: &Config) -> Vec<String> { - let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()]; - if config.snippet_cap().is_some() { - res.push("<".to_owned()); - } - res -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 90b81d0a80d..90316f3b89d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -250,10 +250,6 @@ impl flags::AnalysisStats { } report_metric("total memory", total_span.memory.allocated.megabytes() as u64, "MB"); - if env::var("RA_COUNT").is_ok() { - eprintln!("{}", profile::countme::get_all()); - } - if self.source_stats { let mut total_file_size = Bytes::default(); for e in ide_db::base_db::ParseQuery.in_db(db).entries::<Vec<_>>() { @@ -443,7 +439,11 @@ impl flags::AnalysisStats { .gen_source_code( &scope, &mut formatter, - ImportPathConfig { prefer_no_std: false, prefer_prelude: true }, + ImportPathConfig { + prefer_no_std: false, + prefer_prelude: true, + prefer_absolute: false, + }, ) .unwrap(); syntax_hit_found |= trim(&original_text) == trim(&generated); @@ -651,7 +651,7 @@ impl flags::AnalysisStats { if let Some(src) = source { let original_file = src.file_id.original_file(db); let path = vfs.file_path(original_file); - let syntax_range = src.value.text_range(); + let syntax_range = src.text_range(); format!("processing: {} ({} {:?})", full_name(), path, syntax_range) } else { format!("processing: {}", full_name()) @@ -945,7 +945,7 @@ impl flags::AnalysisStats { if let Some(src) = source { let original_file = src.file_id.original_file(db); let path = vfs.file_path(original_file); - let syntax_range = src.value.text_range(); + let syntax_range = src.text_range(); format!("processing: {} ({} {:?})", full_name(), path, syntax_range) } else { format!("processing: {}", full_name()) @@ -992,8 +992,10 @@ impl flags::AnalysisStats { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, style_lints: false, term_search_fuel: 400, + term_search_borrowck: true, }, ide::AssistResolveStrategy::All, file_id, @@ -1006,6 +1008,11 @@ impl flags::AnalysisStats { type_hints: true, discriminant_hints: ide::DiscriminantHints::Always, parameter_hints: true, + generic_parameter_hints: ide::GenericParameterHints { + type_hints: true, + lifetime_hints: true, + const_hints: true, + }, chaining_hints: true, adjustment_hints: ide::AdjustmentHints::Always, adjustment_hints_mode: ide::AdjustmentHintsMode::Postfix, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index e8504979bed..3594cdda2e9 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -10,17 +10,15 @@ use dirs::config_dir; use flycheck::{CargoOptions, FlycheckConfig}; use ide::{ AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, - InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, - Snippet, SnippetScope, SourceRootId, + GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, + InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, + MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, SnippetCap, }; -use indexmap::IndexMap; use itertools::Itertools; -use lsp_types::{ClientCapabilities, MarkupKind}; use paths::{Utf8Path, Utf8PathBuf}; use project_model::{ CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource, @@ -36,10 +34,9 @@ use triomphe::Arc; use vfs::{AbsPath, AbsPathBuf, VfsPath}; use crate::{ - caps::completion_item_edit_resolve, + capabilities::ClientCapabilities, diagnostics::DiagnosticsMapConfig, - line_index::PositionEncoding, - lsp_ext::{self, negotiated_encoding, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope}, + lsp_ext::{WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope}, }; mod patch_old_style; @@ -341,8 +338,10 @@ config_data! { assist_emitMustUse: bool = false, /// Placeholder expression to use for missing expressions in assists. assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo, - /// Term search fuel in "units of work" for assists (Defaults to 400). - assist_termSearch_fuel: usize = 400, + /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check. + assist_termSearch_borrowcheck: bool = true, + /// Term search fuel in "units of work" for assists (Defaults to 1800). + assist_termSearch_fuel: usize = 1800, /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file. imports_granularity_enforce: bool = false, @@ -358,6 +357,8 @@ config_data! { imports_preferPrelude: bool = false, /// The path structure for newly inserted paths to use. imports_prefix: ImportPrefixDef = ImportPrefixDef::Plain, + /// Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". + imports_prefixExternPrelude: bool = false, } } @@ -382,8 +383,7 @@ config_data! { /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position. completion_privateEditable_enable: bool = false, /// Custom completion snippets. - // NOTE: we use IndexMap for deterministic serialization ordering - completion_snippets_custom: IndexMap<String, SnippetDef> = serde_json::from_str(r#"{ + completion_snippets_custom: FxHashMap<String, SnippetDef> = serde_json::from_str(r#"{ "Arc::new": { "postfix": "arc", "body": "Arc::new(${receiver})", @@ -426,8 +426,8 @@ config_data! { }"#).unwrap(), /// Whether to enable term search based snippets like `Some(foo.bar().baz())`. completion_termSearch_enable: bool = false, - /// Term search fuel in "units of work" for autocompletion (Defaults to 200). - completion_termSearch_fuel: usize = 200, + /// Term search fuel in "units of work" for autocompletion (Defaults to 1000). + completion_termSearch_fuel: usize = 1000, /// Controls file watching implementation. files_watcher: FilesWatcherDef = FilesWatcherDef::Client, @@ -509,6 +509,12 @@ config_data! { inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false, /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix, + /// Whether to show const generic parameter name inlay hints. + inlayHints_genericParameterHints_const_enable: bool= false, + /// Whether to show generic lifetime parameter name inlay hints. + inlayHints_genericParameterHints_lifetime_enable: bool = true, + /// Whether to show generic type parameter name inlay hints. + inlayHints_genericParameterHints_type_enable: bool = false, /// Whether to show implicit drop hints. inlayHints_implicitDrops_enable: bool = false, /// Whether to show inlay type hints for elided lifetimes in function signatures. @@ -659,7 +665,7 @@ pub struct Config { discovered_projects: Vec<ProjectManifest>, /// The workspace roots as registered by the LSP client workspace_roots: Vec<AbsPathBuf>, - caps: lsp_types::ClientCapabilities, + caps: ClientCapabilities, root_path: AbsPathBuf, snippets: Vec<Snippet>, visual_studio_code_version: Option<Version>, @@ -698,6 +704,15 @@ pub struct Config { detached_files: Vec<AbsPathBuf>, } +// Delegate capability fetching methods +impl std::ops::Deref for Config { + type Target = ClientCapabilities; + + fn deref(&self) -> &Self::Target { + &self.caps + } +} + impl Config { pub fn user_config_path(&self) -> &VfsPath { &self.user_config_path @@ -844,6 +859,9 @@ impl Config { config.source_root_parent_map = source_root_map; } + // IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`. + config.snippets.clear(); + let snips = self.completion_snippets_custom().to_owned(); for (name, def) in snips.iter() { @@ -951,23 +969,6 @@ impl ConfigChange { } } -macro_rules! try_ { - ($expr:expr) => { - || -> _ { Some($expr) }() - }; -} -macro_rules! try_or { - ($expr:expr, $or:expr) => { - try_!($expr).unwrap_or($or) - }; -} - -macro_rules! try_or_def { - ($expr:expr) => { - try_!($expr).unwrap_or_default() - }; -} - #[derive(Debug, Clone, Eq, PartialEq)] pub enum LinkedProject { ProjectManifest(ProjectManifest), @@ -1174,7 +1175,7 @@ impl std::error::Error for ConfigErrors {} impl Config { pub fn new( root_path: AbsPathBuf, - caps: ClientCapabilities, + caps: lsp_types::ClientCapabilities, workspace_roots: Vec<AbsPathBuf>, visual_studio_code_version: Option<Version>, user_config_path: Option<Utf8PathBuf>, @@ -1202,7 +1203,7 @@ impl Config { }; Config { - caps, + caps: ClientCapabilities::new(caps), discovered_projects: Vec::new(), root_path, snippets: Default::default(), @@ -1240,7 +1241,19 @@ impl Config { } pub fn json_schema() -> serde_json::Value { - FullConfigInput::json_schema() + let mut s = FullConfigInput::json_schema(); + + fn sort_objects_by_field(json: &mut serde_json::Value) { + if let serde_json::Value::Object(object) = json { + let old = std::mem::take(object); + old.into_iter().sorted_by(|(k, _), (k2, _)| k.cmp(k2)).for_each(|(k, mut v)| { + sort_objects_by_field(&mut v); + object.insert(k, v); + }); + } + } + sort_objects_by_field(&mut s); + s } pub fn root_path(&self) -> &AbsPathBuf { @@ -1251,7 +1264,7 @@ impl Config { &self.root_ratoml_path } - pub fn caps(&self) -> &lsp_types::ClientCapabilities { + pub fn caps(&self) -> &ClientCapabilities { &self.caps } } @@ -1265,7 +1278,9 @@ impl Config { prefer_no_std: self.imports_preferNoStd(source_root).to_owned(), assist_emit_must_use: self.assist_emitMustUse(source_root).to_owned(), prefer_prelude: self.imports_preferPrelude(source_root).to_owned(), + prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(), term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64, + term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), } } @@ -1273,7 +1288,7 @@ impl Config { CompletionConfig { enable_postfix_completions: self.completion_postfix_enable().to_owned(), enable_imports_on_the_fly: self.completion_autoimport_enable().to_owned() - && completion_item_edit_resolve(&self.caps), + && self.caps.completion_item_edit_resolve(), enable_self_on_the_fly: self.completion_autoself_enable().to_owned(), enable_private_editable: self.completion_privateEditable_enable().to_owned(), full_function_signatures: self.completion_fullFunctionSignatures_enable().to_owned(), @@ -1282,19 +1297,11 @@ impl Config { CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses), CallableCompletionDef::None => None, }, - snippet_cap: SnippetCap::new(try_or_def!( - self.caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .snippet_support? - )), + snippet_cap: SnippetCap::new(self.completion_snippet()), insert_use: self.insert_use_config(source_root), prefer_no_std: self.imports_preferNoStd(source_root).to_owned(), prefer_prelude: self.imports_preferPrelude(source_root).to_owned(), + prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(), snippets: self.snippets.clone().to_vec(), limit: self.completion_limit().to_owned(), enable_term_search: self.completion_termSearch_enable().to_owned(), @@ -1323,8 +1330,10 @@ impl Config { insert_use: self.insert_use_config(source_root), prefer_no_std: self.imports_preferNoStd(source_root).to_owned(), prefer_prelude: self.imports_preferPrelude(source_root).to_owned(), + prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(), style_lints: self.diagnostics_styleLints_enable().to_owned(), term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64, + term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), } } pub fn expand_proc_attr_macros(&self) -> bool { @@ -1342,7 +1351,7 @@ impl Config { } pub fn hover_actions(&self) -> HoverActionsConfig { - let enable = self.experimental("hoverActions") && self.hover_actions_enable().to_owned(); + let enable = self.caps.hover_actions() && self.hover_actions_enable().to_owned(); HoverActionsConfig { implementations: enable && self.hover_actions_implementations_enable().to_owned(), references: enable && self.hover_actions_references_enable().to_owned(), @@ -1368,17 +1377,7 @@ impl Config { }), documentation: self.hover_documentation_enable().to_owned(), format: { - let is_markdown = try_or_def!(self - .caps - .text_document - .as_ref()? - .hover - .as_ref()? - .content_format - .as_ref()? - .as_slice()) - .contains(&MarkupKind::Markdown); - if is_markdown { + if self.caps.hover_markdown_support() { HoverDocFormat::Markdown } else { HoverDocFormat::PlainText @@ -1392,22 +1391,17 @@ impl Config { } pub fn inlay_hints(&self) -> InlayHintsConfig { - let client_capability_fields = self - .caps - .text_document - .as_ref() - .and_then(|text| text.inlay_hint.as_ref()) - .and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref()) - .map(|inlay_resolve| inlay_resolve.properties.iter()) - .into_iter() - .flatten() - .cloned() - .collect::<FxHashSet<_>>(); + let client_capability_fields = self.inlay_hint_resolve_support_properties(); InlayHintsConfig { render_colons: self.inlayHints_renderColons().to_owned(), type_hints: self.inlayHints_typeHints_enable().to_owned(), parameter_hints: self.inlayHints_parameterHints_enable().to_owned(), + generic_parameter_hints: GenericParameterHints { + type_hints: self.inlayHints_genericParameterHints_type_enable().to_owned(), + lifetime_hints: self.inlayHints_genericParameterHints_lifetime_enable().to_owned(), + const_hints: self.inlayHints_genericParameterHints_const_enable().to_owned(), + }, chaining_hints: self.inlayHints_chainingHints_enable().to_owned(), discriminant_hints: match self.inlayHints_discriminantHints_enable() { DiscriminantHintsDef::Always => ide::DiscriminantHints::Always, @@ -1573,165 +1567,10 @@ impl Config { } } - pub fn did_save_text_document_dynamic_registration(&self) -> bool { - let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?); - caps.did_save == Some(true) && caps.dynamic_registration == Some(true) - } - - pub fn did_change_watched_files_dynamic_registration(&self) -> bool { - try_or_def!( - self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration? - ) - } - - pub fn did_change_watched_files_relative_pattern_support(&self) -> bool { - try_or_def!( - self.caps - .workspace - .as_ref()? - .did_change_watched_files - .as_ref()? - .relative_pattern_support? - ) - } - pub fn prefill_caches(&self) -> bool { self.cachePriming_enable().to_owned() } - pub fn location_link(&self) -> bool { - try_or_def!(self.caps.text_document.as_ref()?.definition?.link_support?) - } - - pub fn line_folding_only(&self) -> bool { - try_or_def!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?) - } - - pub fn hierarchical_symbols(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .document_symbol - .as_ref()? - .hierarchical_document_symbol_support? - ) - } - - pub fn code_action_literals(&self) -> bool { - try_!(self - .caps - .text_document - .as_ref()? - .code_action - .as_ref()? - .code_action_literal_support - .as_ref()?) - .is_some() - } - - pub fn work_done_progress(&self) -> bool { - try_or_def!(self.caps.window.as_ref()?.work_done_progress?) - } - - pub fn will_rename(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?) - } - - pub fn change_annotation_support(&self) -> bool { - try_!(self - .caps - .workspace - .as_ref()? - .workspace_edit - .as_ref()? - .change_annotation_support - .as_ref()?) - .is_some() - } - - pub fn code_action_resolve(&self) -> bool { - try_or_def!(self - .caps - .text_document - .as_ref()? - .code_action - .as_ref()? - .resolve_support - .as_ref()? - .properties - .as_slice()) - .iter() - .any(|it| it == "edit") - } - - pub fn signature_help_label_offsets(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .signature_help - .as_ref()? - .signature_information - .as_ref()? - .parameter_information - .as_ref()? - .label_offset_support? - ) - } - - pub fn completion_label_details_support(&self) -> bool { - try_!(self - .caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .label_details_support - .as_ref()?) - .is_some() - } - - pub fn semantics_tokens_augments_syntax_tokens(&self) -> bool { - try_!(self.caps.text_document.as_ref()?.semantic_tokens.as_ref()?.augments_syntax_tokens?) - .unwrap_or(false) - } - - pub fn position_encoding(&self) -> PositionEncoding { - negotiated_encoding(&self.caps) - } - - fn experimental(&self, index: &'static str) -> bool { - try_or_def!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?) - } - - pub fn code_action_group(&self) -> bool { - self.experimental("codeActionGroup") - } - - pub fn local_docs(&self) -> bool { - self.experimental("localDocs") - } - - pub fn open_server_logs(&self) -> bool { - self.experimental("openServerLogs") - } - - pub fn server_status_notification(&self) -> bool { - self.experimental("serverStatusNotification") - } - - /// Whether the client supports colored output for full diagnostics from `checkOnSave`. - pub fn color_diagnostic_output(&self) -> bool { - self.experimental("colorDiagnosticOutput") - } - - pub fn test_explorer(&self) -> bool { - self.experimental("testExplorer") - } - pub fn publish_diagnostics(&self) -> bool { self.diagnostics_enable().to_owned() } @@ -2009,7 +1848,7 @@ impl Config { pub fn snippet_cap(&self) -> Option<SnippetCap> { // FIXME: Also detect the proposed lsp version at caps.workspace.workspaceEdit.snippetEditSupport // once lsp-types has it. - SnippetCap::new(self.experimental("snippetTextEdit")) + SnippetCap::new(self.snippet_text_edit()) } pub fn call_info(&self) -> CallInfoConfig { @@ -2049,36 +1888,8 @@ impl Config { } } - pub fn semantic_tokens_refresh(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?) - } - - pub fn code_lens_refresh(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?) - } - - pub fn inlay_hints_refresh(&self) -> bool { - try_or_def!(self.caps.workspace.as_ref()?.inlay_hint.as_ref()?.refresh_support?) - } - - pub fn insert_replace_support(&self) -> bool { - try_or_def!( - self.caps - .text_document - .as_ref()? - .completion - .as_ref()? - .completion_item - .as_ref()? - .insert_replace_support? - ) - } - pub fn client_commands(&self) -> ClientCommandsConfig { - let commands = - try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null); - let commands: Option<lsp_ext::ClientCommandOptions> = - serde_json::from_value(commands.clone()).ok(); + let commands = self.commands(); let force = commands.is_none() && *self.lens_forceCustomCommands(); let commands = commands.map(|it| it.commands).unwrap_or_default(); @@ -2637,9 +2448,8 @@ macro_rules! _config_data { /// All fields `Option<T>`, `None` representing fields not set in a particular JSON/TOML blob. #[allow(non_snake_case)] - #[derive(Clone, Serialize, Default)] + #[derive(Clone, Default)] struct $input { $( - #[serde(skip_serializing_if = "Option::is_none")] $field: Option<$ty>, )* } @@ -2722,7 +2532,7 @@ struct DefaultConfigData { /// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to /// all fields being None. -#[derive(Debug, Clone, Default, Serialize)] +#[derive(Debug, Clone, Default)] struct FullConfigInput { global: GlobalConfigInput, local: LocalConfigInput, @@ -2767,7 +2577,7 @@ impl FullConfigInput { /// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to /// all fields being None. -#[derive(Debug, Clone, Default, Serialize)] +#[derive(Debug, Clone, Default)] struct GlobalLocalConfigInput { global: GlobalConfigInput, local: LocalConfigInput, @@ -2929,7 +2739,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "FxHashMap<Box<str>, Box<[Box<str>]>>" => set! { "type": "object", }, - "IndexMap<String, SnippetDef>" => set! { + "FxHashMap<String, SnippetDef>" => set! { "type": "object", }, "FxHashMap<String, String>" => set! { @@ -3344,6 +3154,7 @@ mod tests { #[test] fn generate_package_json_config() { let s = Config::json_schema(); + let schema = format!("{s:#}"); let mut schema = schema .trim_start_matches('[') @@ -3364,7 +3175,7 @@ mod tests { for idx in url_offsets { let link = &schema[idx..]; // matching on whitespace to ignore normal links - if let Some(link_end) = link.find(|c| c == ' ' || c == '[') { + if let Some(link_end) = link.find([' ', '[']) { if link.chars().nth(link_end) == Some('[') { if let Some(link_text_end) = link.find(']') { let link_text = link[link_end..(link_text_end + 1)].to_string(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs index 4832e8cab43..defa464f2ba 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -66,7 +66,7 @@ fn location( let uri = url_from_abs_path(&file_name); let range = { - let position_encoding = snap.config.position_encoding(); + let position_encoding = snap.config.negotiated_encoding(); lsp_types::Range::new( position( &position_encoding, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 717d8a632c3..de4c9586dfd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -529,7 +529,7 @@ impl GlobalStateSnapshot { pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> { let endings = self.vfs.read().1[&file_id]; let index = self.analysis.file_line_index(file_id)?; - let res = LineIndex { index, endings, encoding: self.config.position_encoding() }; + let res = LineIndex { index, endings, encoding: self.config.caps().negotiated_encoding() }; Ok(res) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index 2dbc297ea6c..095d7c941c1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -100,7 +100,7 @@ pub(crate) fn handle_did_change_text_document( *version = params.text_document.version; let new_contents = apply_document_changes( - state.config.position_encoding(), + state.config.negotiated_encoding(), std::str::from_utf8(data).unwrap(), params.content_changes, ) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 8e39b15da3d..e19f7a4898b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -847,7 +847,7 @@ pub(crate) fn handle_runnables( if expect_test { if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args { runnable.label = format!("{} + expect", runnable.label); - r.expect_test = Some(true); + r.environment.insert("UPDATE_EXPECT".to_owned(), "1".to_owned()); } } res.push(runnable); @@ -874,6 +874,7 @@ pub(crate) fn handle_runnables( if all_targets { cargo_args.push("--all-targets".to_owned()); } + cargo_args.extend(config.cargo_extra_args.iter().cloned()); res.push(lsp_ext::Runnable { label: format!( "cargo {cmd} -p {}{all_targets}", @@ -884,12 +885,11 @@ pub(crate) fn handle_runnables( kind: lsp_ext::RunnableKind::Cargo, args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { workspace_root: Some(spec.workspace_root.clone().into()), - cwd: Some(cwd.into()), + cwd: cwd.into(), override_cargo: config.override_cargo.clone(), cargo_args, - cargo_extra_args: config.cargo_extra_args.clone(), executable_args: Vec::new(), - expect_test: None, + environment: Default::default(), }), }) } @@ -897,20 +897,23 @@ pub(crate) fn handle_runnables( Some(TargetSpec::ProjectJson(_)) => {} None => { if !snap.config.linked_or_discovered_projects().is_empty() { - res.push(lsp_ext::Runnable { - label: "cargo check --workspace".to_owned(), - location: None, - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { - workspace_root: None, - cwd: None, - override_cargo: config.override_cargo, - cargo_args: vec!["check".to_owned(), "--workspace".to_owned()], - cargo_extra_args: config.cargo_extra_args, - executable_args: Vec::new(), - expect_test: None, - }), - }); + if let Some(path) = snap.file_id_to_file_path(file_id).parent() { + let mut cargo_args = vec!["check".to_owned(), "--workspace".to_owned()]; + cargo_args.extend(config.cargo_extra_args.iter().cloned()); + res.push(lsp_ext::Runnable { + label: "cargo check --workspace".to_owned(), + location: None, + kind: lsp_ext::RunnableKind::Cargo, + args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { + workspace_root: None, + cwd: path.as_path().unwrap().to_path_buf().into(), + override_cargo: config.override_cargo, + cargo_args, + executable_args: Vec::new(), + environment: Default::default(), + }), + }); + }; } } } @@ -1637,7 +1640,9 @@ pub(crate) fn handle_call_hierarchy_incoming( from_ranges: call_item .ranges .into_iter() - .map(|it| to_proto::range(&line_index, it)) + // This is the range relative to the item + .filter(|it| it.file_id == file_id) + .map(|it| to_proto::range(&line_index, it.range)) .collect(), }); } @@ -1672,7 +1677,9 @@ pub(crate) fn handle_call_hierarchy_outgoing( from_ranges: call_item .ranges .into_iter() - .map(|it| to_proto::range(&line_index, it)) + // This is the range relative to the caller + .filter(|it| it.file_id == fpos.file_id) + .map(|it| to_proto::range(&line_index, it.range)) .collect(), }); } @@ -2291,19 +2298,8 @@ fn to_url(path: VfsPath) -> Option<Url> { } fn resource_ops_supported(config: &Config, kind: ResourceOperationKind) -> anyhow::Result<()> { - #[rustfmt::skip] - let resops = (|| { - config - .caps() - .workspace - .as_ref()? - .workspace_edit - .as_ref()? - .resource_operations - .as_ref() - })(); - - if !matches!(resops, Some(resops) if resops.contains(&kind)) { + if !matches!(config.workspace_edit_resource_operations(), Some(resops) if resops.contains(&kind)) + { return Err(LspError::new( ErrorCode::RequestFailed as i32, format!( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 1e2cd4339b3..ff8eb6c8612 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -152,6 +152,7 @@ fn integrated_completion_benchmark() { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, snippets: Vec::new(), limit: None, }; @@ -197,6 +198,7 @@ fn integrated_completion_benchmark() { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, snippets: Vec::new(), limit: None, }; @@ -240,6 +242,7 @@ fn integrated_completion_benchmark() { }, prefer_no_std: false, prefer_prelude: true, + prefer_absolute: false, snippets: Vec::new(), limit: None, }; @@ -299,7 +302,9 @@ fn integrated_diagnostics_benchmark() { }, prefer_no_std: false, prefer_prelude: false, + prefer_absolute: false, term_search_fuel: 400, + term_search_borrowck: true, }; host.analysis() .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index a398e98f093..174979edede 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -9,11 +9,9 @@ //! The `cli` submodule implements some batch-processing analysis, primarily as //! a debugging aid. -#![warn(rust_2018_idioms, unused_lifetimes)] - pub mod cli; -mod caps; +mod capabilities; mod diagnostics; mod diff; mod dispatch; @@ -49,7 +47,8 @@ mod integrated_benchmarks; use serde::de::DeserializeOwned; pub use crate::{ - caps::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph, version::version, + capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph, + version::version, }; pub fn from_json<T: DeserializeOwned>( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index b82ba441904..9a852067f2e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -4,19 +4,16 @@ use std::ops; -use ide_db::line_index::WideEncoding; use lsp_types::request::Request; +use lsp_types::Url; use lsp_types::{ notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams, PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams, }; -use lsp_types::{PositionEncodingKind, Url}; use paths::Utf8PathBuf; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; -use crate::line_index::PositionEncoding; - pub enum InternalTestingFetchConfig {} impl Request for InternalTestingFetchConfig { @@ -460,28 +457,27 @@ pub enum RunnableKind { #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct CargoRunnableArgs { - // command to be executed instead of cargo + #[serde(skip_serializing_if = "FxHashMap::is_empty")] + pub environment: FxHashMap<String, String>, + pub cwd: Utf8PathBuf, + /// Command to be executed instead of cargo pub override_cargo: Option<String>, #[serde(skip_serializing_if = "Option::is_none")] pub workspace_root: Option<Utf8PathBuf>, - #[serde(skip_serializing_if = "Option::is_none")] - pub cwd: Option<Utf8PathBuf>, // command, --package and --lib stuff pub cargo_args: Vec<String>, - // user-specified additional cargo args, like `--release`. - pub cargo_extra_args: Vec<String>, // stuff after -- pub executable_args: Vec<String>, - #[serde(skip_serializing_if = "Option::is_none")] - pub expect_test: Option<bool>, } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct ShellRunnableArgs { + #[serde(skip_serializing_if = "FxHashMap::is_empty")] + pub environment: FxHashMap<String, String>, + pub cwd: Utf8PathBuf, pub program: String, pub args: Vec<String>, - pub cwd: Utf8PathBuf, } pub enum RelatedTests {} @@ -738,24 +734,6 @@ pub enum CodeLensResolveDataKind { References(lsp_types::TextDocumentPositionParams), } -pub fn negotiated_encoding(caps: &lsp_types::ClientCapabilities) -> PositionEncoding { - let client_encodings = match &caps.general { - Some(general) => general.position_encodings.as_deref().unwrap_or_default(), - None => &[], - }; - - for enc in client_encodings { - if enc == &PositionEncodingKind::UTF8 { - return PositionEncoding::Utf8; - } else if enc == &PositionEncodingKind::UTF32 { - return PositionEncoding::Wide(WideEncoding::Utf32); - } - // NB: intentionally prefer just about anything else to utf-16. - } - - PositionEncoding::Wide(WideEncoding::Utf16) -} - pub enum MoveItem {} impl Request for MoveItem { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index db5f666a5b9..de394d3d118 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -501,7 +501,9 @@ pub(crate) fn inlay_hint( padding_left: Some(inlay_hint.pad_left), padding_right: Some(inlay_hint.pad_right), kind: match inlay_hint.kind { - InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER), + InlayKind::Parameter | InlayKind::GenericParameter => { + Some(lsp_types::InlayHintKind::PARAMETER) + } InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE), _ => None, }, @@ -1390,10 +1392,9 @@ pub(crate) fn runnable( workspace_root: Some(workspace_root.into()), override_cargo: config.override_cargo, cargo_args, - cwd: Some(cwd.into()), - cargo_extra_args: config.cargo_extra_args, + cwd: cwd.into(), executable_args, - expect_test: None, + environment: Default::default(), }), })) } @@ -1407,6 +1408,7 @@ pub(crate) fn runnable( program: json_shell_runnable_args.program, args: json_shell_runnable_args.args, cwd: json_shell_runnable_args.cwd, + environment: Default::default(), }; Ok(Some(lsp_ext::Runnable { label, @@ -1419,6 +1421,9 @@ pub(crate) fn runnable( } } None => { + let Some(path) = snap.file_id_to_file_path(runnable.nav.file_id).parent() else { + return Ok(None); + }; let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(snap, None, &runnable.kind, &runnable.cfg); @@ -1433,10 +1438,9 @@ pub(crate) fn runnable( workspace_root: None, override_cargo: config.override_cargo, cargo_args, - cwd: None, - cargo_extra_args: config.cargo_extra_args, + cwd: path.as_path().unwrap().to_path_buf().into(), executable_args, - expect_test: None, + environment: Default::default(), }), })) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index bd0f733ef39..1039daf850c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -184,14 +184,28 @@ impl GlobalState { message.push_str(err); message.push_str("\n\n"); }; - if let Some(Err(err)) = proc_macro_client { - status.health |= lsp_ext::Health::Warning; - format_to!( - message, - "Failed spawning proc-macro server for workspace `{}`: {err}", - ws.manifest_or_root() - ); - message.push_str("\n\n"); + match proc_macro_client { + Some(Err(err)) => { + status.health |= lsp_ext::Health::Warning; + format_to!( + message, + "Failed spawning proc-macro server for workspace `{}`: {err}", + ws.manifest_or_root() + ); + message.push_str("\n\n"); + } + Some(Ok(client)) => { + if let Some(err) = client.exited() { + status.health |= lsp_ext::Health::Warning; + format_to!( + message, + "proc-macro server for workspace `{}` exited: {err}", + ws.manifest_or_root() + ); + message.push_str("\n\n"); + } + } + _ => (), } } } @@ -529,7 +543,7 @@ impl GlobalState { None => ws.find_sysroot_proc_macro_srv()?, }; - let env = match &ws.kind { + let env: FxHashMap<_, _> = match &ws.kind { ProjectWorkspaceKind::Cargo { cargo_config_extra_env, .. } | ProjectWorkspaceKind::DetachedFile { cargo: Some(_), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs index 6145f7e05f9..863ff064399 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs @@ -110,7 +110,8 @@ impl CargoTargetSpec { kind: &RunnableKind, cfg: &Option<CfgExpr>, ) -> (Vec<String>, Vec<String>) { - let extra_test_binary_args = snap.config.runnables().extra_test_binary_args; + let config = snap.config.runnables(); + let extra_test_binary_args = config.extra_test_binary_args; let mut cargo_args = Vec::new(); let mut executable_args = Vec::new(); @@ -196,6 +197,7 @@ impl CargoTargetSpec { } } } + cargo_args.extend(config.cargo_extra_args.iter().cloned()); (cargo_args, executable_args) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index f886df60e68..56f416a0b6e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -8,15 +8,11 @@ //! specific JSON shapes here -- there's little value in such tests, as we can't //! be sure without a real client anyway. -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::disallowed_types)] mod ratoml; -#[cfg(not(feature = "in-rust-tree"))] -mod sourcegen; mod support; mod testdir; -mod tidy; use std::{collections::HashMap, path::PathBuf, time::Instant}; @@ -259,7 +255,6 @@ fn main() {} "args": { "cargoArgs": ["test", "--package", "foo", "--test", "spam"], "executableArgs": ["test_eggs", "--exact", "--show-output"], - "cargoExtraArgs": [], "overrideCargo": null, "cwd": server.path().join("foo"), "workspaceRoot": server.path().join("foo") @@ -290,7 +285,6 @@ fn main() {} "--test", "spam" ], - "cargoExtraArgs": [], "executableArgs": [ "", "--show-output" @@ -326,7 +320,6 @@ fn main() {} "args": { "cargoArgs": ["check", "--package", "foo", "--all-targets"], "executableArgs": [], - "cargoExtraArgs": [], "overrideCargo": null, "cwd": server.path().join("foo"), "workspaceRoot": server.path().join("foo") @@ -338,7 +331,6 @@ fn main() {} "args": { "cargoArgs": ["test", "--package", "foo", "--all-targets"], "executableArgs": [], - "cargoExtraArgs": [], "overrideCargo": null, "cwd": server.path().join("foo"), "workspaceRoot": server.path().join("foo") @@ -427,7 +419,6 @@ mod tests { runnable, "--all-targets" ], - "cargoExtraArgs": [], "executableArgs": [] }, }, @@ -490,7 +481,6 @@ fn otherpkg() {} "mainpkg", "--all-targets" ], - "cargoExtraArgs": [], "executableArgs": [] }, }, @@ -516,7 +506,6 @@ fn otherpkg() {} "otherpkg", "--all-targets" ], - "cargoExtraArgs": [], "executableArgs": [] }, }, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index c4383255323..66100971fbf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -388,9 +388,8 @@ impl Server { } fn recv(&self) -> Result<Option<Message>, Timeout> { let msg = recv_timeout(&self.client.receiver)?; - let msg = msg.map(|msg| { + let msg = msg.inspect(|msg| { self.messages.borrow_mut().push(msg.clone()); - msg }); Ok(msg) } diff --git a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml b/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml deleted file mode 100644 index d5ea4c39aa1..00000000000 --- a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "sourcegen" -version = "0.0.0" -description = "TBD" -publish = false - -authors.workspace = true -edition.workspace = true -license.workspace = true -rust-version.workspace = true - -[lib] -doctest = false - -[dependencies] -xshell.workspace = true - -[lints] -workspace = true \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs deleted file mode 100644 index 829b4d5b0ff..00000000000 --- a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! rust-analyzer relies heavily on source code generation. -//! -//! Things like feature documentation or assist tests are implemented by -//! processing rust-analyzer's own source code and generating the appropriate -//! output. See `sourcegen_` tests in various crates. -//! -//! This crate contains utilities to make this kind of source-gen easy. - -#![warn(rust_2018_idioms, unused_lifetimes)] - -use std::{ - fmt, fs, mem, - path::{Path, PathBuf}, -}; - -use xshell::{cmd, Shell}; - -pub fn list_rust_files(dir: &Path) -> Vec<PathBuf> { - let mut res = list_files(dir); - res.retain(|it| { - it.file_name().unwrap_or_default().to_str().unwrap_or_default().ends_with(".rs") - }); - res -} - -pub fn list_files(dir: &Path) -> Vec<PathBuf> { - let mut res = Vec::new(); - let mut work = vec![dir.to_path_buf()]; - while let Some(dir) = work.pop() { - for entry in dir.read_dir().unwrap() { - let entry = entry.unwrap(); - let file_type = entry.file_type().unwrap(); - let path = entry.path(); - let is_hidden = - path.file_name().unwrap_or_default().to_str().unwrap_or_default().starts_with('.'); - if !is_hidden { - if file_type.is_dir() { - work.push(path); - } else if file_type.is_file() { - res.push(path); - } - } - } - } - res -} - -#[derive(Clone)] -pub struct CommentBlock { - pub id: String, - pub line: usize, - pub contents: Vec<String>, - is_doc: bool, -} - -impl CommentBlock { - pub fn extract(tag: &str, text: &str) -> Vec<CommentBlock> { - assert!(tag.starts_with(char::is_uppercase)); - - let tag = format!("{tag}:"); - let mut blocks = CommentBlock::extract_untagged(text); - blocks.retain_mut(|block| { - let first = block.contents.remove(0); - let Some(id) = first.strip_prefix(&tag) else { - return false; - }; - - if block.is_doc { - panic!("Use plain (non-doc) comments with tags like {tag}:\n {first}"); - } - - id.trim().clone_into(&mut block.id); - true - }); - blocks - } - - pub fn extract_untagged(text: &str) -> Vec<CommentBlock> { - let mut res = Vec::new(); - - let lines = text.lines().map(str::trim_start); - - let dummy_block = - CommentBlock { id: String::new(), line: 0, contents: Vec::new(), is_doc: false }; - let mut block = dummy_block.clone(); - for (line_num, line) in lines.enumerate() { - match line.strip_prefix("//") { - Some(mut contents) => { - if let Some('/' | '!') = contents.chars().next() { - contents = &contents[1..]; - block.is_doc = true; - } - if let Some(' ') = contents.chars().next() { - contents = &contents[1..]; - } - block.contents.push(contents.to_owned()); - } - None => { - if !block.contents.is_empty() { - let block = mem::replace(&mut block, dummy_block.clone()); - res.push(block); - } - block.line = line_num + 2; - } - } - } - if !block.contents.is_empty() { - res.push(block); - } - res - } -} - -#[derive(Debug)] -pub struct Location { - pub file: PathBuf, - pub line: usize, -} - -impl fmt::Display for Location { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let path = self.file.strip_prefix(project_root()).unwrap().display().to_string(); - let path = path.replace('\\', "/"); - let name = self.file.file_name().unwrap(); - write!( - f, - "https://github.com/rust-lang/rust-analyzer/blob/master/{}#L{}[{}]", - path, - self.line, - name.to_str().unwrap() - ) - } -} - -fn ensure_rustfmt(sh: &Shell) { - let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default(); - if !version.contains("stable") { - panic!( - "Failed to run rustfmt from toolchain 'stable'. \ - Please run `rustup component add rustfmt --toolchain stable` to install it.", - ); - } -} - -pub fn reformat(text: String) -> String { - let sh = Shell::new().unwrap(); - ensure_rustfmt(&sh); - let rustfmt_toml = project_root().join("rustfmt.toml"); - let mut stdout = cmd!( - sh, - "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true" - ) - .stdin(text) - .read() - .unwrap(); - if !stdout.ends_with('\n') { - stdout.push('\n'); - } - stdout -} - -pub fn add_preamble(generator: &'static str, mut text: String) -> String { - let preamble = format!("//! Generated by `{generator}`, do not edit by hand.\n\n"); - text.insert_str(0, &preamble); - text -} - -/// Checks that the `file` has the specified `contents`. If that is not the -/// case, updates the file and then fails the test. -#[allow(clippy::print_stderr)] -pub fn ensure_file_contents(file: &Path, contents: &str) { - if let Ok(old_contents) = fs::read_to_string(file) { - if normalize_newlines(&old_contents) == normalize_newlines(contents) { - // File is already up to date. - return; - } - } - - let display_path = file.strip_prefix(project_root()).unwrap_or(file); - eprintln!( - "\n\x1b[31;1merror\x1b[0m: {} was not up-to-date, updating\n", - display_path.display() - ); - if std::env::var("CI").is_ok() { - eprintln!(" NOTE: run `cargo test` locally and commit the updated files\n"); - } - if let Some(parent) = file.parent() { - let _ = fs::create_dir_all(parent); - } - fs::write(file, contents).unwrap(); - panic!("some file was not up to date and has been updated, simply re-run the tests"); -} - -fn normalize_newlines(s: &str) -> String { - s.replace("\r\n", "\n") -} - -pub fn project_root() -> PathBuf { - let dir = env!("CARGO_MANIFEST_DIR"); - let res = PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned(); - assert!(res.join("triagebot.toml").exists()); - res -} diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs index 54f10df42a8..76dbd42ff6b 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs @@ -1,7 +1,5 @@ //! Missing batteries for standard libraries. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::io as sio; use std::process::Command; use std::{cmp::Ordering, ops, time::Instant}; diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 1809ca7dea5..b371ec6ebd5 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -33,6 +33,7 @@ text-edit.workspace = true [dev-dependencies] rayon.workspace = true expect-test = "1.4.0" +rustc_apfloat = "0.2.0" test-utils.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast.rs b/src/tools/rust-analyzer/crates/syntax/src/ast.rs index 168ca9f1328..3282bd6eff2 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast.rs @@ -31,8 +31,8 @@ pub use self::{ operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix}, traits::{ - AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericParams, - HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility, + AttrDocCommentIter, DocCommentIter, HasArgList, HasAttrs, HasDocComments, HasGenericArgs, + HasGenericParams, HasLoopBody, HasModuleItem, HasName, HasTypeBounds, HasVisibility, }, }; @@ -149,14 +149,17 @@ pub trait RangeItem { mod support { use super::{AstChildren, AstNode, SyntaxKind, SyntaxNode, SyntaxToken}; + #[inline] pub(super) fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> { parent.children().find_map(N::cast) } + #[inline] pub(super) fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> { AstChildren::new(parent) } + #[inline] pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> { parent.children_with_tokens().filter_map(|it| it.into_token()).find(|it| it.kind() == kind) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 2445e4f1a32..f1286e7aa21 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -6,7 +6,7 @@ use parser::{SyntaxKind, T}; use crate::{ algo::{self, neighbor}, - ast::{self, edit::IndentLevel, make, HasGenericParams}, + ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams}, ted::{self, Position}, AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index 28a9dadacef..b0ee9dfd507 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -6,7 +6,8 @@ use crate::{ ast::{ self, operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp}, - support, AstChildren, AstNode, + support, ArgList, AstChildren, AstNode, BlockExpr, ClosureExpr, Const, Expr, Fn, + FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree, }, AstToken, SyntaxKind::*, @@ -435,3 +436,57 @@ impl AstNode for CallableExpr { } } } + +impl MacroDef { + fn tts(&self) -> (Option<ast::TokenTree>, Option<ast::TokenTree>) { + let mut types = support::children(self.syntax()); + let first = types.next(); + let second = types.next(); + (first, second) + } + + pub fn args(&self) -> Option<TokenTree> { + match self.tts() { + (Some(args), Some(_)) => Some(args), + _ => None, + } + } + + pub fn body(&self) -> Option<TokenTree> { + match self.tts() { + (Some(body), None) | (_, Some(body)) => Some(body), + _ => None, + } + } +} + +impl ClosureExpr { + pub fn body(&self) -> Option<Expr> { + support::child(&self.syntax) + } +} +impl Const { + pub fn body(&self) -> Option<Expr> { + support::child(&self.syntax) + } +} +impl Fn { + pub fn body(&self) -> Option<BlockExpr> { + support::child(&self.syntax) + } +} +impl Static { + pub fn body(&self) -> Option<Expr> { + support::child(&self.syntax) + } +} +impl FormatArgsExpr { + pub fn args(&self) -> AstChildren<FormatArgsArg> { + support::children(&self.syntax) + } +} +impl ArgList { + pub fn args(&self) -> AstChildren<Expr> { + support::children(&self.syntax) + } +} diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 98186c5473d..0373e7c5529 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1,4 +1,4 @@ -//! Generated by `sourcegen_ast`, do not edit by hand. +//! Generated by `cargo codegen grammar`, do not edit by hand. #![allow(non_snake_case)] use crate::{ @@ -12,6 +12,7 @@ pub struct Abi { pub(crate) syntax: SyntaxNode, } impl Abi { + #[inline] pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) } } @@ -20,8 +21,9 @@ pub struct ArgList { pub(crate) syntax: SyntaxNode, } impl ArgList { - pub fn args(&self) -> AstChildren<Expr> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -31,10 +33,15 @@ pub struct ArrayExpr { } impl ast::HasAttrs for ArrayExpr {} impl ArrayExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } } @@ -43,10 +50,15 @@ pub struct ArrayType { pub(crate) syntax: SyntaxNode, } impl ArrayType { + #[inline] pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } } @@ -56,11 +68,17 @@ pub struct AsmExpr { } impl ast::HasAttrs for AsmExpr {} impl AsmExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn asm_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![asm]) } + #[inline] pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) } } @@ -70,8 +88,11 @@ pub struct AssocItemList { } impl ast::HasAttrs for AssocItemList {} impl AssocItemList { + #[inline] pub fn assoc_items(&self) -> AstChildren<AssocItem> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -79,14 +100,20 @@ impl AssocItemList { pub struct AssocTypeArg { pub(crate) syntax: SyntaxNode, } +impl ast::HasGenericArgs for AssocTypeArg {} impl ast::HasTypeBounds for AssocTypeArg {} impl AssocTypeArg { + #[inline] pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) } - pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } } @@ -95,10 +122,15 @@ pub struct Attr { pub(crate) syntax: SyntaxNode, } impl Attr { + #[inline] pub fn meta(&self) -> Option<Meta> { support::child(&self.syntax) } + #[inline] pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } + #[inline] pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } } @@ -108,8 +140,11 @@ pub struct AwaitExpr { } impl ast::HasAttrs for AwaitExpr {} impl AwaitExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } + #[inline] pub fn await_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![await]) } } @@ -119,7 +154,9 @@ pub struct BecomeExpr { } impl ast::HasAttrs for BecomeExpr {} impl BecomeExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn become_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![become]) } } @@ -136,11 +173,17 @@ pub struct BlockExpr { } impl ast::HasAttrs for BlockExpr {} impl BlockExpr { + #[inline] pub fn label(&self) -> Option<Label> { support::child(&self.syntax) } + #[inline] pub fn stmt_list(&self) -> Option<StmtList> { support::child(&self.syntax) } + #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn try_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![try]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -149,7 +192,9 @@ pub struct BoxPat { pub(crate) syntax: SyntaxNode, } impl BoxPat { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn box_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![box]) } } @@ -159,8 +204,11 @@ pub struct BreakExpr { } impl ast::HasAttrs for BreakExpr {} impl BreakExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn break_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![break]) } } @@ -171,6 +219,7 @@ pub struct CallExpr { impl ast::HasArgList for CallExpr {} impl ast::HasAttrs for CallExpr {} impl CallExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } } @@ -180,8 +229,11 @@ pub struct CastExpr { } impl ast::HasAttrs for CastExpr {} impl CastExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } } @@ -191,14 +243,21 @@ pub struct ClosureExpr { } impl ast::HasAttrs for ClosureExpr {} impl ClosureExpr { - pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) } + #[inline] pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } + #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } + #[inline] pub fn move_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![move]) } + #[inline] pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) } } @@ -211,13 +270,19 @@ impl ast::HasDocComments for Const {} impl ast::HasName for Const {} impl ast::HasVisibility for Const {} impl Const { - pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } } @@ -226,6 +291,7 @@ pub struct ConstArg { pub(crate) syntax: SyntaxNode, } impl ConstArg { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } } @@ -234,7 +300,9 @@ pub struct ConstBlockPat { pub(crate) syntax: SyntaxNode, } impl ConstBlockPat { + #[inline] pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } } @@ -245,10 +313,15 @@ pub struct ConstParam { impl ast::HasAttrs for ConstParam {} impl ast::HasName for ConstParam {} impl ConstParam { + #[inline] pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } } @@ -258,7 +331,9 @@ pub struct ContinueExpr { } impl ast::HasAttrs for ContinueExpr {} impl ContinueExpr { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn continue_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![continue]) } @@ -269,7 +344,9 @@ pub struct DynTraitType { pub(crate) syntax: SyntaxNode, } impl DynTraitType { + #[inline] pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) } + #[inline] pub fn dyn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![dyn]) } } @@ -283,7 +360,9 @@ impl ast::HasGenericParams for Enum {} impl ast::HasName for Enum {} impl ast::HasVisibility for Enum {} impl Enum { + #[inline] pub fn variant_list(&self) -> Option<VariantList> { support::child(&self.syntax) } + #[inline] pub fn enum_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![enum]) } } @@ -292,7 +371,9 @@ pub struct ExprStmt { pub(crate) syntax: SyntaxNode, } impl ExprStmt { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } } @@ -303,8 +384,11 @@ pub struct ExternBlock { impl ast::HasAttrs for ExternBlock {} impl ast::HasDocComments for ExternBlock {} impl ExternBlock { + #[inline] pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) } + #[inline] pub fn extern_item_list(&self) -> Option<ExternItemList> { support::child(&self.syntax) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -316,10 +400,15 @@ impl ast::HasAttrs for ExternCrate {} impl ast::HasDocComments for ExternCrate {} impl ast::HasVisibility for ExternCrate {} impl ExternCrate { + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } + #[inline] pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) } } @@ -329,8 +418,11 @@ pub struct ExternItemList { } impl ast::HasAttrs for ExternItemList {} impl ExternItemList { + #[inline] pub fn extern_items(&self) -> AstChildren<ExternItem> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -340,8 +432,11 @@ pub struct FieldExpr { } impl ast::HasAttrs for FieldExpr {} impl FieldExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } } @@ -355,15 +450,23 @@ impl ast::HasGenericParams for Fn {} impl ast::HasName for Fn {} impl ast::HasVisibility for Fn {} impl Fn { + #[inline] pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) } - pub fn body(&self) -> Option<BlockExpr> { support::child(&self.syntax) } + #[inline] pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } + #[inline] pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -372,12 +475,19 @@ pub struct FnPtrType { pub(crate) syntax: SyntaxNode, } impl FnPtrType { + #[inline] pub fn abi(&self) -> Option<Abi> { support::child(&self.syntax) } + #[inline] pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } + #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn fn_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![fn]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -387,8 +497,11 @@ pub struct ForExpr { } impl ast::HasAttrs for ForExpr {} impl ForExpr { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } + #[inline] pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) } } @@ -397,8 +510,11 @@ pub struct ForType { pub(crate) syntax: SyntaxNode, } impl ForType { + #[inline] pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } } @@ -408,7 +524,9 @@ pub struct FormatArgsArg { } impl ast::HasName for FormatArgsArg {} impl FormatArgsArg { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } } @@ -418,13 +536,19 @@ pub struct FormatArgsExpr { } impl ast::HasAttrs for FormatArgsExpr {} impl FormatArgsExpr { - pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) } + #[inline] pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) } + #[inline] pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) } + #[inline] pub fn format_args_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![format_args]) } @@ -435,9 +559,13 @@ pub struct GenericArgList { pub(crate) syntax: SyntaxNode, } impl GenericArgList { + #[inline] pub fn generic_args(&self) -> AstChildren<GenericArg> { support::children(&self.syntax) } + #[inline] pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } + #[inline] pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } + #[inline] pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } } @@ -446,8 +574,11 @@ pub struct GenericParamList { pub(crate) syntax: SyntaxNode, } impl GenericParamList { + #[inline] pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) } + #[inline] pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } + #[inline] pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } } @@ -458,9 +589,13 @@ pub struct IdentPat { impl ast::HasAttrs for IdentPat {} impl ast::HasName for IdentPat {} impl IdentPat { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn at_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![@]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } + #[inline] pub fn ref_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ref]) } } @@ -470,7 +605,9 @@ pub struct IfExpr { } impl ast::HasAttrs for IfExpr {} impl IfExpr { + #[inline] pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) } + #[inline] pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) } } @@ -483,12 +620,19 @@ impl ast::HasDocComments for Impl {} impl ast::HasGenericParams for Impl {} impl ast::HasVisibility for Impl {} impl Impl { + #[inline] pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) } + #[inline] pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } + #[inline] pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } + #[inline] pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -497,7 +641,9 @@ pub struct ImplTraitType { pub(crate) syntax: SyntaxNode, } impl ImplTraitType { + #[inline] pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) } + #[inline] pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) } } @@ -507,7 +653,9 @@ pub struct IndexExpr { } impl ast::HasAttrs for IndexExpr {} impl IndexExpr { + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } } @@ -516,6 +664,7 @@ pub struct InferType { pub(crate) syntax: SyntaxNode, } impl InferType { + #[inline] pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } } @@ -526,7 +675,9 @@ pub struct ItemList { impl ast::HasAttrs for ItemList {} impl ast::HasModuleItem for ItemList {} impl ItemList { + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -535,7 +686,9 @@ pub struct Label { pub(crate) syntax: SyntaxNode, } impl Label { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } } @@ -544,7 +697,9 @@ pub struct LetElse { pub(crate) syntax: SyntaxNode, } impl LetElse { + #[inline] pub fn block_expr(&self) -> Option<BlockExpr> { support::child(&self.syntax) } + #[inline] pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) } } @@ -554,9 +709,13 @@ pub struct LetExpr { } impl ast::HasAttrs for LetExpr {} impl LetExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) } } @@ -566,13 +725,21 @@ pub struct LetStmt { } impl ast::HasAttrs for LetStmt {} impl LetStmt { + #[inline] pub fn initializer(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn let_else(&self) -> Option<LetElse> { support::child(&self.syntax) } + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) } } @@ -581,6 +748,7 @@ pub struct Lifetime { pub(crate) syntax: SyntaxNode, } impl Lifetime { + #[inline] pub fn lifetime_ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![lifetime_ident]) } @@ -591,6 +759,7 @@ pub struct LifetimeArg { pub(crate) syntax: SyntaxNode, } impl LifetimeArg { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } } @@ -601,6 +770,7 @@ pub struct LifetimeParam { impl ast::HasAttrs for LifetimeParam {} impl ast::HasTypeBounds for LifetimeParam {} impl LifetimeParam { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } } @@ -616,7 +786,9 @@ pub struct LiteralPat { pub(crate) syntax: SyntaxNode, } impl LiteralPat { + #[inline] pub fn literal(&self) -> Option<Literal> { support::child(&self.syntax) } + #[inline] pub fn minus_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![-]) } } @@ -627,6 +799,7 @@ pub struct LoopExpr { impl ast::HasAttrs for LoopExpr {} impl ast::HasLoopBody for LoopExpr {} impl LoopExpr { + #[inline] pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) } } @@ -637,9 +810,13 @@ pub struct MacroCall { impl ast::HasAttrs for MacroCall {} impl ast::HasDocComments for MacroCall {} impl MacroCall { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } + #[inline] pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } } @@ -652,8 +829,7 @@ impl ast::HasDocComments for MacroDef {} impl ast::HasName for MacroDef {} impl ast::HasVisibility for MacroDef {} impl MacroDef { - pub fn args(&self) -> Option<TokenTree> { support::child(&self.syntax) } - pub fn body(&self) -> Option<TokenTree> { support::child(&self.syntax) } + #[inline] pub fn macro_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro]) } } @@ -662,12 +838,19 @@ pub struct MacroEagerInput { pub(crate) syntax: SyntaxNode, } impl MacroEagerInput { + #[inline] pub fn exprs(&self) -> AstChildren<Expr> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -676,6 +859,7 @@ pub struct MacroExpr { pub(crate) syntax: SyntaxNode, } impl MacroExpr { + #[inline] pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) } } @@ -691,6 +875,7 @@ pub struct MacroPat { pub(crate) syntax: SyntaxNode, } impl MacroPat { + #[inline] pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) } } @@ -703,8 +888,11 @@ impl ast::HasDocComments for MacroRules {} impl ast::HasName for MacroRules {} impl ast::HasVisibility for MacroRules {} impl MacroRules { + #[inline] pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } + #[inline] pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } + #[inline] pub fn macro_rules_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![macro_rules]) } @@ -715,7 +903,9 @@ pub struct MacroStmts { pub(crate) syntax: SyntaxNode, } impl MacroStmts { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } } @@ -724,6 +914,7 @@ pub struct MacroType { pub(crate) syntax: SyntaxNode, } impl MacroType { + #[inline] pub fn macro_call(&self) -> Option<MacroCall> { support::child(&self.syntax) } } @@ -733,10 +924,15 @@ pub struct MatchArm { } impl ast::HasAttrs for MatchArm {} impl MatchArm { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn guard(&self) -> Option<MatchGuard> { support::child(&self.syntax) } + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) } + #[inline] pub fn fat_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=>]) } } @@ -746,8 +942,11 @@ pub struct MatchArmList { } impl ast::HasAttrs for MatchArmList {} impl MatchArmList { + #[inline] pub fn arms(&self) -> AstChildren<MatchArm> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -757,8 +956,11 @@ pub struct MatchExpr { } impl ast::HasAttrs for MatchExpr {} impl MatchExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) } + #[inline] pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) } } @@ -767,6 +969,7 @@ pub struct MatchGuard { pub(crate) syntax: SyntaxNode, } impl MatchGuard { + #[inline] pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) } } @@ -775,12 +978,19 @@ pub struct Meta { pub(crate) syntax: SyntaxNode, } impl Meta { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -790,10 +1000,13 @@ pub struct MethodCallExpr { } impl ast::HasArgList for MethodCallExpr {} impl ast::HasAttrs for MethodCallExpr {} +impl ast::HasGenericArgs for MethodCallExpr {} impl MethodCallExpr { - pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn receiver(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) } } @@ -806,8 +1019,11 @@ impl ast::HasDocComments for Module {} impl ast::HasName for Module {} impl ast::HasVisibility for Module {} impl Module { + #[inline] pub fn item_list(&self) -> Option<ItemList> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) } } @@ -816,7 +1032,9 @@ pub struct Name { pub(crate) syntax: SyntaxNode, } impl Name { + #[inline] pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) } + #[inline] pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) } } @@ -825,10 +1043,15 @@ pub struct NameRef { pub(crate) syntax: SyntaxNode, } impl NameRef { + #[inline] pub fn Self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![Self]) } + #[inline] pub fn crate_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![crate]) } + #[inline] pub fn ident_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![ident]) } + #[inline] pub fn self_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![self]) } + #[inline] pub fn super_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![super]) } } @@ -837,6 +1060,7 @@ pub struct NeverType { pub(crate) syntax: SyntaxNode, } impl NeverType { + #[inline] pub fn excl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![!]) } } @@ -846,13 +1070,21 @@ pub struct OffsetOfExpr { } impl ast::HasAttrs for OffsetOfExpr {} impl OffsetOfExpr { + #[inline] pub fn fields(&self) -> AstChildren<NameRef> { support::children(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn pound_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![#]) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) } + #[inline] pub fn builtin_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![builtin]) } + #[inline] pub fn offset_of_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![offset_of]) } @@ -863,6 +1095,7 @@ pub struct OrPat { pub(crate) syntax: SyntaxNode, } impl OrPat { + #[inline] pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) } } @@ -872,9 +1105,13 @@ pub struct Param { } impl ast::HasAttrs for Param {} impl Param { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn dotdotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![...]) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } } @@ -883,11 +1120,17 @@ pub struct ParamList { pub(crate) syntax: SyntaxNode, } impl ParamList { + #[inline] pub fn params(&self) -> AstChildren<Param> { support::children(&self.syntax) } + #[inline] pub fn self_param(&self) -> Option<SelfParam> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) } + #[inline] pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) } } @@ -897,8 +1140,11 @@ pub struct ParenExpr { } impl ast::HasAttrs for ParenExpr {} impl ParenExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -907,8 +1153,11 @@ pub struct ParenPat { pub(crate) syntax: SyntaxNode, } impl ParenPat { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -917,8 +1166,11 @@ pub struct ParenType { pub(crate) syntax: SyntaxNode, } impl ParenType { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -927,8 +1179,11 @@ pub struct Path { pub(crate) syntax: SyntaxNode, } impl Path { + #[inline] pub fn qualifier(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn segment(&self) -> Option<PathSegment> { support::child(&self.syntax) } + #[inline] pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } } @@ -938,6 +1193,7 @@ pub struct PathExpr { } impl ast::HasAttrs for PathExpr {} impl PathExpr { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } } @@ -946,6 +1202,7 @@ pub struct PathPat { pub(crate) syntax: SyntaxNode, } impl PathPat { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } } @@ -953,16 +1210,25 @@ impl PathPat { pub struct PathSegment { pub(crate) syntax: SyntaxNode, } +impl ast::HasGenericArgs for PathSegment {} impl PathSegment { - pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) } + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + #[inline] pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } + #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } + #[inline] pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } + #[inline] pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } + #[inline] pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } } @@ -971,6 +1237,7 @@ pub struct PathType { pub(crate) syntax: SyntaxNode, } impl PathType { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } } @@ -980,6 +1247,7 @@ pub struct PrefixExpr { } impl ast::HasAttrs for PrefixExpr {} impl PrefixExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } } @@ -988,9 +1256,13 @@ pub struct PtrType { pub(crate) syntax: SyntaxNode, } impl PtrType { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } } @@ -1012,7 +1284,9 @@ pub struct RecordExpr { pub(crate) syntax: SyntaxNode, } impl RecordExpr { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn record_expr_field_list(&self) -> Option<RecordExprFieldList> { support::child(&self.syntax) } @@ -1024,8 +1298,11 @@ pub struct RecordExprField { } impl ast::HasAttrs for RecordExprField {} impl RecordExprField { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } } @@ -1035,10 +1312,15 @@ pub struct RecordExprFieldList { } impl ast::HasAttrs for RecordExprFieldList {} impl RecordExprFieldList { + #[inline] pub fn fields(&self) -> AstChildren<RecordExprField> { support::children(&self.syntax) } + #[inline] pub fn spread(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } + #[inline] pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) } } @@ -1051,7 +1333,9 @@ impl ast::HasDocComments for RecordField {} impl ast::HasName for RecordField {} impl ast::HasVisibility for RecordField {} impl RecordField { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } } @@ -1060,8 +1344,11 @@ pub struct RecordFieldList { pub(crate) syntax: SyntaxNode, } impl RecordFieldList { + #[inline] pub fn fields(&self) -> AstChildren<RecordField> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1070,7 +1357,9 @@ pub struct RecordPat { pub(crate) syntax: SyntaxNode, } impl RecordPat { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn record_pat_field_list(&self) -> Option<RecordPatFieldList> { support::child(&self.syntax) } @@ -1082,8 +1371,11 @@ pub struct RecordPatField { } impl ast::HasAttrs for RecordPatField {} impl RecordPatField { + #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } } @@ -1092,9 +1384,13 @@ pub struct RecordPatFieldList { pub(crate) syntax: SyntaxNode, } impl RecordPatFieldList { + #[inline] pub fn fields(&self) -> AstChildren<RecordPatField> { support::children(&self.syntax) } + #[inline] pub fn rest_pat(&self) -> Option<RestPat> { support::child(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1104,10 +1400,15 @@ pub struct RefExpr { } impl ast::HasAttrs for RefExpr {} impl RefExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } + #[inline] pub fn raw_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![raw]) } } @@ -1116,8 +1417,11 @@ pub struct RefPat { pub(crate) syntax: SyntaxNode, } impl RefPat { + #[inline] pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) } + #[inline] pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } } @@ -1126,9 +1430,13 @@ pub struct RefType { pub(crate) syntax: SyntaxNode, } impl RefType { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } } @@ -1138,7 +1446,9 @@ pub struct Rename { } impl ast::HasName for Rename {} impl Rename { + #[inline] pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } + #[inline] pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } } @@ -1148,6 +1458,7 @@ pub struct RestPat { } impl ast::HasAttrs for RestPat {} impl RestPat { + #[inline] pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) } } @@ -1156,7 +1467,9 @@ pub struct RetType { pub(crate) syntax: SyntaxNode, } impl RetType { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn thin_arrow_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![->]) } } @@ -1166,7 +1479,9 @@ pub struct ReturnExpr { } impl ast::HasAttrs for ReturnExpr {} impl ReturnExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn return_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![return]) } } @@ -1177,10 +1492,15 @@ pub struct SelfParam { impl ast::HasAttrs for SelfParam {} impl ast::HasName for SelfParam {} impl SelfParam { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn amp_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![&]) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } } @@ -1189,8 +1509,11 @@ pub struct SlicePat { pub(crate) syntax: SyntaxNode, } impl SlicePat { + #[inline] pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } } @@ -1199,8 +1522,11 @@ pub struct SliceType { pub(crate) syntax: SyntaxNode, } impl SliceType { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } } @@ -1212,6 +1538,7 @@ impl ast::HasAttrs for SourceFile {} impl ast::HasDocComments for SourceFile {} impl ast::HasModuleItem for SourceFile {} impl SourceFile { + #[inline] pub fn shebang_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![shebang]) } } @@ -1224,12 +1551,17 @@ impl ast::HasDocComments for Static {} impl ast::HasName for Static {} impl ast::HasVisibility for Static {} impl Static { - pub fn body(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } + #[inline] pub fn static_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![static]) } } @@ -1239,9 +1571,13 @@ pub struct StmtList { } impl ast::HasAttrs for StmtList {} impl StmtList { + #[inline] pub fn statements(&self) -> AstChildren<Stmt> { support::children(&self.syntax) } + #[inline] pub fn tail_expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1255,8 +1591,11 @@ impl ast::HasGenericParams for Struct {} impl ast::HasName for Struct {} impl ast::HasVisibility for Struct {} impl Struct { + #[inline] pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn struct_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![struct]) } } @@ -1265,11 +1604,17 @@ pub struct TokenTree { pub(crate) syntax: SyntaxNode, } impl TokenTree { + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn l_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['[']) } + #[inline] pub fn r_brack_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![']']) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1284,9 +1629,13 @@ impl ast::HasName for Trait {} impl ast::HasTypeBounds for Trait {} impl ast::HasVisibility for Trait {} impl Trait { + #[inline] pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) } + #[inline] pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) } + #[inline] pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) } + #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } @@ -1300,9 +1649,13 @@ impl ast::HasGenericParams for TraitAlias {} impl ast::HasName for TraitAlias {} impl ast::HasVisibility for TraitAlias {} impl TraitAlias { + #[inline] pub fn type_bound_list(&self) -> Option<TypeBoundList> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) } } @@ -1312,7 +1665,9 @@ pub struct TryExpr { } impl ast::HasAttrs for TryExpr {} impl TryExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) } } @@ -1322,8 +1677,11 @@ pub struct TupleExpr { } impl ast::HasAttrs for TupleExpr {} impl TupleExpr { + #[inline] pub fn fields(&self) -> AstChildren<Expr> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -1335,6 +1693,7 @@ impl ast::HasAttrs for TupleField {} impl ast::HasDocComments for TupleField {} impl ast::HasVisibility for TupleField {} impl TupleField { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } } @@ -1343,8 +1702,11 @@ pub struct TupleFieldList { pub(crate) syntax: SyntaxNode, } impl TupleFieldList { + #[inline] pub fn fields(&self) -> AstChildren<TupleField> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -1353,8 +1715,11 @@ pub struct TuplePat { pub(crate) syntax: SyntaxNode, } impl TuplePat { + #[inline] pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -1363,9 +1728,13 @@ pub struct TupleStructPat { pub(crate) syntax: SyntaxNode, } impl TupleStructPat { + #[inline] pub fn fields(&self) -> AstChildren<Pat> { support::children(&self.syntax) } + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -1374,8 +1743,11 @@ pub struct TupleType { pub(crate) syntax: SyntaxNode, } impl TupleType { + #[inline] pub fn fields(&self) -> AstChildren<Type> { support::children(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } } @@ -1390,10 +1762,15 @@ impl ast::HasName for TypeAlias {} impl ast::HasTypeBounds for TypeAlias {} impl ast::HasVisibility for TypeAlias {} impl TypeAlias { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } + #[inline] pub fn default_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![default]) } + #[inline] pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) } } @@ -1402,6 +1779,7 @@ pub struct TypeArg { pub(crate) syntax: SyntaxNode, } impl TypeArg { + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } } @@ -1410,11 +1788,17 @@ pub struct TypeBound { pub(crate) syntax: SyntaxNode, } impl TypeBound { + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) } + #[inline] pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) } + #[inline] pub fn const_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![const]) } + #[inline] pub fn tilde_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![~]) } } @@ -1423,6 +1807,7 @@ pub struct TypeBoundList { pub(crate) syntax: SyntaxNode, } impl TypeBoundList { + #[inline] pub fn bounds(&self) -> AstChildren<TypeBound> { support::children(&self.syntax) } } @@ -1434,7 +1819,9 @@ impl ast::HasAttrs for TypeParam {} impl ast::HasName for TypeParam {} impl ast::HasTypeBounds for TypeParam {} impl TypeParam { + #[inline] pub fn default_type(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } } @@ -1444,6 +1831,7 @@ pub struct UnderscoreExpr { } impl ast::HasAttrs for UnderscoreExpr {} impl UnderscoreExpr { + #[inline] pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } } @@ -1457,7 +1845,9 @@ impl ast::HasGenericParams for Union {} impl ast::HasName for Union {} impl ast::HasVisibility for Union {} impl Union { + #[inline] pub fn record_field_list(&self) -> Option<RecordFieldList> { support::child(&self.syntax) } + #[inline] pub fn union_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![union]) } } @@ -1469,8 +1859,11 @@ impl ast::HasAttrs for Use {} impl ast::HasDocComments for Use {} impl ast::HasVisibility for Use {} impl Use { + #[inline] pub fn use_tree(&self) -> Option<UseTree> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } + #[inline] pub fn use_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![use]) } } @@ -1479,10 +1872,15 @@ pub struct UseTree { pub(crate) syntax: SyntaxNode, } impl UseTree { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn rename(&self) -> Option<Rename> { support::child(&self.syntax) } + #[inline] pub fn use_tree_list(&self) -> Option<UseTreeList> { support::child(&self.syntax) } + #[inline] pub fn star_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![*]) } + #[inline] pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } } @@ -1491,8 +1889,11 @@ pub struct UseTreeList { pub(crate) syntax: SyntaxNode, } impl UseTreeList { + #[inline] pub fn use_trees(&self) -> AstChildren<UseTree> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1505,8 +1906,11 @@ impl ast::HasDocComments for Variant {} impl ast::HasName for Variant {} impl ast::HasVisibility for Variant {} impl Variant { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) } + #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } } @@ -1515,8 +1919,11 @@ pub struct VariantList { pub(crate) syntax: SyntaxNode, } impl VariantList { + #[inline] pub fn variants(&self) -> AstChildren<Variant> { support::children(&self.syntax) } + #[inline] pub fn l_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['{']) } + #[inline] pub fn r_curly_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['}']) } } @@ -1525,10 +1932,15 @@ pub struct Visibility { pub(crate) syntax: SyntaxNode, } impl Visibility { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } + #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) } + #[inline] pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) } } @@ -1537,7 +1949,9 @@ pub struct WhereClause { pub(crate) syntax: SyntaxNode, } impl WhereClause { + #[inline] pub fn predicates(&self) -> AstChildren<WherePred> { support::children(&self.syntax) } + #[inline] pub fn where_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![where]) } } @@ -1547,9 +1961,13 @@ pub struct WherePred { } impl ast::HasTypeBounds for WherePred {} impl WherePred { + #[inline] pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) } + #[inline] pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) } } @@ -1559,6 +1977,7 @@ pub struct WhileExpr { } impl ast::HasAttrs for WhileExpr {} impl WhileExpr { + #[inline] pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) } } @@ -1567,6 +1986,7 @@ pub struct WildcardPat { pub(crate) syntax: SyntaxNode, } impl WildcardPat { + #[inline] pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) } } @@ -1576,8 +1996,11 @@ pub struct YeetExpr { } impl ast::HasAttrs for YeetExpr {} impl YeetExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn do_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![do]) } + #[inline] pub fn yeet_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yeet]) } } @@ -1587,7 +2010,9 @@ pub struct YieldExpr { } impl ast::HasAttrs for YieldExpr {} impl YieldExpr { + #[inline] pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn yield_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![yield]) } } @@ -1772,6 +2197,12 @@ pub struct AnyHasDocComments { impl ast::HasDocComments for AnyHasDocComments {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AnyHasGenericArgs { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasGenericArgs for AnyHasGenericArgs {} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct AnyHasGenericParams { pub(crate) syntax: SyntaxNode, } @@ -1807,7 +2238,9 @@ pub struct AnyHasVisibility { } impl ast::HasVisibility for AnyHasVisibility {} impl AstNode for Abi { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ABI } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1815,10 +2248,13 @@ impl AstNode for Abi { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ArgList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ARG_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1826,10 +2262,13 @@ impl AstNode for ArgList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ArrayExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1837,10 +2276,13 @@ impl AstNode for ArrayExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ArrayType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1848,10 +2290,13 @@ impl AstNode for ArrayType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for AsmExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASM_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1859,10 +2304,13 @@ impl AstNode for AsmExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for AssocItemList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_ITEM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1870,10 +2318,13 @@ impl AstNode for AssocItemList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for AssocTypeArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ASSOC_TYPE_ARG } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1881,10 +2332,13 @@ impl AstNode for AssocTypeArg { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Attr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ATTR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1892,10 +2346,13 @@ impl AstNode for Attr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for AwaitExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == AWAIT_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1903,10 +2360,13 @@ impl AstNode for AwaitExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for BecomeExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == BECOME_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1914,10 +2374,13 @@ impl AstNode for BecomeExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for BinExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == BIN_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1925,10 +2388,13 @@ impl AstNode for BinExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for BlockExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == BLOCK_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1936,10 +2402,13 @@ impl AstNode for BlockExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for BoxPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == BOX_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1947,10 +2416,13 @@ impl AstNode for BoxPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for BreakExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == BREAK_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1958,10 +2430,13 @@ impl AstNode for BreakExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for CallExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CALL_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1969,10 +2444,13 @@ impl AstNode for CallExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for CastExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CAST_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1980,10 +2458,13 @@ impl AstNode for CastExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ClosureExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CLOSURE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -1991,10 +2472,13 @@ impl AstNode for ClosureExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Const { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CONST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2002,10 +2486,13 @@ impl AstNode for Const { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ConstArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_ARG } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2013,10 +2500,13 @@ impl AstNode for ConstArg { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ConstBlockPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_BLOCK_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2024,10 +2514,13 @@ impl AstNode for ConstBlockPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ConstParam { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CONST_PARAM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2035,10 +2528,13 @@ impl AstNode for ConstParam { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ContinueExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == CONTINUE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2046,10 +2542,13 @@ impl AstNode for ContinueExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for DynTraitType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == DYN_TRAIT_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2057,10 +2556,13 @@ impl AstNode for DynTraitType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Enum { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ENUM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2068,10 +2570,13 @@ impl AstNode for Enum { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ExprStmt { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == EXPR_STMT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2079,10 +2584,13 @@ impl AstNode for ExprStmt { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ExternBlock { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_BLOCK } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2090,10 +2598,13 @@ impl AstNode for ExternBlock { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ExternCrate { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_CRATE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2101,10 +2612,13 @@ impl AstNode for ExternCrate { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ExternItemList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == EXTERN_ITEM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2112,10 +2626,13 @@ impl AstNode for ExternItemList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for FieldExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FIELD_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2123,10 +2640,13 @@ impl AstNode for FieldExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Fn { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FN } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2134,10 +2654,13 @@ impl AstNode for Fn { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for FnPtrType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FN_PTR_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2145,10 +2668,13 @@ impl AstNode for FnPtrType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ForExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2156,10 +2682,13 @@ impl AstNode for ForExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ForType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FOR_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2167,10 +2696,13 @@ impl AstNode for ForType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for FormatArgsArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2178,10 +2710,13 @@ impl AstNode for FormatArgsArg { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for FormatArgsExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2189,10 +2724,13 @@ impl AstNode for FormatArgsExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for GenericArgList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_ARG_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2200,10 +2738,13 @@ impl AstNode for GenericArgList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for GenericParamList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2211,10 +2752,13 @@ impl AstNode for GenericParamList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for IdentPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == IDENT_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2222,10 +2766,13 @@ impl AstNode for IdentPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for IfExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == IF_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2233,10 +2780,13 @@ impl AstNode for IfExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Impl { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2244,10 +2794,13 @@ impl AstNode for Impl { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ImplTraitType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_TRAIT_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2255,10 +2808,13 @@ impl AstNode for ImplTraitType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for IndexExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == INDEX_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2266,10 +2822,13 @@ impl AstNode for IndexExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for InferType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == INFER_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2277,10 +2836,13 @@ impl AstNode for InferType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ItemList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == ITEM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2288,10 +2850,13 @@ impl AstNode for ItemList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Label { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LABEL } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2299,10 +2864,13 @@ impl AstNode for Label { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LetElse { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LET_ELSE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2310,10 +2878,13 @@ impl AstNode for LetElse { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LetExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2321,10 +2892,13 @@ impl AstNode for LetExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LetStmt { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LET_STMT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2332,10 +2906,13 @@ impl AstNode for LetStmt { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Lifetime { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2343,10 +2920,13 @@ impl AstNode for Lifetime { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LifetimeArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_ARG } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2354,10 +2934,13 @@ impl AstNode for LifetimeArg { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LifetimeParam { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LIFETIME_PARAM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2365,10 +2948,13 @@ impl AstNode for LifetimeParam { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Literal { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2376,10 +2962,13 @@ impl AstNode for Literal { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LiteralPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LITERAL_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2387,10 +2976,13 @@ impl AstNode for LiteralPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for LoopExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == LOOP_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2398,10 +2990,13 @@ impl AstNode for LoopExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroCall { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_CALL } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2409,10 +3004,13 @@ impl AstNode for MacroCall { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroDef { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2420,10 +3018,13 @@ impl AstNode for MacroDef { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroEagerInput { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EAGER_INPUT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2431,10 +3032,13 @@ impl AstNode for MacroEagerInput { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2442,10 +3046,13 @@ impl AstNode for MacroExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroItems { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_ITEMS } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2453,10 +3060,13 @@ impl AstNode for MacroItems { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2464,10 +3074,13 @@ impl AstNode for MacroPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroRules { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_RULES } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2475,10 +3088,13 @@ impl AstNode for MacroRules { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroStmts { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_STMTS } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2486,10 +3102,13 @@ impl AstNode for MacroStmts { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MacroType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2497,10 +3116,13 @@ impl AstNode for MacroType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MatchArm { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2508,10 +3130,13 @@ impl AstNode for MatchArm { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MatchArmList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2519,10 +3144,13 @@ impl AstNode for MatchArmList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MatchExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2530,10 +3158,13 @@ impl AstNode for MatchExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MatchGuard { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_GUARD } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2541,10 +3172,13 @@ impl AstNode for MatchGuard { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Meta { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == META } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2552,10 +3186,13 @@ impl AstNode for Meta { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for MethodCallExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == METHOD_CALL_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2563,10 +3200,13 @@ impl AstNode for MethodCallExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Module { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2574,10 +3214,13 @@ impl AstNode for Module { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Name { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == NAME } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2585,10 +3228,13 @@ impl AstNode for Name { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for NameRef { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == NAME_REF } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2596,10 +3242,13 @@ impl AstNode for NameRef { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for NeverType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == NEVER_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2607,10 +3256,13 @@ impl AstNode for NeverType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for OffsetOfExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == OFFSET_OF_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2618,10 +3270,13 @@ impl AstNode for OffsetOfExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for OrPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == OR_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2629,10 +3284,13 @@ impl AstNode for OrPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Param { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2640,10 +3298,13 @@ impl AstNode for Param { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ParamList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2651,10 +3312,13 @@ impl AstNode for ParamList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ParenExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2662,10 +3326,13 @@ impl AstNode for ParenExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ParenPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2673,10 +3340,13 @@ impl AstNode for ParenPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ParenType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PAREN_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2684,10 +3354,13 @@ impl AstNode for ParenType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Path { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2695,10 +3368,13 @@ impl AstNode for Path { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PathExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2706,10 +3382,13 @@ impl AstNode for PathExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PathPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2717,10 +3396,13 @@ impl AstNode for PathPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PathSegment { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_SEGMENT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2728,10 +3410,13 @@ impl AstNode for PathSegment { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PathType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2739,10 +3424,13 @@ impl AstNode for PathType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PrefixExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PREFIX_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2750,10 +3438,13 @@ impl AstNode for PrefixExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for PtrType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PTR_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2761,10 +3452,13 @@ impl AstNode for PtrType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RangeExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2772,10 +3466,13 @@ impl AstNode for RangeExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RangePat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RANGE_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2783,10 +3480,13 @@ impl AstNode for RangePat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2794,10 +3494,13 @@ impl AstNode for RecordExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordExprField { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2805,10 +3508,13 @@ impl AstNode for RecordExprField { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordExprFieldList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_EXPR_FIELD_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2816,10 +3522,13 @@ impl AstNode for RecordExprFieldList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordField { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2827,10 +3536,13 @@ impl AstNode for RecordField { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordFieldList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_FIELD_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2838,10 +3550,13 @@ impl AstNode for RecordFieldList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2849,10 +3564,13 @@ impl AstNode for RecordPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordPatField { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2860,10 +3578,13 @@ impl AstNode for RecordPatField { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RecordPatFieldList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RECORD_PAT_FIELD_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2871,10 +3592,13 @@ impl AstNode for RecordPatFieldList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RefExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == REF_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2882,10 +3606,13 @@ impl AstNode for RefExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RefPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == REF_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2893,10 +3620,13 @@ impl AstNode for RefPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RefType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == REF_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2904,10 +3634,13 @@ impl AstNode for RefType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Rename { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RENAME } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2915,10 +3648,13 @@ impl AstNode for Rename { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RestPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == REST_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2926,10 +3662,13 @@ impl AstNode for RestPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for RetType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RET_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2937,10 +3676,13 @@ impl AstNode for RetType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for ReturnExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2948,10 +3690,13 @@ impl AstNode for ReturnExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for SelfParam { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2959,10 +3704,13 @@ impl AstNode for SelfParam { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for SlicePat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2970,10 +3718,13 @@ impl AstNode for SlicePat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for SliceType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == SLICE_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2981,10 +3732,13 @@ impl AstNode for SliceType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for SourceFile { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == SOURCE_FILE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -2992,10 +3746,13 @@ impl AstNode for SourceFile { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Static { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == STATIC } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3003,10 +3760,13 @@ impl AstNode for Static { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for StmtList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3014,10 +3774,13 @@ impl AstNode for StmtList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Struct { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == STRUCT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3025,10 +3788,13 @@ impl AstNode for Struct { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TokenTree { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TOKEN_TREE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3036,10 +3802,13 @@ impl AstNode for TokenTree { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Trait { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3047,10 +3816,13 @@ impl AstNode for Trait { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TraitAlias { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TRAIT_ALIAS } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3058,10 +3830,13 @@ impl AstNode for TraitAlias { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TryExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TRY_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3069,10 +3844,13 @@ impl AstNode for TryExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TupleExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3080,10 +3858,13 @@ impl AstNode for TupleExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TupleField { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3091,10 +3872,13 @@ impl AstNode for TupleField { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TupleFieldList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_FIELD_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3102,10 +3886,13 @@ impl AstNode for TupleFieldList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TuplePat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3113,10 +3900,13 @@ impl AstNode for TuplePat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TupleStructPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_STRUCT_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3124,10 +3914,13 @@ impl AstNode for TupleStructPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TupleType { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TUPLE_TYPE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3135,10 +3928,13 @@ impl AstNode for TupleType { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TypeAlias { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ALIAS } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3146,10 +3942,13 @@ impl AstNode for TypeAlias { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TypeArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ARG } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3157,10 +3956,13 @@ impl AstNode for TypeArg { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TypeBound { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3168,10 +3970,13 @@ impl AstNode for TypeBound { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TypeBoundList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3179,10 +3984,13 @@ impl AstNode for TypeBoundList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for TypeParam { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_PARAM } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3190,10 +3998,13 @@ impl AstNode for TypeParam { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for UnderscoreExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == UNDERSCORE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3201,10 +4012,13 @@ impl AstNode for UnderscoreExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Union { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == UNION } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3212,10 +4026,13 @@ impl AstNode for Union { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Use { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == USE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3223,10 +4040,13 @@ impl AstNode for Use { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for UseTree { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3234,10 +4054,13 @@ impl AstNode for UseTree { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for UseTreeList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3245,10 +4068,13 @@ impl AstNode for UseTreeList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Variant { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3256,10 +4082,13 @@ impl AstNode for Variant { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for VariantList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == VARIANT_LIST } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3267,10 +4096,13 @@ impl AstNode for VariantList { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for Visibility { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3278,10 +4110,13 @@ impl AstNode for Visibility { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for WhereClause { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3289,10 +4124,13 @@ impl AstNode for WhereClause { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for WherePred { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_PRED } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3300,10 +4138,13 @@ impl AstNode for WherePred { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for WhileExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == WHILE_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3311,10 +4152,13 @@ impl AstNode for WhileExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for WildcardPat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == WILDCARD_PAT } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3322,10 +4166,13 @@ impl AstNode for WildcardPat { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for YeetExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == YEET_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3333,10 +4180,13 @@ impl AstNode for YeetExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AstNode for YieldExpr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == YIELD_EXPR } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) @@ -3344,19 +4194,25 @@ impl AstNode for YieldExpr { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl From<Enum> for Adt { + #[inline] fn from(node: Enum) -> Adt { Adt::Enum(node) } } impl From<Struct> for Adt { + #[inline] fn from(node: Struct) -> Adt { Adt::Struct(node) } } impl From<Union> for Adt { + #[inline] fn from(node: Union) -> Adt { Adt::Union(node) } } impl AstNode for Adt { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { ENUM => Adt::Enum(Enum { syntax }), @@ -3366,6 +4222,7 @@ impl AstNode for Adt { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { Adt::Enum(it) => &it.syntax, @@ -3375,19 +4232,25 @@ impl AstNode for Adt { } } impl From<Const> for AssocItem { + #[inline] fn from(node: Const) -> AssocItem { AssocItem::Const(node) } } impl From<Fn> for AssocItem { + #[inline] fn from(node: Fn) -> AssocItem { AssocItem::Fn(node) } } impl From<MacroCall> for AssocItem { + #[inline] fn from(node: MacroCall) -> AssocItem { AssocItem::MacroCall(node) } } impl From<TypeAlias> for AssocItem { + #[inline] fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) } } impl AstNode for AssocItem { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { CONST => AssocItem::Const(Const { syntax }), @@ -3398,6 +4261,7 @@ impl AstNode for AssocItem { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { AssocItem::Const(it) => &it.syntax, @@ -3408,114 +4272,151 @@ impl AstNode for AssocItem { } } impl From<ArrayExpr> for Expr { + #[inline] fn from(node: ArrayExpr) -> Expr { Expr::ArrayExpr(node) } } impl From<AsmExpr> for Expr { + #[inline] fn from(node: AsmExpr) -> Expr { Expr::AsmExpr(node) } } impl From<AwaitExpr> for Expr { + #[inline] fn from(node: AwaitExpr) -> Expr { Expr::AwaitExpr(node) } } impl From<BecomeExpr> for Expr { + #[inline] fn from(node: BecomeExpr) -> Expr { Expr::BecomeExpr(node) } } impl From<BinExpr> for Expr { + #[inline] fn from(node: BinExpr) -> Expr { Expr::BinExpr(node) } } impl From<BlockExpr> for Expr { + #[inline] fn from(node: BlockExpr) -> Expr { Expr::BlockExpr(node) } } impl From<BreakExpr> for Expr { + #[inline] fn from(node: BreakExpr) -> Expr { Expr::BreakExpr(node) } } impl From<CallExpr> for Expr { + #[inline] fn from(node: CallExpr) -> Expr { Expr::CallExpr(node) } } impl From<CastExpr> for Expr { + #[inline] fn from(node: CastExpr) -> Expr { Expr::CastExpr(node) } } impl From<ClosureExpr> for Expr { + #[inline] fn from(node: ClosureExpr) -> Expr { Expr::ClosureExpr(node) } } impl From<ContinueExpr> for Expr { + #[inline] fn from(node: ContinueExpr) -> Expr { Expr::ContinueExpr(node) } } impl From<FieldExpr> for Expr { + #[inline] fn from(node: FieldExpr) -> Expr { Expr::FieldExpr(node) } } impl From<ForExpr> for Expr { + #[inline] fn from(node: ForExpr) -> Expr { Expr::ForExpr(node) } } impl From<FormatArgsExpr> for Expr { + #[inline] fn from(node: FormatArgsExpr) -> Expr { Expr::FormatArgsExpr(node) } } impl From<IfExpr> for Expr { + #[inline] fn from(node: IfExpr) -> Expr { Expr::IfExpr(node) } } impl From<IndexExpr> for Expr { + #[inline] fn from(node: IndexExpr) -> Expr { Expr::IndexExpr(node) } } impl From<LetExpr> for Expr { + #[inline] fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) } } impl From<Literal> for Expr { + #[inline] fn from(node: Literal) -> Expr { Expr::Literal(node) } } impl From<LoopExpr> for Expr { + #[inline] fn from(node: LoopExpr) -> Expr { Expr::LoopExpr(node) } } impl From<MacroExpr> for Expr { + #[inline] fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) } } impl From<MatchExpr> for Expr { + #[inline] fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } } impl From<MethodCallExpr> for Expr { + #[inline] fn from(node: MethodCallExpr) -> Expr { Expr::MethodCallExpr(node) } } impl From<OffsetOfExpr> for Expr { + #[inline] fn from(node: OffsetOfExpr) -> Expr { Expr::OffsetOfExpr(node) } } impl From<ParenExpr> for Expr { + #[inline] fn from(node: ParenExpr) -> Expr { Expr::ParenExpr(node) } } impl From<PathExpr> for Expr { + #[inline] fn from(node: PathExpr) -> Expr { Expr::PathExpr(node) } } impl From<PrefixExpr> for Expr { + #[inline] fn from(node: PrefixExpr) -> Expr { Expr::PrefixExpr(node) } } impl From<RangeExpr> for Expr { + #[inline] fn from(node: RangeExpr) -> Expr { Expr::RangeExpr(node) } } impl From<RecordExpr> for Expr { + #[inline] fn from(node: RecordExpr) -> Expr { Expr::RecordExpr(node) } } impl From<RefExpr> for Expr { + #[inline] fn from(node: RefExpr) -> Expr { Expr::RefExpr(node) } } impl From<ReturnExpr> for Expr { + #[inline] fn from(node: ReturnExpr) -> Expr { Expr::ReturnExpr(node) } } impl From<TryExpr> for Expr { + #[inline] fn from(node: TryExpr) -> Expr { Expr::TryExpr(node) } } impl From<TupleExpr> for Expr { + #[inline] fn from(node: TupleExpr) -> Expr { Expr::TupleExpr(node) } } impl From<UnderscoreExpr> for Expr { + #[inline] fn from(node: UnderscoreExpr) -> Expr { Expr::UnderscoreExpr(node) } } impl From<WhileExpr> for Expr { + #[inline] fn from(node: WhileExpr) -> Expr { Expr::WhileExpr(node) } } impl From<YeetExpr> for Expr { + #[inline] fn from(node: YeetExpr) -> Expr { Expr::YeetExpr(node) } } impl From<YieldExpr> for Expr { + #[inline] fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) } } impl AstNode for Expr { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -3557,6 +4458,7 @@ impl AstNode for Expr { | YIELD_EXPR ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { ARRAY_EXPR => Expr::ArrayExpr(ArrayExpr { syntax }), @@ -3599,6 +4501,7 @@ impl AstNode for Expr { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { Expr::ArrayExpr(it) => &it.syntax, @@ -3641,19 +4544,25 @@ impl AstNode for Expr { } } impl From<Fn> for ExternItem { + #[inline] fn from(node: Fn) -> ExternItem { ExternItem::Fn(node) } } impl From<MacroCall> for ExternItem { + #[inline] fn from(node: MacroCall) -> ExternItem { ExternItem::MacroCall(node) } } impl From<Static> for ExternItem { + #[inline] fn from(node: Static) -> ExternItem { ExternItem::Static(node) } } impl From<TypeAlias> for ExternItem { + #[inline] fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) } } impl AstNode for ExternItem { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { FN => ExternItem::Fn(Fn { syntax }), @@ -3664,6 +4573,7 @@ impl AstNode for ExternItem { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { ExternItem::Fn(it) => &it.syntax, @@ -3674,13 +4584,17 @@ impl AstNode for ExternItem { } } impl From<RecordFieldList> for FieldList { + #[inline] fn from(node: RecordFieldList) -> FieldList { FieldList::RecordFieldList(node) } } impl From<TupleFieldList> for FieldList { + #[inline] fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) } } impl AstNode for FieldList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }), @@ -3689,6 +4603,7 @@ impl AstNode for FieldList { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { FieldList::RecordFieldList(it) => &it.syntax, @@ -3697,21 +4612,27 @@ impl AstNode for FieldList { } } impl From<AssocTypeArg> for GenericArg { + #[inline] fn from(node: AssocTypeArg) -> GenericArg { GenericArg::AssocTypeArg(node) } } impl From<ConstArg> for GenericArg { + #[inline] fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) } } impl From<LifetimeArg> for GenericArg { + #[inline] fn from(node: LifetimeArg) -> GenericArg { GenericArg::LifetimeArg(node) } } impl From<TypeArg> for GenericArg { + #[inline] fn from(node: TypeArg) -> GenericArg { GenericArg::TypeArg(node) } } impl AstNode for GenericArg { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ASSOC_TYPE_ARG | CONST_ARG | LIFETIME_ARG | TYPE_ARG) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }), @@ -3722,6 +4643,7 @@ impl AstNode for GenericArg { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { GenericArg::AssocTypeArg(it) => &it.syntax, @@ -3732,18 +4654,23 @@ impl AstNode for GenericArg { } } impl From<ConstParam> for GenericParam { + #[inline] fn from(node: ConstParam) -> GenericParam { GenericParam::ConstParam(node) } } impl From<LifetimeParam> for GenericParam { + #[inline] fn from(node: LifetimeParam) -> GenericParam { GenericParam::LifetimeParam(node) } } impl From<TypeParam> for GenericParam { + #[inline] fn from(node: TypeParam) -> GenericParam { GenericParam::TypeParam(node) } } impl AstNode for GenericParam { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { CONST_PARAM => GenericParam::ConstParam(ConstParam { syntax }), @@ -3753,6 +4680,7 @@ impl AstNode for GenericParam { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { GenericParam::ConstParam(it) => &it.syntax, @@ -3762,57 +4690,75 @@ impl AstNode for GenericParam { } } impl From<Const> for Item { + #[inline] fn from(node: Const) -> Item { Item::Const(node) } } impl From<Enum> for Item { + #[inline] fn from(node: Enum) -> Item { Item::Enum(node) } } impl From<ExternBlock> for Item { + #[inline] fn from(node: ExternBlock) -> Item { Item::ExternBlock(node) } } impl From<ExternCrate> for Item { + #[inline] fn from(node: ExternCrate) -> Item { Item::ExternCrate(node) } } impl From<Fn> for Item { + #[inline] fn from(node: Fn) -> Item { Item::Fn(node) } } impl From<Impl> for Item { + #[inline] fn from(node: Impl) -> Item { Item::Impl(node) } } impl From<MacroCall> for Item { + #[inline] fn from(node: MacroCall) -> Item { Item::MacroCall(node) } } impl From<MacroDef> for Item { + #[inline] fn from(node: MacroDef) -> Item { Item::MacroDef(node) } } impl From<MacroRules> for Item { + #[inline] fn from(node: MacroRules) -> Item { Item::MacroRules(node) } } impl From<Module> for Item { + #[inline] fn from(node: Module) -> Item { Item::Module(node) } } impl From<Static> for Item { + #[inline] fn from(node: Static) -> Item { Item::Static(node) } } impl From<Struct> for Item { + #[inline] fn from(node: Struct) -> Item { Item::Struct(node) } } impl From<Trait> for Item { + #[inline] fn from(node: Trait) -> Item { Item::Trait(node) } } impl From<TraitAlias> for Item { + #[inline] fn from(node: TraitAlias) -> Item { Item::TraitAlias(node) } } impl From<TypeAlias> for Item { + #[inline] fn from(node: TypeAlias) -> Item { Item::TypeAlias(node) } } impl From<Union> for Item { + #[inline] fn from(node: Union) -> Item { Item::Union(node) } } impl From<Use> for Item { + #[inline] fn from(node: Use) -> Item { Item::Use(node) } } impl AstNode for Item { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -3835,6 +4781,7 @@ impl AstNode for Item { | USE ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { CONST => Item::Const(Const { syntax }), @@ -3858,6 +4805,7 @@ impl AstNode for Item { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { Item::Const(it) => &it.syntax, @@ -3881,54 +4829,71 @@ impl AstNode for Item { } } impl From<BoxPat> for Pat { + #[inline] fn from(node: BoxPat) -> Pat { Pat::BoxPat(node) } } impl From<ConstBlockPat> for Pat { + #[inline] fn from(node: ConstBlockPat) -> Pat { Pat::ConstBlockPat(node) } } impl From<IdentPat> for Pat { + #[inline] fn from(node: IdentPat) -> Pat { Pat::IdentPat(node) } } impl From<LiteralPat> for Pat { + #[inline] fn from(node: LiteralPat) -> Pat { Pat::LiteralPat(node) } } impl From<MacroPat> for Pat { + #[inline] fn from(node: MacroPat) -> Pat { Pat::MacroPat(node) } } impl From<OrPat> for Pat { + #[inline] fn from(node: OrPat) -> Pat { Pat::OrPat(node) } } impl From<ParenPat> for Pat { + #[inline] fn from(node: ParenPat) -> Pat { Pat::ParenPat(node) } } impl From<PathPat> for Pat { + #[inline] fn from(node: PathPat) -> Pat { Pat::PathPat(node) } } impl From<RangePat> for Pat { + #[inline] fn from(node: RangePat) -> Pat { Pat::RangePat(node) } } impl From<RecordPat> for Pat { + #[inline] fn from(node: RecordPat) -> Pat { Pat::RecordPat(node) } } impl From<RefPat> for Pat { + #[inline] fn from(node: RefPat) -> Pat { Pat::RefPat(node) } } impl From<RestPat> for Pat { + #[inline] fn from(node: RestPat) -> Pat { Pat::RestPat(node) } } impl From<SlicePat> for Pat { + #[inline] fn from(node: SlicePat) -> Pat { Pat::SlicePat(node) } } impl From<TuplePat> for Pat { + #[inline] fn from(node: TuplePat) -> Pat { Pat::TuplePat(node) } } impl From<TupleStructPat> for Pat { + #[inline] fn from(node: TupleStructPat) -> Pat { Pat::TupleStructPat(node) } } impl From<WildcardPat> for Pat { + #[inline] fn from(node: WildcardPat) -> Pat { Pat::WildcardPat(node) } } impl AstNode for Pat { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -3950,6 +4915,7 @@ impl AstNode for Pat { | WILDCARD_PAT ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { BOX_PAT => Pat::BoxPat(BoxPat { syntax }), @@ -3972,6 +4938,7 @@ impl AstNode for Pat { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { Pat::BoxPat(it) => &it.syntax, @@ -3994,57 +4961,75 @@ impl AstNode for Pat { } } impl From<ExprStmt> for Stmt { + #[inline] fn from(node: ExprStmt) -> Stmt { Stmt::ExprStmt(node) } } impl From<Item> for Stmt { + #[inline] fn from(node: Item) -> Stmt { Stmt::Item(node) } } impl From<LetStmt> for Stmt { + #[inline] fn from(node: LetStmt) -> Stmt { Stmt::LetStmt(node) } } impl From<ArrayType> for Type { + #[inline] fn from(node: ArrayType) -> Type { Type::ArrayType(node) } } impl From<DynTraitType> for Type { + #[inline] fn from(node: DynTraitType) -> Type { Type::DynTraitType(node) } } impl From<FnPtrType> for Type { + #[inline] fn from(node: FnPtrType) -> Type { Type::FnPtrType(node) } } impl From<ForType> for Type { + #[inline] fn from(node: ForType) -> Type { Type::ForType(node) } } impl From<ImplTraitType> for Type { + #[inline] fn from(node: ImplTraitType) -> Type { Type::ImplTraitType(node) } } impl From<InferType> for Type { + #[inline] fn from(node: InferType) -> Type { Type::InferType(node) } } impl From<MacroType> for Type { + #[inline] fn from(node: MacroType) -> Type { Type::MacroType(node) } } impl From<NeverType> for Type { + #[inline] fn from(node: NeverType) -> Type { Type::NeverType(node) } } impl From<ParenType> for Type { + #[inline] fn from(node: ParenType) -> Type { Type::ParenType(node) } } impl From<PathType> for Type { + #[inline] fn from(node: PathType) -> Type { Type::PathType(node) } } impl From<PtrType> for Type { + #[inline] fn from(node: PtrType) -> Type { Type::PtrType(node) } } impl From<RefType> for Type { + #[inline] fn from(node: RefType) -> Type { Type::RefType(node) } } impl From<SliceType> for Type { + #[inline] fn from(node: SliceType) -> Type { Type::SliceType(node) } } impl From<TupleType> for Type { + #[inline] fn from(node: TupleType) -> Type { Type::TupleType(node) } } impl AstNode for Type { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -4064,6 +5049,7 @@ impl AstNode for Type { | TUPLE_TYPE ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { ARRAY_TYPE => Type::ArrayType(ArrayType { syntax }), @@ -4084,6 +5070,7 @@ impl AstNode for Type { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { Type::ArrayType(it) => &it.syntax, @@ -4110,10 +5097,13 @@ impl AnyHasArgList { } } impl AstNode for AnyHasArgList { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasArgList { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasAttrs { @@ -4123,6 +5113,7 @@ impl AnyHasAttrs { } } impl AstNode for AnyHasAttrs { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -4200,9 +5191,11 @@ impl AstNode for AnyHasAttrs { | YIELD_EXPR ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasAttrs { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasDocComments { @@ -4212,6 +5205,7 @@ impl AnyHasDocComments { } } impl AstNode for AnyHasDocComments { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -4238,9 +5232,29 @@ impl AstNode for AnyHasDocComments { | VARIANT ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasDocComments { syntax }) } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl AnyHasGenericArgs { + #[inline] + pub fn new<T: ast::HasGenericArgs>(node: T) -> AnyHasGenericArgs { + AnyHasGenericArgs { syntax: node.syntax().clone() } + } +} +impl AstNode for AnyHasGenericArgs { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { + matches!(kind, ASSOC_TYPE_ARG | METHOD_CALL_EXPR | PATH_SEGMENT) + } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + Self::can_cast(syntax.kind()).then_some(AnyHasGenericArgs { syntax }) + } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasGenericParams { @@ -4250,12 +5264,15 @@ impl AnyHasGenericParams { } } impl AstNode for AnyHasGenericParams { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TRAIT_ALIAS | TYPE_ALIAS | UNION) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasGenericParams { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasLoopBody { @@ -4265,10 +5282,13 @@ impl AnyHasLoopBody { } } impl AstNode for AnyHasLoopBody { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasLoopBody { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasModuleItem { @@ -4278,10 +5298,13 @@ impl AnyHasModuleItem { } } impl AstNode for AnyHasModuleItem { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ITEM_LIST | MACRO_ITEMS | SOURCE_FILE) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasModuleItem { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasName { @@ -4291,6 +5314,7 @@ impl AnyHasName { } } impl AstNode for AnyHasName { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -4316,9 +5340,11 @@ impl AstNode for AnyHasName { | VARIANT ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasName { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasTypeBounds { @@ -4328,15 +5354,18 @@ impl AnyHasTypeBounds { } } impl AstNode for AnyHasTypeBounds { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, ASSOC_TYPE_ARG | LIFETIME_PARAM | TRAIT | TYPE_ALIAS | TYPE_PARAM | WHERE_PRED ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasTypeBounds { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl AnyHasVisibility { @@ -4346,6 +5375,7 @@ impl AnyHasVisibility { } } impl AstNode for AnyHasVisibility { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!( kind, @@ -4369,9 +5399,11 @@ impl AstNode for AnyHasVisibility { | VARIANT ) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(AnyHasVisibility { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } impl std::fmt::Display for Adt { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs index 651a8ebbf79..85d20c2bd8c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs @@ -1,4 +1,4 @@ -//! Generated by `sourcegen_ast`, do not edit by hand. +//! Generated by `cargo codegen grammar`, do not edit by hand. use crate::{ ast::AstToken, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index b0fbe7101c1..911e3d823de 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -10,7 +10,10 @@ use parser::SyntaxKind; use rowan::{GreenNodeData, GreenTokenData}; use crate::{ - ast::{self, support, AstNode, AstToken, HasAttrs, HasGenericParams, HasName, SyntaxNode}, + ast::{ + self, support, AstNode, AstToken, HasAttrs, HasGenericArgs, HasGenericParams, HasName, + SyntaxNode, + }, ted, NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T, }; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 9131cd2f179..28089ffb377 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -27,6 +27,14 @@ impl Expr { } fn needs_parens_in_expr(&self, parent: &Expr) -> bool { + // Parentheses are necessary when calling a function-like pointer that is a member of a struct or union + // (e.g. `(a.f)()`). + let is_parent_call_expr = matches!(parent, ast::Expr::CallExpr(_)); + let is_field_expr = matches!(self, ast::Expr::FieldExpr(_)); + if is_parent_call_expr && is_field_expr { + return true; + } + // Special-case block weirdness if parent.child_is_followed_by_a_block() { use Expr::*; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs index 1ce548f8fc7..df017ddde64 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs @@ -1,9 +1,6 @@ //! There are many AstNodes, but only a few tokens, so we hand-write them here. -use std::{ - borrow::Cow, - num::{ParseFloatError, ParseIntError}, -}; +use std::{borrow::Cow, num::ParseIntError}; use rustc_lexer::unescape::{ unescape_byte, unescape_char, unescape_mixed, unescape_unicode, EscapeError, MixedUnit, Mode, @@ -393,9 +390,9 @@ impl ast::IntNumber { } } - pub fn float_value(&self) -> Option<f64> { + pub fn value_string(&self) -> String { let (_, text, _) = self.split_into_parts(); - text.replace('_', "").parse::<f64>().ok() + text.replace('_', "") } } @@ -432,14 +429,9 @@ impl ast::FloatNumber { } } - pub fn value(&self) -> Result<f64, ParseFloatError> { - let (text, _) = self.split_into_parts(); - text.replace('_', "").parse::<f64>() - } - - pub fn value_f32(&self) -> Result<f32, ParseFloatError> { + pub fn value_string(&self) -> String { let (text, _) = self.split_into_parts(); - text.replace('_', "").parse::<f32>() + text.replace('_', "") } } @@ -497,6 +489,8 @@ impl ast::Byte { #[cfg(test)] mod tests { + use rustc_apfloat::ieee::Quad as f128; + use crate::ast::{self, make, FloatNumber, IntNumber}; fn check_float_suffix<'a>(lit: &str, expected: impl Into<Option<&'a str>>) { @@ -507,12 +501,17 @@ mod tests { assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into()); } - fn check_float_value(lit: &str, expected: impl Into<Option<f64>> + Copy) { + // FIXME(#17451) Use `expected: f128` once `f128` is stabilised. + fn check_float_value(lit: &str, expected: &str) { + let expected = Some(expected.parse::<f128>().unwrap()); assert_eq!( - FloatNumber { syntax: make::tokens::literal(lit) }.value().ok(), - expected.into() + FloatNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f128>().ok(), + expected + ); + assert_eq!( + IntNumber { syntax: make::tokens::literal(lit) }.value_string().parse::<f128>().ok(), + expected ); - assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into()); } fn check_int_value(lit: &str, expected: impl Into<Option<u128>>) { @@ -525,9 +524,9 @@ mod tests { check_float_suffix("123f32", "f32"); check_float_suffix("123.0e", None); check_float_suffix("123.0e4", None); - check_float_suffix("123.0ef32", "f32"); + check_float_suffix("123.0ef16", "f16"); check_float_suffix("123.0E4f32", "f32"); - check_float_suffix("1_2_3.0_f32", "f32"); + check_float_suffix("1_2_3.0_f128", "f128"); } #[test] @@ -594,8 +593,10 @@ bcde", b"abcde", #[test] fn test_value_underscores() { - check_float_value("1.234567891011121_f64", 1.234567891011121_f64); - check_float_value("1__0.__0__f32", 10.0); + check_float_value("1.3_4665449586950493453___6_f128", "1.346654495869504934536"); + check_float_value("1.234567891011121_f64", "1.234567891011121"); + check_float_value("1__0.__0__f32", "10.0"); + check_float_value("3._0_f16", "3.0"); check_int_value("0b__1_0_", 2); check_int_value("1_1_1_1_1_1", 111111); } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs index 16f7356b1e3..152b0cb98c2 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/traits.rs @@ -52,6 +52,11 @@ pub trait HasGenericParams: AstNode { support::child(self.syntax()) } } +pub trait HasGenericArgs: AstNode { + fn generic_arg_list(&self) -> Option<ast::GenericArgList> { + support::child(self.syntax()) + } +} pub trait HasTypeBounds: AstNode { fn type_bound_list(&self) -> Option<ast::TypeBoundList> { diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs index b5d816b0ce1..177f48b986a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs @@ -20,7 +20,6 @@ //! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] -#![warn(rust_2018_idioms, unused_lifetimes)] #[cfg(not(feature = "in-rust-tree"))] extern crate ra_ap_rustc_lexer as rustc_lexer; diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs index 43f62d0d1e0..088817b8357 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs @@ -6,7 +6,6 @@ //! * Extracting markup (mainly, `$0` markers) out of fixture strings. //! * marks (see the eponymous module). -#![warn(rust_2018_idioms, unused_lifetimes)] #![allow(clippy::print_stderr)] mod assert_linear; @@ -305,7 +304,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> { } let range = TextRange::at(offset, len.try_into().unwrap()); let line_no_caret = &line[len..]; - let end_marker = line_no_caret.find(|c| c == '$'); + let end_marker = line_no_caret.find('$'); let next = line_no_caret.find(marker).map_or(line.len(), |it| it + len); let cond = |end_marker| { diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 0257ed9ab41..d1862f7d738 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -123,7 +123,7 @@ pub mod marker { impl_copy! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } @@ -180,7 +180,7 @@ pub mod default { 0; usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } impl_default! { - 0.0; f32 f64 + 0.0; f16 f32 f64 f128 } // endregion:builtin_impls } @@ -276,7 +276,7 @@ pub mod clone { impl_clone! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } @@ -796,7 +796,7 @@ pub mod ops { )*) } - add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 } // endregion:builtin_impls // endregion:add @@ -1043,7 +1043,7 @@ pub mod fmt { impl_debug! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 - f32 f64 + f16 f32 f64 f128 bool char } diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/text-edit/src/lib.rs index e2ff373c1ba..3efe0850d88 100644 --- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs +++ b/src/tools/rust-analyzer/crates/text-edit/src/lib.rs @@ -4,8 +4,6 @@ //! so `TextEdit` is the ultimate representation of the work done by //! rust-analyzer. -#![warn(rust_2018_idioms, unused_lifetimes)] - use itertools::Itertools; use std::cmp::max; pub use text_size::{TextRange, TextSize}; diff --git a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs index 2591ed16916..a0603e35a09 100644 --- a/src/tools/rust-analyzer/crates/toolchain/src/lib.rs +++ b/src/tools/rust-analyzer/crates/toolchain/src/lib.rs @@ -1,7 +1,5 @@ //! Discovery of `cargo` & `rustc` executables. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{env, iter, path::PathBuf}; use camino::{Utf8Path, Utf8PathBuf}; diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml index c96f088cdc5..1311e2ddf89 100644 --- a/src/tools/rust-analyzer/crates/tt/Cargo.toml +++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml @@ -12,6 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] +arrayvec.workspace = true smol_str.workspace = true text-size.workspace = true diff --git a/src/tools/rust-analyzer/crates/tt/src/iter.rs b/src/tools/rust-analyzer/crates/tt/src/iter.rs new file mode 100644 index 00000000000..175259a3e47 --- /dev/null +++ b/src/tools/rust-analyzer/crates/tt/src/iter.rs @@ -0,0 +1,161 @@ +//! A "Parser" structure for token trees. We use this when parsing a declarative +//! macro definition into a list of patterns and templates. + +use arrayvec::ArrayVec; + +use crate::{Ident, Leaf, Punct, Spacing, Subtree, TokenTree}; + +#[derive(Debug, Clone)] +pub struct TtIter<'a, S> { + inner: std::slice::Iter<'a, TokenTree<S>>, +} + +impl<'a, S: Copy> TtIter<'a, S> { + pub fn new(subtree: &'a Subtree<S>) -> TtIter<'a, S> { + TtIter { inner: subtree.token_trees.iter() } + } + + pub fn new_iter(iter: std::slice::Iter<'a, TokenTree<S>>) -> TtIter<'a, S> { + TtIter { inner: iter } + } + + pub fn expect_char(&mut self, char: char) -> Result<(), ()> { + match self.next() { + Some(&TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()), + _ => Err(()), + } + } + + pub fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> { + match self.next() { + Some(TokenTree::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(c) => { + Ok(()) + } + _ => Err(()), + } + } + + pub fn expect_subtree(&mut self) -> Result<&'a Subtree<S>, ()> { + match self.next() { + Some(TokenTree::Subtree(it)) => Ok(it), + _ => Err(()), + } + } + + pub fn expect_leaf(&mut self) -> Result<&'a Leaf<S>, ()> { + match self.next() { + Some(TokenTree::Leaf(it)) => Ok(it), + _ => Err(()), + } + } + + pub fn expect_dollar(&mut self) -> Result<(), ()> { + match self.expect_leaf()? { + Leaf::Punct(Punct { char: '$', .. }) => Ok(()), + _ => Err(()), + } + } + + pub fn expect_ident(&mut self) -> Result<&'a Ident<S>, ()> { + match self.expect_leaf()? { + Leaf::Ident(it) if it.text != "_" => Ok(it), + _ => Err(()), + } + } + + pub fn expect_ident_or_underscore(&mut self) -> Result<&'a Ident<S>, ()> { + match self.expect_leaf()? { + Leaf::Ident(it) => Ok(it), + _ => Err(()), + } + } + + pub fn expect_literal(&mut self) -> Result<&'a Leaf<S>, ()> { + let it = self.expect_leaf()?; + match it { + Leaf::Literal(_) => Ok(it), + Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it), + _ => Err(()), + } + } + + pub fn expect_single_punct(&mut self) -> Result<&'a Punct<S>, ()> { + match self.expect_leaf()? { + Leaf::Punct(it) => Ok(it), + _ => Err(()), + } + } + + /// Returns consecutive `Punct`s that can be glued together. + /// + /// This method currently may return a single quotation, which is part of lifetime ident and + /// conceptually not a punct in the context of mbe. Callers should handle this. + pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, 3>, ()> { + let TokenTree::Leaf(Leaf::Punct(first)) = self.next().ok_or(())?.clone() else { + return Err(()); + }; + + let mut res = ArrayVec::new(); + if first.spacing == Spacing::Alone { + res.push(first); + return Ok(res); + } + + let (second, third) = match (self.peek_n(0), self.peek_n(1)) { + (Some(TokenTree::Leaf(Leaf::Punct(p2))), Some(TokenTree::Leaf(Leaf::Punct(p3)))) + if p2.spacing == Spacing::Joint => + { + (p2, Some(p3)) + } + (Some(TokenTree::Leaf(Leaf::Punct(p2))), _) => (p2, None), + _ => { + res.push(first); + return Ok(res); + } + }; + + match (first.char, second.char, third.map(|it| it.char)) { + ('.', '.', Some('.' | '=')) | ('<', '<', Some('=')) | ('>', '>', Some('=')) => { + let _ = self.next().unwrap(); + let _ = self.next().unwrap(); + res.push(first); + res.push(*second); + res.push(*third.unwrap()); + } + ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _) + | ('-' | '=' | '>', '>', _) + | ('<', '-', _) + | (':', ':', _) + | ('.', '.', _) + | ('&', '&', _) + | ('<', '<', _) + | ('|', '|', _) => { + let _ = self.next().unwrap(); + res.push(first); + res.push(*second); + } + _ => res.push(first), + } + Ok(res) + } + pub fn peek_n(&self, n: usize) -> Option<&'a TokenTree<S>> { + self.inner.as_slice().get(n) + } + + pub fn as_slice(&self) -> &'a [TokenTree<S>] { + self.inner.as_slice() + } +} + +impl<'a, S> Iterator for TtIter<'a, S> { + type Item = &'a TokenTree<S>; + fn next(&mut self) -> Option<Self::Item> { + self.inner.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} + +impl<S> std::iter::ExactSizeIterator for TtIter<'_, S> {} diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index e9de3f97b0e..369744d0e96 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -2,7 +2,8 @@ //! input and output) of macros. It closely mirrors `proc_macro` crate's //! `TokenTree`. -#![warn(rust_2018_idioms, unused_lifetimes)] +pub mod buffer; +pub mod iter; use std::fmt; @@ -365,8 +366,6 @@ impl<S> Subtree<S> { } } -pub mod buffer; - pub fn pretty<S>(tkns: &[TokenTree<S>]) -> String { fn tokentree_to_text<S>(tkn: &TokenTree<S>) -> String { match tkn { diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index 1dbccab370c..7e0f9af7af8 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -7,8 +7,6 @@ //! Hopefully, one day a reliable file watching/walking crate appears on //! crates.io, and we can reduce this to trivial glue code. -#![warn(rust_2018_idioms, unused_lifetimes)] - use std::{ fs, path::{Component, Path}, diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs index 18c8699dd4d..b3aa6e2fe11 100644 --- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs @@ -38,8 +38,6 @@ //! [`Handle`]: loader::Handle //! [`Entries`]: loader::Entry -#![warn(rust_2018_idioms, unused_lifetimes)] - mod anchored_path; pub mod file_set; pub mod loader; diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md index 4303a800a04..f4e7263868c 100644 --- a/src/tools/rust-analyzer/docs/dev/architecture.md +++ b/src/tools/rust-analyzer/docs/dev/architecture.md @@ -368,7 +368,7 @@ In particular, we generate: * Documentation tests for assists -See the `sourcegen` crate for details. +See the `xtask\src\codegen\assists_doc_tests.rs` module for details. **Architecture Invariant:** we avoid bootstrapping. For codegen we need to parse Rust code. diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 695fec7e8e0..74acb6f9940 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp/ext.rs hash: 8e6e340f2899b5e9 +lsp/ext.rs hash: 39b47906286ad9c If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: @@ -376,12 +376,29 @@ rust-analyzer supports two `kind`s of runnables, `"cargo"` and `"shell"`. The `a ```typescript { + /** + * Environment variables to set before running the command. + */ + environment?: Record<string, string>; + /** + * The working directory to run the command in. + */ + cwd: string; + /** + * The workspace root directory of the cargo project. + */ workspaceRoot?: string; - cwd?: string; + /** + * The cargo command to run. + */ cargoArgs: string[]; - cargoExtraArgs: string[]; + /** + * Arguments to pass to the executable, these will be passed to the command after a `--` argument. + */ executableArgs: string[]; - expectTest?: boolean; + /** + * Command to execute instead of `cargo`. + */ overrideCargo?: string; } ``` @@ -390,10 +407,17 @@ The args for `"shell"` look like this: ```typescript { + /** + * Environment variables to set before running the command. + */ + environment?: Record<string, string>; + /** + * The working directory to run the command in. + */ + cwd: string; kind: string; program: string; args: string[]; - cwd: string; } ``` diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 14aae91741e..edb95abdb8e 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -9,10 +9,15 @@ for enum variants. -- Placeholder expression to use for missing expressions in assists. -- -[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `400`):: +[[rust-analyzer.assist.termSearch.borrowcheck]]rust-analyzer.assist.termSearch.borrowcheck (default: `true`):: + -- -Term search fuel in "units of work" for assists (Defaults to 400). +Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check. +-- +[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `1800`):: ++ +-- +Term search fuel in "units of work" for assists (Defaults to 1800). -- [[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`):: + @@ -350,12 +355,6 @@ Default: "description": "Put the expression into a pinned `Box`", "scope": "expr" }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, "Err": { "postfix": "err", "body": "Err(${receiver})", @@ -367,6 +366,12 @@ Default: "body": "Some(${receiver})", "description": "Wrap the expression in an `Option::Some`", "scope": "expr" + }, + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", + "scope": "expr" } } ---- @@ -378,10 +383,10 @@ Custom completion snippets. -- Whether to enable term search based snippets like `Some(foo.bar().baz())`. -- -[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `200`):: +[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `1000`):: + -- -Term search fuel in "units of work" for autocompletion (Defaults to 200). +Term search fuel in "units of work" for autocompletion (Defaults to 1000). -- [[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`):: + @@ -589,6 +594,11 @@ Whether to prefer import paths containing a `prelude` module. -- The path structure for newly inserted paths to use. -- +[[rust-analyzer.imports.prefixExternPrelude]]rust-analyzer.imports.prefixExternPrelude (default: `false`):: ++ +-- +Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". +-- [[rust-analyzer.inlayHints.bindingModeHints.enable]]rust-analyzer.inlayHints.bindingModeHints.enable (default: `false`):: + -- @@ -645,6 +655,21 @@ Whether to hide inlay hints for type adjustments outside of `unsafe` blocks. -- Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc). -- +[[rust-analyzer.inlayHints.genericParameterHints.const.enable]]rust-analyzer.inlayHints.genericParameterHints.const.enable (default: `false`):: ++ +-- +Whether to show const generic parameter name inlay hints. +-- +[[rust-analyzer.inlayHints.genericParameterHints.lifetime.enable]]rust-analyzer.inlayHints.genericParameterHints.lifetime.enable (default: `true`):: ++ +-- +Whether to show generic lifetime parameter name inlay hints. +-- +[[rust-analyzer.inlayHints.genericParameterHints.type.enable]]rust-analyzer.inlayHints.genericParameterHints.type.enable (default: `false`):: ++ +-- +Whether to show generic type parameter name inlay hints. +-- [[rust-analyzer.inlayHints.implicitDrops.enable]]rust-analyzer.inlayHints.implicitDrops.enable (default: `false`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index db2a989106f..7e77c7e52fa 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -305,6 +305,16 @@ "command": "rust-analyzer.toggleLSPLogs", "title": "Toggle LSP Logs", "category": "rust-analyzer" + }, + { + "command": "rust-analyzer.openWalkthrough", + "title": "Open Walkthrough", + "category": "rust-analyzer" + }, + { + "command": "rust-analyzer.openFAQ", + "title": "Open FAQ", + "category": "rust-analyzer" } ], "keybindings": [ @@ -323,14 +333,6 @@ { "title": "general", "properties": { - "rust-analyzer.cargoRunner": { - "type": [ - "null", - "string" - ], - "default": null, - "description": "Custom cargo runner extension ID." - }, "rust-analyzer.restartServerOnConfigChange": { "markdownDescription": "Whether to restart the server automatically when certain settings that require a restart are changed.", "default": false, @@ -591,9 +593,19 @@ { "title": "assist", "properties": { + "rust-analyzer.assist.termSearch.borrowcheck": { + "markdownDescription": "Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.", + "default": true, + "type": "boolean" + } + } + }, + { + "title": "assist", + "properties": { "rust-analyzer.assist.termSearch.fuel": { - "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).", - "default": 400, + "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 1800).", + "default": 1800, "type": "integer", "minimum": 0 } @@ -1187,12 +1199,6 @@ "description": "Put the expression into a pinned `Box`", "scope": "expr" }, - "Ok": { - "postfix": "ok", - "body": "Ok(${receiver})", - "description": "Wrap the expression in a `Result::Ok`", - "scope": "expr" - }, "Err": { "postfix": "err", "body": "Err(${receiver})", @@ -1204,6 +1210,12 @@ "body": "Some(${receiver})", "description": "Wrap the expression in an `Option::Some`", "scope": "expr" + }, + "Ok": { + "postfix": "ok", + "body": "Ok(${receiver})", + "description": "Wrap the expression in a `Result::Ok`", + "scope": "expr" } }, "type": "object" @@ -1224,8 +1236,8 @@ "title": "completion", "properties": { "rust-analyzer.completion.termSearch.fuel": { - "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).", - "default": 200, + "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 1000).", + "default": 1000, "type": "integer", "minimum": 0 } @@ -1723,6 +1735,16 @@ } }, { + "title": "imports", + "properties": { + "rust-analyzer.imports.prefixExternPrelude": { + "markdownDescription": "Whether to prefix external (including std, core) crate imports with `::`. e.g. \"use ::std::io::Read;\".", + "default": false, + "type": "boolean" + } + } + }, + { "title": "inlayHints", "properties": { "rust-analyzer.inlayHints.bindingModeHints.enable": { @@ -1890,6 +1912,36 @@ { "title": "inlayHints", "properties": { + "rust-analyzer.inlayHints.genericParameterHints.const.enable": { + "markdownDescription": "Whether to show const generic parameter name inlay hints.", + "default": false, + "type": "boolean" + } + } + }, + { + "title": "inlayHints", + "properties": { + "rust-analyzer.inlayHints.genericParameterHints.lifetime.enable": { + "markdownDescription": "Whether to show generic lifetime parameter name inlay hints.", + "default": true, + "type": "boolean" + } + } + }, + { + "title": "inlayHints", + "properties": { + "rust-analyzer.inlayHints.genericParameterHints.type.enable": { + "markdownDescription": "Whether to show generic type parameter name inlay hints.", + "default": false, + "type": "boolean" + } + } + }, + { + "title": "inlayHints", + "properties": { "rust-analyzer.inlayHints.implicitDrops.enable": { "markdownDescription": "Whether to show implicit drop hints.", "default": false, @@ -3132,6 +3184,12 @@ { "command": "rust-analyzer.toggleLSPLogs", "when": "inRustProject" + }, + { + "command": "rust-analyzer.openWalkthrough" + }, + { + "command": "rust-analyzer.openFAQ" } ], "editor/context": [ @@ -3161,6 +3219,57 @@ "fileMatch": "rust-project.json", "url": "https://json.schemastore.org/rust-project.json" } + ], + "walkthroughs": [ + { + "id": "landing", + "title": "Learn about rust-analyzer", + "description": "A brief introduction to get started with rust-analyzer. Learn about key features and resources to help you get the most out of the extension.", + "steps": [ + { + "id": "setup", + "title": "Useful Setup Tips", + "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the following to your settings.json will mark all Rust library sources as readonly:\n```json\n\"files.readonlyInclude\": {\n \"**/.cargo/registry/src/**/*.rs\": true,\n \"**/lib/rustlib/src/rust/library/**/*.rs\": true,\n},\n```\n\n**Check on Save**\n\nBy default, rust-analyzer will run `cargo check` on your codebase when you save a file, rendering diagnostics emitted by `cargo check` within your code. This can potentially collide with other `cargo` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the `rust-analyzer.checkOnSave` configuration and running the `rust-analyzer: Run flycheck` command on-demand instead.", + "media": { + "image": "./icon.png", + "altText": "rust-analyzer logo" + } + }, + { + "id": "docs", + "title": "Visit the docs!", + "description": "Confused about configurations? Want to learn more about rust-analyzer? Visit the [User Manual](https://rust-analyzer.github.io/manual.html)!", + "media": { + "image": "./icon.png", + "altText": "rust-analyzer logo" + }, + "completionEvents": [ + "onLink:https://rust-analyzer.github.io/manual.html" + ] + }, + { + "id": "faq", + "title": "FAQ", + "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the `editor.inlayHints.enabled` setting.", + "media": { + "image": "icon.png", + "altText": "rust-analyzer logo" + } + }, + { + "id": "changelog", + "title": "Changelog", + "description": "Stay up-to-date with the latest changes in rust-analyzer. Check out the changelog [here](https://rust-analyzer.github.io/thisweek)!", + "media": { + "image": "icon.png", + "altText": "rust-analyzer logo" + }, + "completionEvents": [ + "onLink:https://rust-analyzer.github.io/thisweek" + ] + } + ] + } ] } } diff --git a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts index 5a92b285ae6..f2884ad0b05 100644 --- a/src/tools/rust-analyzer/editors/code/src/bootstrap.ts +++ b/src/tools/rust-analyzer/editors/code/src/bootstrap.ts @@ -36,6 +36,12 @@ async function getServer( config: Config, state: PersistentState, ): Promise<string | undefined> { + const packageJson: { + version: string; + releaseTag: string | null; + enableProposedApi: boolean | undefined; + } = context.extension.packageJSON; + const explicitPath = process.env["__RA_LSP_SERVER_DEBUG"] ?? config.serverPath; if (explicitPath) { if (explicitPath.startsWith("~/")) { @@ -43,7 +49,7 @@ async function getServer( } return explicitPath; } - if (config.package.releaseTag === null) return "rust-analyzer"; + if (packageJson.releaseTag === null) return "rust-analyzer"; const ext = process.platform === "win32" ? ".exe" : ""; const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`); @@ -54,8 +60,15 @@ async function getServer( if (bundledExists) { let server = bundled; if (await isNixOs()) { - server = await getNixOsServer(config, ext, state, bundled, server); - await state.updateServerVersion(config.package.version); + server = await getNixOsServer( + context.globalStorageUri, + packageJson.version, + ext, + state, + bundled, + server, + ); + await state.updateServerVersion(packageJson.version); } return server.fsPath; } @@ -86,19 +99,20 @@ export function isValidExecutable(path: string, extraEnv: Env): boolean { } async function getNixOsServer( - config: Config, + globalStorageUri: vscode.Uri, + version: string, ext: string, state: PersistentState, bundled: vscode.Uri, server: vscode.Uri, ) { - await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); - const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`); + await vscode.workspace.fs.createDirectory(globalStorageUri).then(); + const dest = vscode.Uri.joinPath(globalStorageUri, `rust-analyzer${ext}`); let exists = await vscode.workspace.fs.stat(dest).then( () => true, () => false, ); - if (exists && config.package.version !== state.serverVersion) { + if (exists && version !== state.serverVersion) { await vscode.workspace.fs.delete(dest); exists = false; } diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index 1c2a34b484d..542233e7b91 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -76,7 +76,8 @@ export async function createClient( // value === "unlinked-file" && value === "temporary-disabled" && !unlinkedFiles.includes(uri) && - diag.message !== "file not included in module tree" + (diag.message === "file not included in crate hierarchy" || + diag.message.startsWith("This file is not included in any crates")) ) { const config = vscode.workspace.getConfiguration("rust-analyzer"); if (config.get("showUnlinkedFileNotification")) { diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index f0f9fab1c64..2b0b3001062 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -1502,3 +1502,23 @@ export function toggleLSPLogs(ctx: Ctx): Cmd { } }; } + +export function openWalkthrough(_: Ctx): Cmd { + return async () => { + await vscode.commands.executeCommand( + "workbench.action.openWalkthrough", + "rust-lang.rust-analyzer#landing", + false, + ); + }; +} + +export function openFAQ(_: Ctx): Cmd { + return async () => { + await vscode.commands.executeCommand( + "workbench.action.openWalkthrough", + "rust-lang.rust-analyzer#faq", + true, + ); + }; +} diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 1931cfe3813..ca77215004d 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -4,13 +4,14 @@ import * as path from "path"; import * as vscode from "vscode"; import { type Env, log, unwrapUndefinable, expectNotUndefined } from "./util"; import type { JsonProject } from "./rust_project"; +import type { Disposable } from "./ctx"; export type RunnableEnvCfgItem = { mask?: string; env: Record<string, string>; platform?: string | string[]; }; -export type RunnableEnvCfg = undefined | Record<string, string> | RunnableEnvCfgItem[]; +export type RunnableEnvCfg = Record<string, string> | RunnableEnvCfgItem[]; export class Config { readonly extensionId = "rust-lang.rust-analyzer"; @@ -29,22 +30,9 @@ export class Config { (opt) => `${this.rootSection}.${opt}`, ); - readonly package: { - version: string; - releaseTag: string | null; - enableProposedApi: boolean | undefined; - } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; - - readonly globalStorageUri: vscode.Uri; - - constructor(ctx: vscode.ExtensionContext) { - this.globalStorageUri = ctx.globalStorageUri; + constructor(disposables: Disposable[]) { this.discoveredWorkspaces = []; - vscode.workspace.onDidChangeConfiguration( - this.onDidChangeConfiguration, - this, - ctx.subscriptions, - ); + vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, disposables); this.refreshLogging(); this.configureLanguage(); } @@ -55,7 +43,10 @@ export class Config { private refreshLogging() { log.setEnabled(this.traceExtension ?? false); - log.info("Extension version:", this.package.version); + log.info( + "Extension version:", + vscode.extensions.getExtension(this.extensionId)!.packageJSON.version, + ); const cfg = Object.entries(this.cfg).filter(([_, val]) => !(val instanceof Function)); log.info("Using configuration", Object.fromEntries(cfg)); @@ -277,10 +268,6 @@ export class Config { return this.get<string[]>("runnables.problemMatcher") || []; } - get cargoRunner() { - return this.get<string | undefined>("cargoRunner"); - } - get testExplorer() { return this.get<boolean | undefined>("testExplorer"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index bf0b84ec358..caa99d76194 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -118,7 +118,7 @@ export class Ctx implements RustAnalyzerExtensionApi { extCtx.subscriptions.push(this); this.version = extCtx.extension.packageJSON.version ?? "<unknown>"; this._serverVersion = "<not running>"; - this.config = new Config(extCtx); + this.config = new Config(extCtx.subscriptions); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); if (this.config.testExplorer) { this.testController = vscode.tests.createTestController( diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 58fe1df51f4..f23e3680933 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -180,7 +180,7 @@ async function getDebugExecutable( env: Record<string, string>, ): Promise<string> { const cargo = new Cargo(runnableArgs.workspaceRoot || ".", debugOutput, env); - const executable = await cargo.executableFromArgs(runnableArgs.cargoArgs); + const executable = await cargo.executableFromArgs(runnableArgs); // if we are here, there were no compilation errors. return executable; diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts index 699052e4d44..e24893b2509 100644 --- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts +++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts @@ -235,22 +235,43 @@ type RunnableShell = { args: ShellRunnableArgs; }; +export type CommonRunnableArgs = { + /** + * Environment variables to set before running the command. + */ + environment?: Record<string, string>; + /** + * The working directory to run the command in. + */ + cwd: string; +}; + export type ShellRunnableArgs = { kind: string; program: string; args: string[]; - cwd: string; -}; +} & CommonRunnableArgs; export type CargoRunnableArgs = { + /** + * The workspace root directory of the cargo project. + */ workspaceRoot?: string; - cargoArgs: string[]; - cwd: string; - cargoExtraArgs: string[]; + /** + * Arguments to pass to the executable, these will be passed to the command after a `--` argument. + */ executableArgs: string[]; - expectTest?: boolean; + /** + * Arguments to pass to cargo. + */ + cargoArgs: string[]; + /** + * Command to execute instead of `cargo`. + */ + // This is supplied by the user via config. We could pull this through the client config in the + // extension directly, but that would prevent us from honoring the rust-analyzer.toml for it. overrideCargo?: string; -}; +} & CommonRunnableArgs; export type RunnablesParams = { textDocument: lc.TextDocumentIdentifier; diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index ff67bb7bd59..c96f2ae869e 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -178,6 +178,8 @@ function createCommands(): Record<string, CommandFactory> { viewMemoryLayout: { enabled: commands.viewMemoryLayout }, toggleCheckOnSave: { enabled: commands.toggleCheckOnSave }, toggleLSPLogs: { enabled: commands.toggleLSPLogs }, + openWalkthrough: { enabled: commands.openWalkthrough }, + openFAQ: { enabled: commands.openFAQ }, // Internal commands which are invoked by the server. applyActionGroup: { enabled: commands.applyActionGroup }, applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand }, diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 7a9049af0de..783bbc1607d 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -66,23 +66,21 @@ export class RunnableQuickPick implements vscode.QuickPickItem { } } -export function prepareBaseEnv(): Record<string, string> { +export function prepareBaseEnv(base?: Record<string, string>): Record<string, string> { const env: Record<string, string> = { RUST_BACKTRACE: "short" }; - Object.assign(env, process.env as { [key: string]: string }); + Object.assign(env, process.env); + if (base) { + Object.assign(env, base); + } return env; } export function prepareEnv( label: string, runnableArgs: ra.CargoRunnableArgs, - runnableEnvCfg: RunnableEnvCfg, + runnableEnvCfg?: RunnableEnvCfg, ): Record<string, string> { - const env = prepareBaseEnv(); - - if (runnableArgs.expectTest) { - env["UPDATE_EXPECT"] = "1"; - } - + const env = prepareBaseEnv(runnableArgs.environment); const platform = process.platform; const checkPlatform = (it: RunnableEnvCfgItem) => { @@ -113,26 +111,31 @@ export async function createTaskFromRunnable( runnable: ra.Runnable, config: Config, ): Promise<vscode.Task> { - let definition: tasks.RustTargetDefinition; + const target = vscode.workspace.workspaceFolders?.[0]; + + let definition: tasks.TaskDefinition; + let options; + let cargo; if (runnable.kind === "cargo") { const runnableArgs = runnable.args; let args = createCargoArgs(runnableArgs); - let program: string; if (runnableArgs.overrideCargo) { // Split on spaces to allow overrides like "wrapper cargo". const cargoParts = runnableArgs.overrideCargo.split(" "); - program = unwrapUndefinable(cargoParts[0]); + cargo = unwrapUndefinable(cargoParts[0]); args = [...cargoParts.slice(1), ...args]; } else { - program = await toolchain.cargoPath(); + cargo = await toolchain.cargoPath(); } definition = { type: tasks.CARGO_TASK_TYPE, - command: program, - args, + command: unwrapUndefinable(args[0]), + args: args.slice(1), + }; + options = { cwd: runnableArgs.workspaceRoot || ".", env: prepareEnv(runnable.label, runnableArgs, config.runnablesExtraEnv), }; @@ -142,13 +145,14 @@ export async function createTaskFromRunnable( type: tasks.SHELL_TASK_TYPE, command: runnableArgs.program, args: runnableArgs.args, + }; + options = { cwd: runnableArgs.cwd, env: prepareBaseEnv(), }; } - const target = vscode.workspace.workspaceFolders?.[0]; - const exec = await tasks.targetToExecution(definition, config.cargoRunner, true); + const exec = await tasks.targetToExecution(definition, options, cargo); const task = await tasks.buildRustTask( target, definition, @@ -167,9 +171,6 @@ export async function createTaskFromRunnable( export function createCargoArgs(runnableArgs: ra.CargoRunnableArgs): string[] { const args = [...runnableArgs.cargoArgs]; // should be a copy! - if (runnableArgs.cargoExtraArgs) { - args.push(...runnableArgs.cargoExtraArgs); // Append user-specified cargo options. - } if (runnableArgs.executableArgs.length > 0) { args.push("--", ...runnableArgs.executableArgs); } diff --git a/src/tools/rust-analyzer/editors/code/src/tasks.ts b/src/tools/rust-analyzer/editors/code/src/tasks.ts index 6f4fbf91889..fac1cc6394f 100644 --- a/src/tools/rust-analyzer/editors/code/src/tasks.ts +++ b/src/tools/rust-analyzer/editors/code/src/tasks.ts @@ -1,6 +1,5 @@ import * as vscode from "vscode"; import type { Config } from "./config"; -import { log, unwrapUndefinable } from "./util"; import * as toolchain from "./toolchain"; // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and @@ -10,21 +9,21 @@ export const SHELL_TASK_TYPE = "shell"; export const RUST_TASK_SOURCE = "rust"; -export type RustTargetDefinition = { +export type TaskDefinition = vscode.TaskDefinition & { readonly type: typeof CARGO_TASK_TYPE | typeof SHELL_TASK_TYPE; -} & vscode.TaskDefinition & - RustTarget; -export type RustTarget = { - // The command to run, usually `cargo`. - command: string; - // Additional arguments passed to the command. args?: string[]; - // The working directory to run the command in. - cwd?: string; - // The shell environment. - env?: { [key: string]: string }; + command: string; }; +export type CargoTaskDefinition = { + env?: Record<string, string>; + type: typeof CARGO_TASK_TYPE; +} & TaskDefinition; + +function isCargoTask(definition: vscode.TaskDefinition): definition is CargoTaskDefinition { + return definition.type === CARGO_TASK_TYPE; +} + class RustTaskProvider implements vscode.TaskProvider { private readonly config: Config; @@ -58,13 +57,13 @@ class RustTaskProvider implements vscode.TaskProvider { for (const workspaceTarget of vscode.workspace.workspaceFolders) { for (const def of defs) { const definition = { - command: cargo, - args: [def.command], - }; - const exec = await targetToExecution(definition, this.config.cargoRunner); + command: def.command, + type: CARGO_TASK_TYPE, + } as const; + const exec = await targetToExecution(definition, {}, cargo); const vscodeTask = await buildRustTask( workspaceTarget, - { ...definition, type: CARGO_TASK_TYPE }, + definition, `cargo ${def.command}`, this.config.problemMatcher, exec, @@ -81,23 +80,13 @@ class RustTaskProvider implements vscode.TaskProvider { // VSCode calls this for every cargo task in the user's tasks.json, // we need to inform VSCode how to execute that command by creating // a ShellExecution for it. - if (task.definition.type === CARGO_TASK_TYPE) { - const taskDefinition = task.definition as RustTargetDefinition; - const cargo = await toolchain.cargoPath(); - const exec = await targetToExecution( - { - command: cargo, - args: [taskDefinition.command].concat(taskDefinition.args || []), - cwd: taskDefinition.cwd, - env: taskDefinition.env, - }, - this.config.cargoRunner, - ); - return await buildRustTask( + if (isCargoTask(task.definition)) { + const exec = await targetToExecution(task.definition, { env: task.definition.env }); + return buildRustTask( task.scope, - taskDefinition, + task.definition, task.name, - this.config.problemMatcher, + task.problemMatchers, exec, ); } @@ -108,7 +97,7 @@ class RustTaskProvider implements vscode.TaskProvider { export async function buildRustTask( scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined, - definition: RustTargetDefinition, + definition: TaskDefinition, name: string, problemMatcher: string[], exec: vscode.ProcessExecution | vscode.ShellExecution, @@ -126,40 +115,23 @@ export async function buildRustTask( } export async function targetToExecution( - definition: RustTarget, - customRunner?: string, - throwOnError: boolean = false, + definition: TaskDefinition, + options?: { + env?: { [key: string]: string }; + cwd?: string; + }, + cargo?: string, ): Promise<vscode.ProcessExecution | vscode.ShellExecution> { - if (customRunner) { - const runnerCommand = `${customRunner}.buildShellExecution`; - - try { - const runnerArgs = { - kind: CARGO_TASK_TYPE, - args: definition.args, - cwd: definition.cwd, - env: definition.env, - }; - const customExec = await vscode.commands.executeCommand(runnerCommand, runnerArgs); - if (customExec) { - if (customExec instanceof vscode.ShellExecution) { - return customExec; - } else { - log.debug("Invalid cargo ShellExecution", customExec); - throw "Invalid cargo ShellExecution."; - } - } - // fallback to default processing - } catch (e) { - if (throwOnError) throw `Cargo runner '${customRunner}' failed! ${e}`; - // fallback to default processing - } + let command, args; + if (isCargoTask(definition)) { + // FIXME: The server should provide cargo + command = cargo || (await toolchain.cargoPath()); + args = [definition.command].concat(definition.args || []); + } else { + command = definition.command; + args = definition.args || []; } - const args = unwrapUndefinable(definition.args); - return new vscode.ProcessExecution(definition.command, args, { - cwd: definition.cwd, - env: definition.env, - }); + return new vscode.ProcessExecution(command, args, options); } export function activateTaskProvider(config: Config): vscode.Disposable { diff --git a/src/tools/rust-analyzer/editors/code/src/toolchain.ts b/src/tools/rust-analyzer/editors/code/src/toolchain.ts index a48d2d90cce..6a0b5c26d82 100644 --- a/src/tools/rust-analyzer/editors/code/src/toolchain.ts +++ b/src/tools/rust-analyzer/editors/code/src/toolchain.ts @@ -4,6 +4,7 @@ import * as path from "path"; import * as readline from "readline"; import * as vscode from "vscode"; import { execute, log, memoizeAsync, unwrapNullable, unwrapUndefinable } from "./util"; +import type { CargoRunnableArgs } from "./lsp_ext"; interface CompilationArtifact { fileName: string; @@ -25,9 +26,8 @@ export class Cargo { ) {} // Made public for testing purposes - static artifactSpec(args: readonly string[]): ArtifactSpec { - const cargoArgs = [...args, "--message-format=json"]; - + static artifactSpec(cargoArgs: string[], executableArgs?: string[]): ArtifactSpec { + cargoArgs = [...cargoArgs, "--message-format=json"]; // arguments for a runnable from the quick pick should be updated. // see crates\rust-analyzer\src\main_loop\handlers.rs, handle_code_lens switch (cargoArgs[0]) { @@ -48,6 +48,9 @@ export class Cargo { // produce 2 artifacts: {"kind": "bin"} and {"kind": "test"} result.filter = (artifacts) => artifacts.filter((it) => it.isTest); } + if (executableArgs) { + cargoArgs.push("--", ...executableArgs); + } return result; } @@ -84,8 +87,10 @@ export class Cargo { return spec.filter?.(artifacts) ?? artifacts; } - async executableFromArgs(args: readonly string[]): Promise<string> { - const artifacts = await this.getArtifacts(Cargo.artifactSpec(args)); + async executableFromArgs(runnableArgs: CargoRunnableArgs): Promise<string> { + const artifacts = await this.getArtifacts( + Cargo.artifactSpec(runnableArgs.cargoArgs, runnableArgs.executableArgs), + ); if (artifacts.length === 0) { throw new Error("No compilation artifacts"); diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts index 21bdaf5384d..81850e03f1c 100644 --- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts +++ b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts @@ -12,12 +12,11 @@ function makeRunnable(label: string): ra.Runnable { cargoArgs: [], cwd: ".", executableArgs: [], - cargoExtraArgs: [], }, }; } -function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> { +function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record<string, string> { const runnable = makeRunnable(runnableName); const runnableArgs = runnable.args as ra.CargoRunnableArgs; return prepareEnv(runnable.label, runnableArgs, config); diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts index bafb9569a1c..84501dde6ca 100644 --- a/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts +++ b/src/tools/rust-analyzer/editors/code/tests/unit/settings.test.ts @@ -13,7 +13,7 @@ export async function getTests(ctx: Context) { USING_MY_VAR: "test test test", MY_VAR: "test", }; - const actualEnv = await substituteVariablesInEnv(envJson); + const actualEnv = substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); @@ -34,7 +34,7 @@ export async function getTests(ctx: Context) { E_IS_ISOLATED: "test", F_USES_E: "test", }; - const actualEnv = await substituteVariablesInEnv(envJson); + const actualEnv = substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); }); @@ -47,7 +47,7 @@ export async function getTests(ctx: Context) { USING_EXTERNAL_VAR: "test test test", }; - const actualEnv = await substituteVariablesInEnv(envJson); + const actualEnv = substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv, expectedEnv); delete process.env["TEST_VARIABLE"]; }); @@ -56,7 +56,7 @@ export async function getTests(ctx: Context) { const envJson = { USING_VSCODE_VAR: "${workspaceFolderBasename}", }; - const actualEnv = await substituteVariablesInEnv(envJson); + const actualEnv = substituteVariablesInEnv(envJson); assert.deepStrictEqual(actualEnv["USING_VSCODE_VAR"], "code"); }); }); diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/tasks.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/tasks.test.ts new file mode 100644 index 00000000000..9bccaaf3d47 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/tests/unit/tasks.test.ts @@ -0,0 +1,139 @@ +import type { Context } from "."; +import * as vscode from "vscode"; +import * as assert from "assert"; +import { targetToExecution } from "../../src/tasks"; + +export async function getTests(ctx: Context) { + await ctx.suite("Tasks", (suite) => { + suite.addTest("cargo targetToExecution", async () => { + assert.deepStrictEqual( + await targetToExecution({ + type: "cargo", + command: "check", + args: ["foo"], + }).then(executionToSimple), + { + process: "cargo", + args: ["check", "foo"], + }, + ); + }); + + suite.addTest("shell targetToExecution", async () => { + assert.deepStrictEqual( + await targetToExecution({ + type: "shell", + command: "thing", + args: ["foo"], + }).then(executionToSimple), + { + process: "thing", + args: ["foo"], + }, + ); + }); + + suite.addTest("base tasks", async () => { + const tasks = await vscode.tasks.fetchTasks({ type: "cargo" }); + const expectedTasks = [ + { + definition: { type: "cargo", command: "build" }, + name: "cargo build", + execution: { + process: "cargo", + args: ["build"], + }, + }, + { + definition: { + type: "cargo", + command: "check", + }, + name: "cargo check", + execution: { + process: "cargo", + args: ["check"], + }, + }, + { + definition: { type: "cargo", command: "clippy" }, + name: "cargo clippy", + execution: { + process: "cargo", + args: ["clippy"], + }, + }, + { + definition: { type: "cargo", command: "test" }, + name: "cargo test", + execution: { + process: "cargo", + args: ["test"], + }, + }, + { + definition: { + type: "cargo", + command: "clean", + }, + name: "cargo clean", + execution: { + process: "cargo", + args: ["clean"], + }, + }, + { + definition: { type: "cargo", command: "run" }, + name: "cargo run", + execution: { + process: "cargo", + args: ["run"], + }, + }, + ]; + tasks.map(f).forEach((actual, i) => { + const expected = expectedTasks[i]; + assert.deepStrictEqual(actual, expected); + }); + }); + }); +} + +function f(task: vscode.Task): { + definition: vscode.TaskDefinition; + name: string; + execution: { + args: string[]; + } & ({ command: string } | { process: string }); +} { + const execution = executionToSimple(task.execution!); + + return { + definition: task.definition, + name: task.name, + execution, + }; +} +function executionToSimple( + taskExecution: vscode.ProcessExecution | vscode.ShellExecution | vscode.CustomExecution, +): { + args: string[]; +} & ({ command: string } | { process: string }) { + const exec = taskExecution as vscode.ProcessExecution | vscode.ShellExecution; + if (exec instanceof vscode.ShellExecution) { + return { + command: typeof exec.command === "string" ? exec.command : exec.command.value, + args: exec.args.map((arg) => { + if (typeof arg === "string") { + return arg; + } + return arg.value; + }), + }; + } else { + return { + process: exec.process, + args: exec.args, + }; + } +} diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index c605feb6eea..424c93a7521 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -3d5d7a24f76006b391d8a53d903ae64c1b4a52d2 +bcf1f6db4594ae6132378b179a30cdb3599a863d diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index 95eed3ee172..d62adb9144b 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -5,6 +5,7 @@ [relabel] allow-unauthenticated = [ "S-*", + "A-*", ] [autolabel."S-waiting-on-review"] diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs index b23d700263f..acaa65129df 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen.rs @@ -5,12 +5,17 @@ use std::{ use xshell::{cmd, Shell}; -use crate::{flags, project_root}; +use crate::{ + flags::{self, CodegenType}, + project_root, +}; pub(crate) mod assists_doc_tests; pub(crate) mod diagnostics_docs; +pub(crate) mod feature_docs; mod grammar; mod lints; +mod parser_inline_tests; impl flags::Codegen { pub(crate) fn run(self, _sh: &Shell) -> anyhow::Result<()> { @@ -18,6 +23,8 @@ impl flags::Codegen { flags::CodegenType::All => { diagnostics_docs::generate(self.check); assists_doc_tests::generate(self.check); + parser_inline_tests::generate(self.check); + // diagnostics_docs::generate(self.check) doesn't generate any tests // lints::generate(self.check) Updating clones the rust repo, so don't run it unless // explicitly asked for } @@ -25,41 +32,13 @@ impl flags::Codegen { flags::CodegenType::AssistsDocTests => assists_doc_tests::generate(self.check), flags::CodegenType::DiagnosticsDocs => diagnostics_docs::generate(self.check), flags::CodegenType::LintDefinitions => lints::generate(self.check), + flags::CodegenType::ParserTests => parser_inline_tests::generate(self.check), + flags::CodegenType::FeatureDocs => feature_docs::generate(self.check), } Ok(()) } } -fn list_rust_files(dir: &Path) -> Vec<PathBuf> { - let mut res = list_files(dir); - res.retain(|it| { - it.file_name().unwrap_or_default().to_str().unwrap_or_default().ends_with(".rs") - }); - res -} - -fn list_files(dir: &Path) -> Vec<PathBuf> { - let mut res = Vec::new(); - let mut work = vec![dir.to_path_buf()]; - while let Some(dir) = work.pop() { - for entry in dir.read_dir().unwrap() { - let entry = entry.unwrap(); - let file_type = entry.file_type().unwrap(); - let path = entry.path(); - let is_hidden = - path.file_name().unwrap_or_default().to_str().unwrap_or_default().starts_with('.'); - if !is_hidden { - if file_type.is_dir() { - work.push(path); - } else if file_type.is_file() { - res.push(path); - } - } - } - } - res -} - #[derive(Clone)] pub(crate) struct CommentBlock { pub(crate) id: String, @@ -174,8 +153,8 @@ fn reformat(text: String) -> String { stdout } -fn add_preamble(generator: &'static str, mut text: String) -> String { - let preamble = format!("//! Generated by `{generator}`, do not edit by hand.\n\n"); +fn add_preamble(cg: CodegenType, mut text: String) -> String { + let preamble = format!("//! Generated by `cargo codegen {cg}`, do not edit by hand.\n\n"); text.insert_str(0, &preamble); text } @@ -183,7 +162,7 @@ fn add_preamble(generator: &'static str, mut text: String) -> String { /// Checks that the `file` has the specified `contents`. If that is not the /// case, updates the file and then fails the test. #[allow(clippy::print_stderr)] -fn ensure_file_contents(file: &Path, contents: &str, check: bool) { +fn ensure_file_contents(cg: CodegenType, file: &Path, contents: &str, check: bool) { if let Ok(old_contents) = fs::read_to_string(file) { if normalize_newlines(&old_contents) == normalize_newlines(contents) { // File is already up to date. @@ -197,9 +176,11 @@ fn ensure_file_contents(file: &Path, contents: &str, check: bool) { "{} was not up-to-date{}", file.display(), if std::env::var("CI").is_ok() { - "\n NOTE: run `cargo codegen` locally and commit the updated files\n" + format!( + "\n NOTE: run `cargo codegen {cg}` locally and commit the updated files\n" + ) } else { - "" + "".to_owned() } ); } else { diff --git a/src/tools/rust-analyzer/xtask/src/codegen/assists_doc_tests.rs b/src/tools/rust-analyzer/xtask/src/codegen/assists_doc_tests.rs index b2d89dde765..d06c9d65df3 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/assists_doc_tests.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/assists_doc_tests.rs @@ -5,10 +5,9 @@ use std::{fmt, fs, path::Path}; use stdx::format_to_acc; use crate::{ - codegen::{ - add_preamble, ensure_file_contents, list_rust_files, reformat, CommentBlock, Location, - }, + codegen::{add_preamble, ensure_file_contents, reformat, CommentBlock, Location}, project_root, + util::list_rust_files, }; pub(crate) fn generate(check: bool) { @@ -45,8 +44,9 @@ r#####" buf.push_str(&test) } } - let buf = add_preamble("sourcegen_assists_docs", reformat(buf)); + let buf = add_preamble(crate::flags::CodegenType::AssistsDocTests, reformat(buf)); ensure_file_contents( + crate::flags::CodegenType::AssistsDocTests, &project_root().join("crates/ide-assists/src/tests/generated.rs"), &buf, check, @@ -59,7 +59,7 @@ r#####" // a release. let contents = add_preamble( - "sourcegen_assists_docs", + crate::flags::CodegenType::AssistsDocTests, assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"), ); let dst = project_root().join("docs/user/generated_assists.adoc"); @@ -195,3 +195,8 @@ fn reveal_hash_comments(text: &str) -> String { }) .fold(String::new(), |mut acc, it| format_to_acc!(acc, "{it}\n")) } + +#[test] +fn test() { + generate(true); +} diff --git a/src/tools/rust-analyzer/xtask/src/codegen/diagnostics_docs.rs b/src/tools/rust-analyzer/xtask/src/codegen/diagnostics_docs.rs index cf30531e7f9..4cb8f3f259d 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/diagnostics_docs.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/diagnostics_docs.rs @@ -3,8 +3,9 @@ use std::{fmt, fs, io, path::PathBuf}; use crate::{ - codegen::{add_preamble, list_rust_files, CommentBlock, Location}, + codegen::{add_preamble, CommentBlock, Location}, project_root, + util::list_rust_files, }; pub(crate) fn generate(check: bool) { @@ -12,7 +13,7 @@ pub(crate) fn generate(check: bool) { if !check { let contents = diagnostics.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); - let contents = add_preamble("sourcegen_diagnostic_docs", contents); + let contents = add_preamble(crate::flags::CodegenType::DiagnosticsDocs, contents); let dst = project_root().join("docs/user/generated_diagnostic.adoc"); fs::write(dst, contents).unwrap(); } @@ -63,7 +64,7 @@ fn is_valid_diagnostic_name(diagnostic: &str) -> Result<(), String> { if diagnostic.chars().any(|c| c.is_ascii_uppercase()) { return Err("Diagnostic names can't contain uppercase symbols".into()); } - if diagnostic.chars().any(|c| !c.is_ascii()) { + if !diagnostic.is_ascii() { return Err("Diagnostic can't contain non-ASCII symbols".into()); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/sourcegen.rs b/src/tools/rust-analyzer/xtask/src/codegen/feature_docs.rs index 2eafb0da692..c6451d888b0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/sourcegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/feature_docs.rs @@ -2,8 +2,13 @@ use std::{fmt, fs, io, path::PathBuf}; -#[test] -fn sourcegen_feature_docs() { +use crate::{ + codegen::{CommentBlock, Location}, + project_root, + util::list_rust_files, +}; + +pub(crate) fn generate(_check: bool) { let features = Feature::collect().unwrap(); let contents = features.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n"); let contents = format!( @@ -13,23 +18,23 @@ fn sourcegen_feature_docs() { ", contents.trim() ); - let dst = sourcegen::project_root().join("docs/user/generated_features.adoc"); + let dst = project_root().join("docs/user/generated_features.adoc"); fs::write(dst, contents).unwrap(); } #[derive(Debug)] struct Feature { id: String, - location: sourcegen::Location, + location: Location, doc: String, } impl Feature { fn collect() -> io::Result<Vec<Feature>> { - let crates_dir = sourcegen::project_root().join("crates"); + let crates_dir = project_root().join("crates"); let mut res = Vec::new(); - for path in sourcegen::list_rust_files(&crates_dir) { + for path in list_rust_files(&crates_dir) { collect_file(&mut res, path)?; } res.sort_by(|lhs, rhs| lhs.id.cmp(&rhs.id)); @@ -37,7 +42,7 @@ impl Feature { fn collect_file(acc: &mut Vec<Feature>, path: PathBuf) -> io::Result<()> { let text = std::fs::read_to_string(&path)?; - let comment_blocks = sourcegen::CommentBlock::extract("Feature", &text); + let comment_blocks = CommentBlock::extract("Feature", &text); for block in comment_blocks { let id = block.id; @@ -45,7 +50,7 @@ impl Feature { panic!("invalid feature name: {id:?}:\n {msg}") } let doc = block.contents.join("\n"); - let location = sourcegen::Location { file: path.clone(), line: block.line }; + let location = Location { file: path.clone(), line: block.line }; acc.push(Feature { id, location, doc }) } diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs index cc2fadc9750..45fa2d37c8f 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs @@ -27,7 +27,12 @@ use self::ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc pub(crate) fn generate(check: bool) { let syntax_kinds = generate_syntax_kinds(KINDS_SRC); let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs"); - ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds, check); + ensure_file_contents( + crate::flags::CodegenType::Grammar, + syntax_kinds_file.as_path(), + &syntax_kinds, + check, + ); let grammar = fs::read_to_string(project_root().join("crates/syntax/rust.ungram")) .unwrap() @@ -37,11 +42,21 @@ pub(crate) fn generate(check: bool) { let ast_tokens = generate_tokens(&ast); let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs"); - ensure_file_contents(ast_tokens_file.as_path(), &ast_tokens, check); + ensure_file_contents( + crate::flags::CodegenType::Grammar, + ast_tokens_file.as_path(), + &ast_tokens, + check, + ); let ast_nodes = generate_nodes(KINDS_SRC, &ast); let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs"); - ensure_file_contents(ast_nodes_file.as_path(), &ast_nodes, check); + ensure_file_contents( + crate::flags::CodegenType::Grammar, + ast_nodes_file.as_path(), + &ast_nodes, + check, + ); } fn generate_tokens(grammar: &AstSrc) -> String { @@ -69,7 +84,7 @@ fn generate_tokens(grammar: &AstSrc) -> String { }); add_preamble( - "sourcegen_ast", + crate::flags::CodegenType::Grammar, reformat( quote! { use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken}; @@ -107,18 +122,21 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { if field.is_many() { quote! { + #[inline] pub fn #method_name(&self) -> AstChildren<#ty> { support::children(&self.syntax) } } } else if let Some(token_kind) = field.token_kind() { quote! { + #[inline] pub fn #method_name(&self) -> Option<#ty> { support::token(&self.syntax, #token_kind) } } } else { quote! { + #[inline] pub fn #method_name(&self) -> Option<#ty> { support::child(&self.syntax) } @@ -141,12 +159,15 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { }, quote! { impl AstNode for #name { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == #kind } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } }, @@ -175,9 +196,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } else { quote! { impl AstNode for #name { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, #(#kinds)|*) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { let res = match syntax.kind() { #( @@ -187,6 +210,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { }; Some(res) } + #[inline] fn syntax(&self) -> &SyntaxNode { match self { #( @@ -211,6 +235,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { quote! { #( impl From<#variants> for #name { + #[inline] fn from(node: #variants) -> #name { #name::#variants(node) } @@ -255,12 +280,15 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } } impl AstNode for #name { + #[inline] fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, #(#kinds)|*) } + #[inline] fn cast(syntax: SyntaxNode) -> Option<Self> { Self::can_cast(syntax.kind()).then_some(#name { syntax }) } + #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } @@ -328,7 +356,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } } - let res = add_preamble("sourcegen_ast", reformat(res)); + let res = add_preamble(crate::flags::CodegenType::Grammar, reformat(res)); res.replace("#[derive", "\n#[derive") } @@ -458,7 +486,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String { } }; - add_preamble("sourcegen_ast", reformat(ast.to_string())) + add_preamble(crate::flags::CodegenType::Grammar, reformat(ast.to_string())) } fn to_upper_snake_case(s: &str) -> String { @@ -692,6 +720,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r | "self_ty" | "iterable" | "condition" + | "args" + | "body" ); if manually_implemented { return; @@ -780,20 +810,21 @@ fn extract_enums(ast: &mut AstSrc) { } } -fn extract_struct_traits(ast: &mut AstSrc) { - let traits: &[(&str, &[&str])] = &[ - ("HasAttrs", &["attrs"]), - ("HasName", &["name"]), - ("HasVisibility", &["visibility"]), - ("HasGenericParams", &["generic_param_list", "where_clause"]), - ("HasTypeBounds", &["type_bound_list", "colon_token"]), - ("HasModuleItem", &["items"]), - ("HasLoopBody", &["label", "loop_body"]), - ("HasArgList", &["arg_list"]), - ]; +const TRAITS: &[(&str, &[&str])] = &[ + ("HasAttrs", &["attrs"]), + ("HasName", &["name"]), + ("HasVisibility", &["visibility"]), + ("HasGenericParams", &["generic_param_list", "where_clause"]), + ("HasGenericArgs", &["generic_arg_list"]), + ("HasTypeBounds", &["type_bound_list", "colon_token"]), + ("HasModuleItem", &["items"]), + ("HasLoopBody", &["label", "loop_body"]), + ("HasArgList", &["arg_list"]), +]; +fn extract_struct_traits(ast: &mut AstSrc) { for node in &mut ast.nodes { - for (name, methods) in traits { + for (name, methods) in TRAITS { extract_struct_trait(node, name, methods); } } @@ -873,3 +904,8 @@ impl AstNodeSrc { }); } } + +#[test] +fn test() { + generate(true); +} diff --git a/src/tools/rust-analyzer/xtask/src/codegen/lints.rs b/src/tools/rust-analyzer/xtask/src/codegen/lints.rs index 6975f9328e5..f097b5817be 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/lints.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/lints.rs @@ -6,8 +6,9 @@ use stdx::format_to; use xshell::{cmd, Shell}; use crate::{ - codegen::{add_preamble, ensure_file_contents, list_files, reformat}, + codegen::{add_preamble, ensure_file_contents, reformat}, project_root, + util::list_files, }; const DESTINATION: &str = "crates/ide-db/src/generated/lints.rs"; @@ -28,7 +29,7 @@ pub(crate) fn generate(check: bool) { cmd!( sh, "git -C {rust_repo} submodule update --init --recursive --depth=1 -- - compiler library src/tools" + compiler library src/tools src/doc/book" ) .run() .unwrap(); @@ -73,10 +74,15 @@ pub struct LintGroup { .unwrap(); generate_descriptor_clippy(&mut contents, &lints_json); - let contents = add_preamble("sourcegen_lints", reformat(contents)); + let contents = add_preamble(crate::flags::CodegenType::LintDefinitions, reformat(contents)); let destination = project_root().join(DESTINATION); - ensure_file_contents(destination.as_path(), &contents, check); + ensure_file_contents( + crate::flags::CodegenType::LintDefinitions, + destination.as_path(), + &contents, + check, + ); } /// Parses the output of `rustdoc -Whelp` and prints `Lint` and `LintGroup` constants into `buf`. diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs index 5a71bfd82b1..5983b06e1b9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs @@ -8,16 +8,21 @@ use std::{ path::{Path, PathBuf}, }; -#[test] -fn sourcegen_parser_tests() { - let grammar_dir = sourcegen::project_root().join(Path::new("crates/parser/src/grammar")); +use crate::{ + codegen::{ensure_file_contents, CommentBlock}, + project_root, + util::list_rust_files, +}; + +pub(crate) fn generate(check: bool) { + let grammar_dir = project_root().join(Path::new("crates/parser/src/grammar")); let tests = tests_from_dir(&grammar_dir); - install_tests(&tests.ok, "crates/parser/test_data/parser/inline/ok"); - install_tests(&tests.err, "crates/parser/test_data/parser/inline/err"); + install_tests(&tests.ok, "crates/parser/test_data/parser/inline/ok", check); + install_tests(&tests.err, "crates/parser/test_data/parser/inline/err", check); - fn install_tests(tests: &HashMap<String, Test>, into: &str) { - let tests_dir = sourcegen::project_root().join(into); + fn install_tests(tests: &HashMap<String, Test>, into: &str, check: bool) { + let tests_dir = project_root().join(into); if !tests_dir.is_dir() { fs::create_dir_all(&tests_dir).unwrap(); } @@ -37,7 +42,7 @@ fn sourcegen_parser_tests() { tests_dir.join(file_name) } }; - sourcegen::ensure_file_contents(&path, &test.text); + ensure_file_contents(crate::flags::CodegenType::ParserTests, &path, &test.text, check); } } } @@ -57,7 +62,7 @@ struct Tests { fn collect_tests(s: &str) -> Vec<Test> { let mut res = Vec::new(); - for comment_block in sourcegen::CommentBlock::extract_untagged(s) { + for comment_block in CommentBlock::extract_untagged(s) { let first_line = &comment_block.contents[0]; let (name, ok) = if let Some(name) = first_line.strip_prefix("test ") { (name.to_owned(), true) @@ -80,7 +85,7 @@ fn collect_tests(s: &str) -> Vec<Test> { fn tests_from_dir(dir: &Path) -> Tests { let mut res = Tests::default(); - for entry in sourcegen::list_rust_files(dir) { + for entry in list_rust_files(dir) { process_file(&mut res, entry.as_path()); } let grammar_rs = dir.parent().unwrap().join("grammar.rs"); @@ -122,3 +127,8 @@ fn existing_tests(dir: &Path, ok: bool) -> HashMap<String, (PathBuf, Test)> { } res } + +#[test] +fn test() { + generate(true); +} diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs index dd7bfd0bda0..cf4a22d476f 100644 --- a/src/tools/rust-analyzer/xtask/src/flags.rs +++ b/src/tools/rust-analyzer/xtask/src/flags.rs @@ -1,6 +1,6 @@ #![allow(unreachable_pub)] -use std::str::FromStr; +use std::{fmt, str::FromStr}; use crate::install::{ClientOpt, ServerOpt}; @@ -73,6 +73,8 @@ xflags::xflags! { optional codegen_type: CodegenType optional --check } + + cmd tidy {} } } @@ -96,9 +98,13 @@ pub enum XtaskCmd { Metrics(Metrics), Bb(Bb), Codegen(Codegen), + Tidy(Tidy), } #[derive(Debug)] +pub struct Tidy {} + +#[derive(Debug)] pub struct Install { pub client: bool, pub code_bin: Option<String>, @@ -185,6 +191,22 @@ pub enum CodegenType { AssistsDocTests, DiagnosticsDocs, LintDefinitions, + ParserTests, + FeatureDocs, +} + +impl fmt::Display for CodegenType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::All => write!(f, "all"), + Self::Grammar => write!(f, "grammar"), + Self::AssistsDocTests => write!(f, "assists-doc-tests"), + Self::DiagnosticsDocs => write!(f, "diagnostics-docs"), + Self::LintDefinitions => write!(f, "lint-definitions"), + Self::ParserTests => write!(f, "parser-tests"), + Self::FeatureDocs => write!(f, "feature-docs"), + } + } } impl FromStr for CodegenType { @@ -195,7 +217,9 @@ impl FromStr for CodegenType { "grammar" => Ok(Self::Grammar), "assists-doc-tests" => Ok(Self::AssistsDocTests), "diagnostics-docs" => Ok(Self::DiagnosticsDocs), - "lints-definitions" => Ok(Self::LintDefinitions), + "lint-definitions" => Ok(Self::LintDefinitions), + "parser-tests" => Ok(Self::ParserTests), + "feature-docs" => Ok(Self::FeatureDocs), _ => Err("Invalid option".to_owned()), } } diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs index e0705763035..5c312da1dd7 100644 --- a/src/tools/rust-analyzer/xtask/src/main.rs +++ b/src/tools/rust-analyzer/xtask/src/main.rs @@ -19,6 +19,8 @@ mod install; mod metrics; mod publish; mod release; +mod tidy; +mod util; use anyhow::bail; use std::{env, path::PathBuf}; @@ -51,6 +53,7 @@ fn main() -> anyhow::Result<()> { )?; Ok(()) } + flags::XtaskCmd::Tidy(cmd) => cmd.run(sh), } } diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs index 5699053a23d..3eda2bc0274 100644 --- a/src/tools/rust-analyzer/xtask/src/release.rs +++ b/src/tools/rust-analyzer/xtask/src/release.rs @@ -32,6 +32,7 @@ impl flags::Release { // Generates bits of manual.adoc. codegen::diagnostics_docs::generate(false); codegen::assists_doc_tests::generate(false); + codegen::feature_docs::generate(false); let website_root = project_root().join("../rust-analyzer.github.io"); { @@ -119,12 +120,11 @@ impl flags::RustcPull { // Fetch given rustc commit. cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git") .run() - .map_err(|e| { + .inspect_err(|_| { // Try to un-do the previous `git commit`, to leave the repo in the state we found it it. cmd!(sh, "git reset --hard HEAD^") .run() .expect("FAILED to clean up again after failed `git fetch`, sorry for that"); - e }) .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs index 7dd6382cfac..e85f5182865 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/src/tools/rust-analyzer/xtask/src/tidy.rs @@ -6,23 +6,29 @@ use std::{ use xshell::Shell; -#[cfg(not(feature = "in-rust-tree"))] use xshell::cmd; -#[test] -fn check_lsp_extensions_docs() { - let sh = &Shell::new().unwrap(); +use crate::{flags::Tidy, project_root, util::list_files}; + +impl Tidy { + pub(crate) fn run(&self, sh: &Shell) -> anyhow::Result<()> { + check_lsp_extensions_docs(sh); + files_are_tidy(sh); + check_licenses(sh); + Ok(()) + } +} +fn check_lsp_extensions_docs(sh: &Shell) { let expected_hash = { - let lsp_ext_rs = sh - .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp/ext.rs")) - .unwrap(); + let lsp_ext_rs = + sh.read_file(project_root().join("crates/rust-analyzer/src/lsp/ext.rs")).unwrap(); stable_hash(lsp_ext_rs.as_str()) }; let actual_hash = { let lsp_extensions_md = - sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap(); + sh.read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap(); let text = lsp_extensions_md .lines() .find_map(|line| line.strip_prefix("lsp/ext.rs hash:")) @@ -45,11 +51,8 @@ Please adjust docs/dev/lsp-extensions.md. } } -#[test] -fn files_are_tidy() { - let sh = &Shell::new().unwrap(); - - let files = sourcegen::list_files(&sourcegen::project_root().join("crates")); +fn files_are_tidy(sh: &Shell) { + let files = list_files(&project_root().join("crates")); let mut tidy_docs = TidyDocs::default(); let mut tidy_marks = TidyMarks::default(); @@ -121,11 +124,7 @@ fn check_cargo_toml(path: &Path, text: String) { } } -#[cfg(not(feature = "in-rust-tree"))] -#[test] -fn check_licenses() { - let sh = &Shell::new().unwrap(); - +fn check_licenses(sh: &Shell) { let expected = " (MIT OR Apache-2.0) AND Unicode-DFS-2016 0BSD OR MIT OR Apache-2.0 @@ -155,7 +154,7 @@ Zlib OR Apache-2.0 OR MIT let meta = cmd!(sh, "cargo metadata --format-version 1").read().unwrap(); let mut licenses = meta - .split(|c| c == ',' || c == '{' || c == '}') + .split([',', '{', '}']) .filter(|it| it.contains(r#""license""#)) .map(|it| it.trim()) .map(|it| it[r#""license":"#.len()..].trim_matches('"')) @@ -277,7 +276,7 @@ impl TidyDocs { } fn is_exclude_dir(p: &Path, dirs_to_exclude: &[&str]) -> bool { - p.strip_prefix(sourcegen::project_root()) + p.strip_prefix(project_root()) .unwrap() .components() .rev() @@ -339,3 +338,8 @@ fn find_marks(set: &mut HashSet<String>, text: &str, mark: &str) { } } } + +#[test] +fn test() { + Tidy {}.run(&Shell::new().unwrap()).unwrap(); +} diff --git a/src/tools/rust-analyzer/xtask/src/util.rs b/src/tools/rust-analyzer/xtask/src/util.rs new file mode 100644 index 00000000000..39f52938c8c --- /dev/null +++ b/src/tools/rust-analyzer/xtask/src/util.rs @@ -0,0 +1,31 @@ +use std::path::{Path, PathBuf}; + +pub(crate) fn list_rust_files(dir: &Path) -> Vec<PathBuf> { + let mut res = list_files(dir); + res.retain(|it| { + it.file_name().unwrap_or_default().to_str().unwrap_or_default().ends_with(".rs") + }); + res +} + +pub(crate) fn list_files(dir: &Path) -> Vec<PathBuf> { + let mut res = Vec::new(); + let mut work = vec![dir.to_path_buf()]; + while let Some(dir) = work.pop() { + for entry in dir.read_dir().unwrap() { + let entry = entry.unwrap(); + let file_type = entry.file_type().unwrap(); + let path = entry.path(); + let is_hidden = + path.file_name().unwrap_or_default().to_str().unwrap_or_default().starts_with('.'); + if !is_hidden { + if file_type.is_dir() { + work.push(path); + } else if file_type.is_file() { + res.push(path); + } + } + } + } + res +} diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f7ec7d0b3f6..bd25a6c144e 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,5 +1,3 @@ -run-make/archive-duplicate-names/Makefile -run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile run-make/c-dynamic-dylib/Makefile run-make/c-dynamic-rlib/Makefile @@ -10,7 +8,6 @@ run-make/c-unwind-abi-catch-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile run-make/compiler-lookup-paths-2/Makefile -run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/crate-hash-rustc-version/Makefile run-make/cross-lang-lto-clang/Makefile @@ -21,18 +18,12 @@ run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/dump-ice-to-disk/Makefile -run-make/dump-mono-stats/Makefile run-make/emit-to-stdout/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile -run-make/extern-fn-explicit-align/Makefile run-make/extern-fn-generic/Makefile -run-make/extern-fn-mangle/Makefile run-make/extern-fn-reachable/Makefile -run-make/extern-fn-struct-passing-abi/Makefile -run-make/extern-fn-with-extern-types/Makefile -run-make/extern-fn-with-packed-struct/Makefile run-make/extern-fn-with-union/Makefile run-make/extern-multiple-copies/Makefile run-make/extern-multiple-copies2/Makefile @@ -46,10 +37,6 @@ run-make/interdependent-c-libraries/Makefile run-make/issue-107094/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile -run-make/issue-18943/Makefile -run-make/issue-22131/Makefile -run-make/issue-25581/Makefile -run-make/issue-26006/Makefile run-make/issue-28595/Makefile run-make/issue-33329/Makefile run-make/issue-35164/Makefile @@ -57,7 +44,6 @@ run-make/issue-36710/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile -run-make/issue-85401-static-mir/Makefile run-make/issue-88756-default-output/Makefile run-make/issue-97463-abi-param-passing/Makefile run-make/jobserver-error/Makefile @@ -67,26 +53,18 @@ run-make/libtest-junit/Makefile run-make/libtest-thread-limit/Makefile run-make/link-cfg/Makefile run-make/link-framework/Makefile -run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile -run-make/longjmp-across-rust/Makefile run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile -run-make/lto-smoke-c/Makefile run-make/macos-deployment-target/Makefile -run-make/macos-fat-archive/Makefile -run-make/manual-link/Makefile run-make/min-global-align/Makefile -run-make/missing-crate-dependency/Makefile -run-make/mixing-libs/Makefile run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-whole-archive/Makefile run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile -run-make/obey-crate-type-flag/Makefile run-make/panic-abort-eh_frame/Makefile run-make/pass-non-c-like-enum-to-c/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile @@ -96,12 +74,9 @@ run-make/pgo-indirect-call-promotion/Makefile run-make/pointer-auth-link-with-c/Makefile run-make/print-calling-conventions/Makefile run-make/print-target-list/Makefile -run-make/prune-link-args/Makefile run-make/raw-dylib-alt-calling-convention/Makefile run-make/raw-dylib-c/Makefile -run-make/raw-dylib-custom-dlltool/Makefile run-make/raw-dylib-import-name-type/Makefile -run-make/raw-dylib-inline-cross-dylib/Makefile run-make/raw-dylib-link-ordinal/Makefile run-make/raw-dylib-stdcall-ordinal/Makefile run-make/redundant-libs/Makefile @@ -120,10 +95,8 @@ run-make/simd-ffi/Makefile run-make/split-debuginfo/Makefile run-make/stable-symbol-names/Makefile run-make/static-dylib-by-default/Makefile -run-make/static-extern-type/Makefile run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile -run-make/std-core-cycle/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/sysroot-crates-are-unstable/Makefile @@ -131,5 +104,4 @@ run-make/test-benches/Makefile run-make/thumb-none-cortex-m/Makefile run-make/thumb-none-qemu/Makefile run-make/translation/Makefile -run-make/unstable-flag-required/Makefile run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 3c72fae0881..f9bf04626f7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -95,7 +95,12 @@ const EXCEPTIONS: ExceptionList = &[ ("self_cell", "Apache-2.0"), // rustc (fluent translations) ("snap", "BSD-3-Clause"), // rustc ("wasm-encoder", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wasm-metadata", "Apache-2.0 WITH LLVM-exception"), // rustc ("wasmparser", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wast", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wat", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wit-component", "Apache-2.0 WITH LLVM-exception"), // rustc + ("wit-parser", "Apache-2.0 WITH LLVM-exception"), // rustc // tidy-alphabetical-end ]; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 3c7284ce6db..57310977704 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3449,7 +3449,6 @@ ui/pattern/issue-6449.rs ui/pattern/issue-66270-pat-struct-parser-recovery.rs ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs -ui/pattern/issue-68393-let-pat-assoc-constant.rs ui/pattern/issue-72565.rs ui/pattern/issue-72574-1.rs ui/pattern/issue-72574-2.rs diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml new file mode 100644 index 00000000000..91ff19ad9fc --- /dev/null +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -0,0 +1,13 @@ +# See the `README.md` in this directory for what this tool is. + +[package] +name = "wasm-component-ld-wrapper" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "wasm-component-ld" +path = "src/main.rs" + +[dependencies] +wasm-component-ld = "0.5.4" diff --git a/src/tools/wasm-component-ld/README.md b/src/tools/wasm-component-ld/README.md new file mode 100644 index 00000000000..54608a2dea1 --- /dev/null +++ b/src/tools/wasm-component-ld/README.md @@ -0,0 +1,62 @@ +# `wasm-component-ld` + +This wrapper is a wrapper around the [`wasm-component-ld`] crates.io crate. That +crate. That crate is itself a thin wrapper around two pieces: + +* `wasm-ld` - the LLVM-based linker distributed as part of LLD and packaged in + Rust as `rust-lld`. +* [`wit-component`] - a Rust crate for creating a [WebAssembly Component] from a + core wasm module. + +This linker is used for Rust's `wasm32-wasip2` target to natively output a +component instead of a core WebAssembly module, unlike other WebAssembly +targets. If you're confused about any of this here's an FAQ-style explanation of +what's going on here: + +* **What's a component?** - It's a proposal to the WebAssembly standard + primarily developed at this time by out-of-browser use cases of WebAssembly. + You can find high-level documentation [here][component docs]. + +* **What's WASIp2?** - Not to be confused with WASIp1, WASIp0, + `wasi_snapshot_preview1`, or `wasi_unstable`, it's a version of WASI. Released + in January 2024 it's the first version of WASI defined in terms of the + component model. + +* **Why does this need its own linker?** - like any target that Rust has the + `wasm32-wasip2` target needs a linker. What makes this different from other + WebAssembly targets is that WASIp2 is defined at the component level, not core + WebAssembly level. This means that filesystem functions take a `string` + instead of `i32 i32`, for example. This means that the raw output of LLVM and + `wasm-ld`, a core WebAssembly module, is not suitable. + +* **Isn't writing a linker really hard?** - Generally, yes, but this linker + works by first asking `wasm-ld` to do all the hard work. It invokes `wasm-ld` + and then uses the output core WebAssembly module to create a component. + +* **How do you create a component from a core module?** - this is the purpose of + the [`wit-component`] crate, notably the `ComponentEncoder` type. This uses + component type information embedded in the core module and a general set of + conventions/guidelines with what the core module imports/exports. A component + is then hooked up to codify all of these conventions in a component itself. + +* **Why not require users to run `wit-component` themselves?** - while possible + it adds friction to the usage `wasm32-wasip2` target. More importantly though + the "module only" output of the `wasm32-wasip2` target is not ready right now. + The standard library still imports from `wasi_snapshot_preview1` and it will + take time to migrate all usage to WASIp2. + +* **What exactly does this linker do?** - the `wasm-component-ld` has the same + CLI interface and flags as `wasm-ld`, plus some more that are + component-specific. These flags are used to forward most flags to `wasm-ld` to + produce a core wasm module. After the core wasm module is produced the + `wit-component` crate will read custom sections in the final binary which + contain component type information. After merging all this type information + together a component is produced which wraps the core module. + +If you've got any other questions about this linker or its operation don't +hesitate to reach out to the maintainers of the `wasm32-wasip2` target. + +[`wasm-component-ld`]: https://crates.io/crates/wasm-component-ld +[`wit-component`]: https://crates.io/crates/wit-component +[WebAssembly Component]: https://github.com/webassembly/component-model +[component docs]: https://component-model.bytecodealliance.org/ diff --git a/src/tools/wasm-component-ld/src/main.rs b/src/tools/wasm-component-ld/src/main.rs new file mode 100644 index 00000000000..caaac651c4c --- /dev/null +++ b/src/tools/wasm-component-ld/src/main.rs @@ -0,0 +1,9 @@ +// See the `README.md` in this directory for what this tool is. + +// The source for this crate lives at +// https://github.com/bytecodealliance/wasm-component-ld and the binary is +// independently used in other projects such as `wasi-sdk` so the `main` +// function is just reexported here to delegate. A Cargo dependency is used to +// facilitate version management in the Rust repository and work well with +// vendored/offline builds. +use wasm_component_ld::main; diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index 65637a2495d..cfa479aa4b2 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -14,6 +14,14 @@ pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp + // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] o.as_slice() } @@ -25,10 +33,35 @@ pub fn nonzero_u64_opt_as_slice(o: &Option<NonZero<u64>>) -> &[NonZero<u64>] { // CHECK-NOT: switch // CHECK-NOT: icmp // CHECK: %[[NZ:.+]] = icmp ne i64 %{{.+}}, 0 - // CHECK-NEXT: zext i1 %[[NZ]] to i64 + // CHECK-NEXT: %[[LEN:.+]] = zext i1 %[[NZ]] to i64 // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %o, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] o.as_slice() } + +// CHECK-LABEL: @u8_opt_as_slice +#[no_mangle] +pub fn u8_opt_as_slice(o: &Option<u8>) -> &[u8] { + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef + // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 + // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: %[[T0:.+]] = insertvalue { ptr, i64 } poison, ptr %{{.+}}, 0 + // CHECK-NEXT: %[[T1:.+]] = insertvalue { ptr, i64 } %[[T0]], i64 %[[LEN]], 1 + // CHECK-NEXT: ret { ptr, i64 } %[[T1]] + o.as_slice() +} + +// CHECK: ![[META_U64]] = !{i64 0, i64 2} +// CHECK: ![[META_U8]] = !{i8 0, i8 2} diff --git a/tests/crashes/122903-1.rs b/tests/crashes/122903-1.rs index 9323c435851..0953962ed9e 100644 --- a/tests/crashes/122903-1.rs +++ b/tests/crashes/122903-1.rs @@ -1,7 +1,7 @@ //@ known-bug: #122903 impl Struct { - async fn box_box_ref_Struct( - self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>>, + fn box_box_ref_Struct( + self: impl FnMut(Box<impl FnMut(&mut Self)>), ) -> &u32 { f } diff --git a/tests/crashes/122903-2.rs b/tests/crashes/122903-2.rs deleted file mode 100644 index 0d5d93014c1..00000000000 --- a/tests/crashes/122903-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ known-bug: #122903 - -impl Struct { - async fn box_box_ref_Struct( - self: Box<Box<Self, impl FnMut(&mut Box<Box<Self, impl FnMut(&mut Self)>>)>> - ) -> &u32 { - f - } -} diff --git a/tests/crashes/126416.rs b/tests/crashes/126416.rs deleted file mode 100644 index 9b6c5169d44..00000000000 --- a/tests/crashes/126416.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: rust-lang/rust#126416 - -trait Output<'a, T: 'a> { - type Type; -} - -struct Wrapper; - -impl Wrapper { - fn do_something_wrapper<O, F>(&mut self, _: F) - where - F: for<'a> FnOnce(<F as Output<i32>>::Type), - { - } -} - -fn main() { - let mut wrapper = Wrapper; - wrapper.do_something_wrapper(|value| ()); -} diff --git a/tests/crashes/127009.rs b/tests/crashes/127009.rs new file mode 100644 index 00000000000..74ca14393e4 --- /dev/null +++ b/tests/crashes/127009.rs @@ -0,0 +1,11 @@ +//@ known-bug: #127009 + +#![feature(non_lifetime_binders)] + +fn b() +where + for<const C: usize> [(); C]: Copy, +{ +} + +fn main() {} diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff index 801e28ff2f4..069a82b9521 100644 --- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-abort.diff @@ -3,8 +3,8 @@ fn non_const() -> usize { let mut _0: usize; - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; + let _1: fn() -> usize {std::intrinsics::size_of::<T>}; + let mut _2: fn() -> usize {std::intrinsics::size_of::<T>}; scope 1 { debug size_of_t => _1; } diff --git a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff index 801e28ff2f4..069a82b9521 100644 --- a/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.panic-unwind.diff @@ -3,8 +3,8 @@ fn non_const() -> usize { let mut _0: usize; - let _1: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; - let mut _2: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}; + let _1: fn() -> usize {std::intrinsics::size_of::<T>}; + let mut _2: fn() -> usize {std::intrinsics::size_of::<T>}; scope 1 { debug size_of_t => _1; } diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index d937514c2ca..fec4a4bb90b 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -5,14 +5,14 @@ use std::path::PathBuf; -use run_make_support::{aux_build, fs_wrapper, rustc, source_root}; +use run_make_support::{aux_build, rfs, rustc, source_root}; fn main() { aux_build().input("stable.rs").emit("metadata").run(); let output = rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run(); - let version = fs_wrapper::read_to_string(source_root().join("src/version")); + let version = rfs::read_to_string(source_root().join("src/version")); let expected_string = format!("stable since {}", version.trim()); output.assert_stderr_contains(expected_string); } diff --git a/tests/run-make/archive-duplicate-names/Makefile b/tests/run-make/archive-duplicate-names/Makefile deleted file mode 100644 index 207eee39299..00000000000 --- a/tests/run-make/archive-duplicate-names/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# When two object archives with the same filename are present, an iterator is supposed to inspect each object, recognize the duplication and extract each one to a different directory. -# This test checks that this duplicate handling behaviour has not been broken. -# See https://github.com/rust-lang/rust/pull/24439 - -# ignore-cross-compile -include ../tools.mk - -all: - mkdir $(TMPDIR)/a - mkdir $(TMPDIR)/b - $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c) - $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c) - $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o - $(RUSTC) foo.rs - $(RUSTC) bar.rs - $(call RUN,bar) diff --git a/tests/run-make/archive-duplicate-names/rmake.rs b/tests/run-make/archive-duplicate-names/rmake.rs new file mode 100644 index 00000000000..62a35566199 --- /dev/null +++ b/tests/run-make/archive-duplicate-names/rmake.rs @@ -0,0 +1,37 @@ +// When two object archives with the same filename are present, an iterator is supposed to +// inspect each object, recognize the duplication and extract each one to a different directory. +// This test checks that this duplicate handling behaviour has not been broken. +// See https://github.com/rust-lang/rust/pull/24439 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{cc, is_msvc, llvm_ar, rfs, run, rustc}; + +fn main() { + rfs::create_dir("a"); + rfs::create_dir("b"); + compile_obj_force_foo("a", "foo"); + compile_obj_force_foo("b", "bar"); + let mut ar = llvm_ar(); + ar.obj_to_ar().arg("libfoo.a"); + if is_msvc() { + ar.arg("a/foo.obj").arg("b/foo.obj").run(); + } else { + ar.arg("a/foo.o").arg("b/foo.o").run(); + } + rustc().input("foo.rs").run(); + rustc().input("bar.rs").run(); + run("bar"); +} + +#[track_caller] +pub fn compile_obj_force_foo(dir: &str, lib_name: &str) { + let obj_file = if is_msvc() { format!("{dir}/foo") } else { format!("{dir}/foo.o") }; + let src = format!("{lib_name}.c"); + if is_msvc() { + cc().arg("-c").out_exe(&obj_file).input(src).run(); + } else { + cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run(); + }; +} diff --git a/tests/run-make/atomic-lock-free/Makefile b/tests/run-make/atomic-lock-free/Makefile deleted file mode 100644 index 37e59624a25..00000000000 --- a/tests/run-make/atomic-lock-free/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -include ../tools.mk - -# This tests ensure that atomic types are never lowered into runtime library calls that are not -# guaranteed to be lock-free. - -all: -ifeq ($(UNAME),Linux) -ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86) - $(RUSTC) --target=i686-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=x86_64-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -ifeq ($(filter arm,$(LLVM_COMPONENTS)),arm) - $(RUSTC) --target=arm-unknown-linux-gnueabi atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=arm-unknown-linux-gnueabihf atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=armv7-unknown-linux-gnueabihf atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=thumbv7neon-unknown-linux-gnueabihf atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -ifeq ($(filter aarch64,$(LLVM_COMPONENTS)),aarch64) - $(RUSTC) --target=aarch64-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -ifeq ($(filter mips,$(LLVM_COMPONENTS)),mips) - $(RUSTC) --target=mips-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=mipsel-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc) - $(RUSTC) --target=powerpc-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=powerpc-unknown-linux-gnuspe atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=powerpc64-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add - $(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -ifeq ($(filter systemz,$(LLVM_COMPONENTS)),systemz) - $(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs - nm "$(TMPDIR)/libatomic_lock_free.rlib" | $(CGREP) -v __atomic_fetch_add -endif -endif diff --git a/tests/run-make/atomic-lock-free/rmake.rs b/tests/run-make/atomic-lock-free/rmake.rs new file mode 100644 index 00000000000..77e136e8487 --- /dev/null +++ b/tests/run-make/atomic-lock-free/rmake.rs @@ -0,0 +1,52 @@ +// This tests ensure that atomic types are never lowered into runtime library calls that are not +// guaranteed to be lock-free. + +//@ only-linux + +use run_make_support::{llvm_components_contain, llvm_readobj, rustc}; + +fn compile(target: &str) { + rustc().input("atomic_lock_free.rs").target(target).run(); +} + +fn check() { + llvm_readobj() + .symbols() + .input("libatomic_lock_free.rlib") + .run() + .assert_stdout_not_contains("__atomic_fetch_add"); +} + +fn compile_and_check(target: &str) { + compile(target); + check(); +} + +fn main() { + if llvm_components_contain("x86") { + compile_and_check("i686-unknown-linux-gnu"); + compile_and_check("x86_64-unknown-linux-gnu"); + } + if llvm_components_contain("arm") { + compile_and_check("arm-unknown-linux-gnueabi"); + compile_and_check("arm-unknown-linux-gnueabihf"); + compile_and_check("armv7-unknown-linux-gnueabihf"); + compile_and_check("thumbv7neon-unknown-linux-gnueabihf"); + } + if llvm_components_contain("aarch64") { + compile_and_check("aarch64-unknown-linux-gnu"); + } + if llvm_components_contain("mips") { + compile_and_check("mips-unknown-linux-gnu"); + compile_and_check("mipsel-unknown-linux-gnu"); + } + if llvm_components_contain("powerpc") { + compile_and_check("powerpc-unknown-linux-gnu"); + compile_and_check("powerpc-unknown-linux-gnuspe"); + compile_and_check("powerpc64-unknown-linux-gnu"); + compile_and_check("powerpc64le-unknown-linux-gnu"); + } + if llvm_components_contain("systemz") { + compile_and_check("s390x-unknown-linux-gnu"); + } +} diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs index b8ea0b6b345..ab9aa445402 100644 --- a/tests/run-make/c-link-to-rust-dylib/rmake.rs +++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs @@ -3,9 +3,7 @@ //@ ignore-cross-compile -use run_make_support::{ - cc, cwd, dynamic_lib_extension, fs_wrapper, is_msvc, read_dir, run, run_fail, rustc, -}; +use run_make_support::{cc, cwd, dynamic_lib_extension, is_msvc, rfs, run, run_fail, rustc}; fn main() { rustc().input("foo.rs").run(); @@ -21,14 +19,14 @@ fn main() { run("bar"); let expected_extension = dynamic_lib_extension(); - read_dir(cwd(), |path| { + rfs::read_dir_entries(cwd(), |path| { if path.is_file() && path.extension().is_some_and(|ext| ext == expected_extension) && path.file_name().and_then(|name| name.to_str()).is_some_and(|name| { name.ends_with(".so") || name.ends_with(".dll") || name.ends_with(".dylib") }) { - fs_wrapper::remove_file(path); + rfs::remove_file(path); } }); run_fail("bar"); diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs index d60b37524f4..ee35350da66 100644 --- a/tests/run-make/c-link-to-rust-staticlib/rmake.rs +++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs @@ -3,7 +3,7 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper::remove_file; +use run_make_support::rfs::remove_file; use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; use std::fs; diff --git a/tests/run-make/cdylib/rmake.rs b/tests/run-make/cdylib/rmake.rs index 55ea227ab51..21b83d1b1a9 100644 --- a/tests/run-make/cdylib/rmake.rs +++ b/tests/run-make/cdylib/rmake.rs @@ -10,7 +10,7 @@ //@ ignore-cross-compile -use run_make_support::{cc, cwd, dynamic_lib_name, fs_wrapper, is_msvc, run, rustc}; +use run_make_support::{cc, cwd, dynamic_lib_name, is_msvc, rfs, run, rustc}; fn main() { rustc().input("bar.rs").run(); @@ -23,7 +23,7 @@ fn main() { } run("foo"); - fs_wrapper::remove_file(dynamic_lib_name("foo")); + rfs::remove_file(dynamic_lib_name("foo")); rustc().input("foo.rs").arg("-Clto").run(); run("foo"); diff --git a/tests/run-make/comment-section/rmake.rs b/tests/run-make/comment-section/rmake.rs index 188c6dcb25d..a16adea7162 100644 --- a/tests/run-make/comment-section/rmake.rs +++ b/tests/run-make/comment-section/rmake.rs @@ -10,8 +10,9 @@ use std::path::PathBuf; use run_make_support::llvm_readobj; +use run_make_support::rfs; use run_make_support::rustc; -use run_make_support::{cwd, env_var, read_dir, run_in_tmpdir}; +use run_make_support::{cwd, env_var, run_in_tmpdir}; fn main() { let target = env_var("TARGET"); @@ -33,7 +34,7 @@ fn main() { // Check all object files (including temporary outputs) have a `.comment` // section with the expected content. - read_dir(cwd(), |f| { + rfs::read_dir_entries(cwd(), |f| { if !f.extension().is_some_and(|ext| ext == "o") { return; } diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index 10ff9cd282d..43d1d69b245 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -14,12 +14,12 @@ #![deny(warnings)] -use run_make_support::fs_wrapper::{read, read_dir}; use run_make_support::object::read::archive::ArchiveFile; use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; use run_make_support::object::ObjectSymbol; use run_make_support::object::RelocationTarget; +use run_make_support::rfs::{read, read_dir}; use run_make_support::{cmd, env_var, object}; use std::collections::HashSet; use std::path::PathBuf; diff --git a/tests/run-make/compiler-lookup-paths/Makefile b/tests/run-make/compiler-lookup-paths/Makefile deleted file mode 100644 index fc0cbde4c35..00000000000 --- a/tests/run-make/compiler-lookup-paths/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# rustc supports different types of lookup paths, such as dependency, native or crate. This test checks that these lookup paths are functional and result in functional compilation. -# See https://github.com/rust-lang/rust/pull/19941 - -include ../tools.mk - -# ignore-wasm32 (need a C compiler) -# ignore-wasm64 (need a C compiler) - -all: $(TMPDIR)/libnative.a - mkdir -p $(TMPDIR)/crate - mkdir -p $(TMPDIR)/native - mv $(TMPDIR)/libnative.a $(TMPDIR)/native - $(RUSTC) a.rs - mv $(TMPDIR)/liba.rlib $(TMPDIR)/crate - $(RUSTC) b.rs -L native=$(TMPDIR)/crate && exit 1 || exit 0 - $(RUSTC) b.rs -L dependency=$(TMPDIR)/crate && exit 1 || exit 0 - $(RUSTC) b.rs -L crate=$(TMPDIR)/crate - $(RUSTC) b.rs -L all=$(TMPDIR)/crate - $(RUSTC) c.rs -L native=$(TMPDIR)/crate && exit 1 || exit 0 - $(RUSTC) c.rs -L crate=$(TMPDIR)/crate && exit 1 || exit 0 - $(RUSTC) c.rs -L dependency=$(TMPDIR)/crate - $(RUSTC) c.rs -L all=$(TMPDIR)/crate - $(RUSTC) d.rs -L dependency=$(TMPDIR)/native && exit 1 || exit 0 - $(RUSTC) d.rs -L crate=$(TMPDIR)/native && exit 1 || exit 0 - $(RUSTC) d.rs -L native=$(TMPDIR)/native - $(RUSTC) d.rs -L all=$(TMPDIR)/native - # Deduplication tests: - # Same hash, no errors. - mkdir -p $(TMPDIR)/e1 - mkdir -p $(TMPDIR)/e2 - $(RUSTC) e.rs -o $(TMPDIR)/e1/libe.rlib - $(RUSTC) e.rs -o $(TMPDIR)/e2/libe.rlib - $(RUSTC) f.rs -L $(TMPDIR)/e1 -L $(TMPDIR)/e2 - $(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L $(TMPDIR)/e2 - $(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2 - # Different hash, errors. - $(RUSTC) e2.rs -o $(TMPDIR)/e2/libe.rlib - $(RUSTC) f.rs -L $(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0 - $(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L $(TMPDIR)/e2 && exit 1 || exit 0 - $(RUSTC) f.rs -L crate=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2 && exit 1 || exit 0 - # Native/dependency paths don't cause errors. - $(RUSTC) f.rs -L native=$(TMPDIR)/e1 -L $(TMPDIR)/e2 - $(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L $(TMPDIR)/e2 - $(RUSTC) f.rs -L dependency=$(TMPDIR)/e1 -L crate=$(TMPDIR)/e2 diff --git a/tests/run-make/compiler-lookup-paths/rmake.rs b/tests/run-make/compiler-lookup-paths/rmake.rs new file mode 100644 index 00000000000..3ffa6e0592f --- /dev/null +++ b/tests/run-make/compiler-lookup-paths/rmake.rs @@ -0,0 +1,84 @@ +// Since #19941, rustc can accept specifications on its library search paths. +// This test runs Rust programs with varied library dependencies, expecting them +// to succeed or fail depending on the situation. +// The second part of the tests also checks that libraries with an incorrect hash +// fail to be used by the compiler. +// See https://github.com/rust-lang/rust/pull/19941 + +//@ ignore-wasm32 +//@ ignore-wasm64 +// Reason: a C compiler is required for build_native_static_lib + +use run_make_support::{build_native_static_lib, rfs, rustc, static_lib_name}; + +fn main() { + build_native_static_lib("native"); + let lib_native = static_lib_name("native"); + rfs::create_dir_all("crate"); + rfs::create_dir_all("native"); + rfs::rename(&lib_native, format!("native/{}", &lib_native)); + rustc().input("a.rs").run(); + rfs::rename("liba.rlib", "crate/liba.rlib"); + rustc().input("b.rs").specific_library_search_path("native", "crate").run_fail(); + rustc().input("b.rs").specific_library_search_path("dependency", "crate").run_fail(); + rustc().input("b.rs").specific_library_search_path("crate", "crate").run(); + rustc().input("b.rs").specific_library_search_path("all", "crate").run(); + + rustc().input("c.rs").specific_library_search_path("native", "crate").run_fail(); + rustc().input("c.rs").specific_library_search_path("crate", "crate").run_fail(); + rustc().input("c.rs").specific_library_search_path("dependency", "crate").run(); + rustc().input("c.rs").specific_library_search_path("all", "crate").run(); + + rustc().input("d.rs").specific_library_search_path("dependency", "native").run_fail(); + rustc().input("d.rs").specific_library_search_path("crate", "native").run_fail(); + rustc().input("d.rs").specific_library_search_path("native", "native").run(); + rustc().input("d.rs").specific_library_search_path("all", "native").run(); + + // Deduplication tests. + rfs::create_dir_all("e1"); + rfs::create_dir_all("e2"); + + rustc().input("e.rs").output("e1/libe.rlib").run(); + rustc().input("e.rs").output("e2/libe.rlib").run(); + // If the library hash is correct, compilation should succeed. + rustc().input("f.rs").library_search_path("e1").library_search_path("e2").run(); + rustc() + .input("f.rs") + .specific_library_search_path("crate", "e1") + .library_search_path("e2") + .run(); + rustc() + .input("f.rs") + .specific_library_search_path("crate", "e1") + .specific_library_search_path("crate", "e2") + .run(); + // If the library has a different hash, errors should occur. + rustc().input("e2.rs").output("e2/libe.rlib").run(); + rustc().input("f.rs").library_search_path("e1").library_search_path("e2").run_fail(); + rustc() + .input("f.rs") + .specific_library_search_path("crate", "e1") + .library_search_path("e2") + .run_fail(); + rustc() + .input("f.rs") + .specific_library_search_path("crate", "e1") + .specific_library_search_path("crate", "e2") + .run_fail(); + // Native and dependency paths do not cause errors. + rustc() + .input("f.rs") + .specific_library_search_path("native", "e1") + .library_search_path("e2") + .run(); + rustc() + .input("f.rs") + .specific_library_search_path("dependency", "e1") + .library_search_path("e2") + .run(); + rustc() + .input("f.rs") + .specific_library_search_path("dependency", "e1") + .specific_library_search_path("crate", "e2") + .run(); +} diff --git a/tests/run-make/const-prop-lint/rmake.rs b/tests/run-make/const-prop-lint/rmake.rs index d194f70d916..17e4b0c77f3 100644 --- a/tests/run-make/const-prop-lint/rmake.rs +++ b/tests/run-make/const-prop-lint/rmake.rs @@ -1,11 +1,11 @@ // Tests that const prop lints interrupting codegen don't leave `.o` files around. -use run_make_support::{cwd, fs_wrapper, rustc}; +use run_make_support::{cwd, rfs, rustc}; fn main() { rustc().input("input.rs").run_fail().assert_exit_code(1); - for entry in fs_wrapper::read_dir(cwd()) { + for entry in rfs::read_dir(cwd()) { let entry = entry.unwrap(); let path = entry.path(); diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs index b7cb2c99711..5bdb49b33ce 100644 --- a/tests/run-make/crate-name-priority/rmake.rs +++ b/tests/run-make/crate-name-priority/rmake.rs @@ -4,15 +4,15 @@ // and the compiler flags, and checks that the flag is favoured each time. // See https://github.com/rust-lang/rust/pull/15518 -use run_make_support::{bin_name, fs_wrapper, rustc}; +use run_make_support::{bin_name, rfs, rustc}; fn main() { rustc().input("foo.rs").run(); - fs_wrapper::remove_file(bin_name("foo")); + rfs::remove_file(bin_name("foo")); rustc().input("foo.rs").crate_name("bar").run(); - fs_wrapper::remove_file(bin_name("bar")); + rfs::remove_file(bin_name("bar")); rustc().input("foo1.rs").run(); - fs_wrapper::remove_file(bin_name("foo")); + rfs::remove_file(bin_name("foo")); rustc().input("foo1.rs").output(bin_name("bar1")).run(); - fs_wrapper::remove_file(bin_name("bar1")); + rfs::remove_file(bin_name("bar1")); } diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index e48c8a0cef3..6bff5c0c8d0 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -1,7 +1,7 @@ // Check that valid binaries are persisted by running them, regardless of whether the // --run or --no-run option is used. -use run_make_support::fs_wrapper::{create_dir, remove_dir_all}; +use run_make_support::rfs::{create_dir, remove_dir_all}; use run_make_support::{run, rustc, rustdoc}; use std::path::Path; diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 5208730d336..5d829b9e88b 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,6 +1,6 @@ // Tests behavior of rustdoc `--runtool`. -use run_make_support::fs_wrapper::{create_dir, remove_dir_all}; +use run_make_support::rfs::{create_dir, remove_dir_all}; use run_make_support::{rustc, rustdoc}; use std::path::PathBuf; diff --git a/tests/run-make/dump-mono-stats/Makefile b/tests/run-make/dump-mono-stats/Makefile deleted file mode 100644 index 196f84be6ec..00000000000 --- a/tests/run-make/dump-mono-stats/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --crate-type lib foo.rs -Z dump-mono-stats=$(TMPDIR) -Zdump-mono-stats-format=json - cat $(TMPDIR)/foo.mono_items.json | $(CGREP) '"name":"bar"' diff --git a/tests/run-make/dump-mono-stats/rmake.rs b/tests/run-make/dump-mono-stats/rmake.rs new file mode 100644 index 00000000000..f4142e0a31c --- /dev/null +++ b/tests/run-make/dump-mono-stats/rmake.rs @@ -0,0 +1,17 @@ +// A flag named dump-mono-stats was added to the compiler in 2022, which +// collects stats on instantiation of items and their associated costs. +// This test checks that the output stat file exists, and that it contains +// a specific expected string. +// See https://github.com/rust-lang/rust/pull/105481 + +use run_make_support::{cwd, rfs, rustc}; + +fn main() { + rustc() + .crate_type("lib") + .input("foo.rs") + .arg(format!("-Zdump-mono-stats={}", cwd().display())) + .arg("-Zdump-mono-stats-format=json") + .run(); + assert!(rfs::read_to_string("foo.mono_items.json").contains(r#""name":"bar""#)); +} diff --git a/tests/run-make/dylib-chain/rmake.rs b/tests/run-make/dylib-chain/rmake.rs index a96cc350875..54d53d47092 100644 --- a/tests/run-make/dylib-chain/rmake.rs +++ b/tests/run-make/dylib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc}; fn main() { rustc().input("m1.rs").arg("-Cprefer-dynamic").run(); @@ -16,8 +16,8 @@ fn main() { rustc().input("m3.rs").arg("-Cprefer-dynamic").run(); rustc().input("m4.rs").run(); run("m4"); - fs_wrapper::remove_file(dynamic_lib_name("m1")); - fs_wrapper::remove_file(dynamic_lib_name("m2")); - fs_wrapper::remove_file(dynamic_lib_name("m3")); + rfs::remove_file(dynamic_lib_name("m1")); + rfs::remove_file(dynamic_lib_name("m2")); + rfs::remove_file(dynamic_lib_name("m3")); run_fail("m4"); } diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index a02c97fec4c..1570e1adc25 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -1,6 +1,6 @@ use std::path::Path; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); @@ -11,7 +11,7 @@ fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { fn main() { let out_dir = Path::new("emit"); - fs_wrapper::create_dir(&out_dir); + rfs::create_dir(&out_dir); emit_and_check(&out_dir, "libfoo.s", "asm"); emit_and_check(&out_dir, "libfoo.bc", "llvm-bc"); diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs index ce56c197588..a97153e37dd 100644 --- a/tests/run-make/emit-path-unhashed/rmake.rs +++ b/tests/run-make/emit-path-unhashed/rmake.rs @@ -6,13 +6,13 @@ // adding a new output type (in this test, metadata). // See https://github.com/rust-lang/rust/issues/86044 -use run_make_support::{diff, fs_wrapper, rustc}; +use run_make_support::{diff, rfs, rustc}; fn main() { - fs_wrapper::create_dir("emit"); - fs_wrapper::create_dir("emit/a"); - fs_wrapper::create_dir("emit/b"); - fs_wrapper::create_dir("emit/c"); + rfs::create_dir("emit"); + rfs::create_dir("emit/a"); + rfs::create_dir("emit/b"); + rfs::create_dir("emit/c"); // The default output name. rustc().emit("link").input("foo.rs").run(); // The output is named with the output flag. diff --git a/tests/run-make/extern-flag-pathless/rmake.rs b/tests/run-make/extern-flag-pathless/rmake.rs index 9cf828abcb8..ec380feae46 100644 --- a/tests/run-make/extern-flag-pathless/rmake.rs +++ b/tests/run-make/extern-flag-pathless/rmake.rs @@ -8,21 +8,21 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("rlib").crate_type("dylib").arg("-Cprefer-dynamic").run(); // By default, the rlib has priority over the dylib. rustc().input("foo.rs").arg("--extern").arg("bar").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); rustc().input("foo.rs").extern_("bar", rust_lib_name("bar")).arg("--extern").arg("bar").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); // The first explicit usage of extern overrides the second pathless --extern bar. rustc() @@ -31,13 +31,13 @@ fn main() { .arg("--extern") .arg("bar") .run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run_fail("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); // With prefer-dynamic, execution fails as it refuses to use the rlib. rustc().input("foo.rs").arg("--extern").arg("bar").arg("-Cprefer-dynamic").run(); - fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp"); + rfs::rename(dynamic_lib_name("bar"), "bar.tmp"); run_fail("foo"); - fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar")); + rfs::rename("bar.tmp", dynamic_lib_name("bar")); } diff --git a/tests/run-make/extern-fn-explicit-align/Makefile b/tests/run-make/extern-fn-explicit-align/Makefile deleted file mode 100644 index 3cbbf383996..00000000000 --- a/tests/run-make/extern-fn-explicit-align/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-explicit-align/rmake.rs b/tests/run-make/extern-fn-explicit-align/rmake.rs new file mode 100644 index 00000000000..fb153f92103 --- /dev/null +++ b/tests/run-make/extern-fn-explicit-align/rmake.rs @@ -0,0 +1,17 @@ +// The compiler's rules of alignment for indirectly passed values in a 16-byte aligned argument, +// in a C external function, used to be arbitrary. Unexpected behavior would occasionally occur +// and cause memory corruption. This was fixed in #112157, streamlining the way alignment occurs, +// and this test reproduces the case featured in the issue, checking that it compiles and executes +// successfully. +// See https://github.com/rust-lang/rust/issues/80127 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extern-fn-mangle/Makefile b/tests/run-make/extern-fn-mangle/Makefile deleted file mode 100644 index 3cbbf383996..00000000000 --- a/tests/run-make/extern-fn-mangle/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-mangle/rmake.rs b/tests/run-make/extern-fn-mangle/rmake.rs new file mode 100644 index 00000000000..3db8b2a0db0 --- /dev/null +++ b/tests/run-make/extern-fn-mangle/rmake.rs @@ -0,0 +1,16 @@ +// In this test, the functions foo() and bar() must avoid being mangled, as +// the external C function depends on them to return the correct sum of 3 + 5 = 8. +// This test therefore checks that the compiled and executed program respects the +// #[no_mangle] flags successfully. +// See https://github.com/rust-lang/rust/pull/15831 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extern-fn-slice-no-ice/rmake.rs b/tests/run-make/extern-fn-slice-no-ice/rmake.rs new file mode 100644 index 00000000000..1f1bbd33127 --- /dev/null +++ b/tests/run-make/extern-fn-slice-no-ice/rmake.rs @@ -0,0 +1,17 @@ +// Slices were broken when implicated in foreign-function interface (FFI) with +// a C library, with something as simple as measuring the length or returning +// an item at a certain index of a slice would cause an internal compiler error (ICE). +// This was fixed in #25653, and this test checks that slices in Rust-C FFI can be part +// of a program that compiles and executes successfully. +// See https://github.com/rust-lang/rust/issues/25581 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/issue-25581/test.c b/tests/run-make/extern-fn-slice-no-ice/test.c index 52fbf78510a..52fbf78510a 100644 --- a/tests/run-make/issue-25581/test.c +++ b/tests/run-make/extern-fn-slice-no-ice/test.c diff --git a/tests/run-make/issue-25581/test.rs b/tests/run-make/extern-fn-slice-no-ice/test.rs index ba6749c9722..ba6749c9722 100644 --- a/tests/run-make/issue-25581/test.rs +++ b/tests/run-make/extern-fn-slice-no-ice/test.rs diff --git a/tests/run-make/extern-fn-struct-passing-abi/Makefile b/tests/run-make/extern-fn-struct-passing-abi/Makefile deleted file mode 100644 index 3cbbf383996..00000000000 --- a/tests/run-make/extern-fn-struct-passing-abi/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-struct-passing-abi/rmake.rs b/tests/run-make/extern-fn-struct-passing-abi/rmake.rs new file mode 100644 index 00000000000..5c4ddb7f58e --- /dev/null +++ b/tests/run-make/extern-fn-struct-passing-abi/rmake.rs @@ -0,0 +1,16 @@ +// Functions with more than 6 arguments using foreign function interfaces (FFI) with C libraries +// would have their arguments unexpectedly swapped, causing unexpected behaviour in Rust-C FFI +// programs. This test compiles and executes Rust code with bulky functions of up to 7 arguments +// and uses assertions to check for unexpected swaps. +// See https://github.com/rust-lang/rust/issues/25594 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extern-fn-with-extern-types/Makefile b/tests/run-make/extern-fn-with-extern-types/Makefile deleted file mode 100644 index 07ec503aaae..00000000000 --- a/tests/run-make/extern-fn-with-extern-types/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,ctest) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-with-extern-types/rmake.rs b/tests/run-make/extern-fn-with-extern-types/rmake.rs new file mode 100644 index 00000000000..02521ae2cdb --- /dev/null +++ b/tests/run-make/extern-fn-with-extern-types/rmake.rs @@ -0,0 +1,16 @@ +// This test checks the functionality of foreign function interface (FFI) where Rust +// must call upon a C library defining functions, where these functions also use custom +// types defined by the C file. In addition to compilation being successful, the binary +// should also successfully execute. +// See https://github.com/rust-lang/rust/pull/44295 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("ctest"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extern-fn-with-packed-struct/Makefile b/tests/run-make/extern-fn-with-packed-struct/Makefile deleted file mode 100644 index 3cbbf383996..00000000000 --- a/tests/run-make/extern-fn-with-packed-struct/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-with-packed-struct/rmake.rs b/tests/run-make/extern-fn-with-packed-struct/rmake.rs new file mode 100644 index 00000000000..e6d8cecd24a --- /dev/null +++ b/tests/run-make/extern-fn-with-packed-struct/rmake.rs @@ -0,0 +1,17 @@ +// Packed structs, in C, occupy less bytes in memory, but are more +// vulnerable to alignment errors. Passing them around in a Rust-C foreign +// function interface (FFI) would cause unexpected behavior, until this was +// fixed in #16584. This test checks that a Rust program with a C library +// compiles and executes successfully, even with usage of a packed struct. +// See https://github.com/rust-lang/rust/issues/16574 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs index c39e397a7cb..0910045bb85 100644 --- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs +++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs @@ -6,9 +6,7 @@ // are named as expected. // See https://github.com/rust-lang/rust/pull/15686 -use run_make_support::{ - bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files, -}; +use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files}; fn main() { rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run(); @@ -16,6 +14,6 @@ fn main() { has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o") }); let object_file = object_files.get(0).unwrap(); - fs_wrapper::remove_file(object_file); - fs_wrapper::remove_file(bin_name("foobar")); + rfs::remove_file(object_file); + rfs::remove_file(bin_name("foobar")); } diff --git a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs index 33c755bddd7..8ba3a0366b0 100644 --- a/tests/run-make/ice-dep-cannot-find-dep/rmake.rs +++ b/tests/run-make/ice-dep-cannot-find-dep/rmake.rs @@ -16,7 +16,7 @@ // If we used `rustc` the additional '-L rmake_out' option would allow rustc to // actually find the crate. -use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{bare_rustc, rfs, rust_lib_name, rustc}; fn main() { rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run(); diff --git a/tests/run-make/issue-85401-static-mir/bar.rs b/tests/run-make/ice-static-mir/bar.rs index 15b12ecf36f..15b12ecf36f 100644 --- a/tests/run-make/issue-85401-static-mir/bar.rs +++ b/tests/run-make/ice-static-mir/bar.rs diff --git a/tests/run-make/issue-85401-static-mir/baz.rs b/tests/run-make/ice-static-mir/baz.rs index 2ff4c51e5d2..2ff4c51e5d2 100644 --- a/tests/run-make/issue-85401-static-mir/baz.rs +++ b/tests/run-make/ice-static-mir/baz.rs diff --git a/tests/run-make/issue-85401-static-mir/foo.rs b/tests/run-make/ice-static-mir/foo.rs index d064c454600..d064c454600 100644 --- a/tests/run-make/issue-85401-static-mir/foo.rs +++ b/tests/run-make/ice-static-mir/foo.rs diff --git a/tests/run-make/ice-static-mir/rmake.rs b/tests/run-make/ice-static-mir/rmake.rs new file mode 100644 index 00000000000..2d4ffa379b6 --- /dev/null +++ b/tests/run-make/ice-static-mir/rmake.rs @@ -0,0 +1,42 @@ +// Trying to access mid-level internal representation (MIR) in statics +// used to cause an internal compiler error (ICE), now handled as a proper +// error since #100211. This test checks that the correct error is printed +// during the linking process, and not the ICE. +// See https://github.com/rust-lang/rust/issues/85401 + +use run_make_support::{bin_name, rust_lib_name, rustc}; + +fn main() { + rustc() + .crate_type("rlib") + .crate_name("foo") + .arg("-Crelocation-model=pic") + .edition("2018") + .input("foo.rs") + .arg("-Zalways-encode-mir=yes") + .emit("metadata") + .output("libfoo.rmeta") + .run(); + rustc() + .crate_type("rlib") + .crate_name("bar") + .arg("-Crelocation-model=pic") + .edition("2018") + .input("bar.rs") + .output(rust_lib_name("bar")) + .extern_("foo", "libfoo.rmeta") + .run(); + rustc() + .crate_type("bin") + .crate_name("baz") + .arg("-Crelocation-model=pic") + .edition("2018") + .input("baz.rs") + .output(bin_name("baz")) + .extern_("bar", rust_lib_name("bar")) + .run_fail() + .assert_stderr_contains( + "crate `foo` required to be available in rlib format, but was not found in this form", + ) + .assert_stdout_not_contains("internal compiler error"); +} diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index 62b8479c328..b6624f37f96 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -24,11 +24,11 @@ // Reason: `set_readonly` has no effect on directories // and does not prevent modification. -use run_make_support::{fs_wrapper, rustc, test_while_readonly}; +use run_make_support::{rfs, rustc, test_while_readonly}; fn main() { // Create an inaccessible directory. - fs_wrapper::create_dir("inaccessible"); + rfs::create_dir("inaccessible"); test_while_readonly("inaccessible", || { // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, // so that it can't create `tmp`. diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index e6d6ae95aaa..14e75671df8 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -13,14 +13,14 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for `std` -use run_make_support::fs_wrapper as fs; +use run_make_support::rfs; use run_make_support::rustc; fn main() { - fs::create_dir("src"); - fs::create_dir("incr"); - fs::copy("a.rs", "src/main.rs"); + rfs::create_dir("src"); + rfs::create_dir("incr"); + rfs::copy("a.rs", "src/main.rs"); rustc().incremental("incr").input("src/main.rs").run(); - fs::copy("b.rs", "src/main.rs"); + rfs::copy("b.rs", "src/main.rs"); rustc().incremental("incr").input("src/main.rs").run(); } diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs index ae142a0d22e..f314e110a8c 100644 --- a/tests/run-make/incr-test-moved-file/rmake.rs +++ b/tests/run-make/incr-test-moved-file/rmake.rs @@ -14,14 +14,14 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{rfs, rust_lib_name, rustc}; fn main() { - fs_wrapper::create_dir("incr"); - fs_wrapper::create_dir("src"); - fs_wrapper::create_dir("src/mydir"); - fs_wrapper::copy("main.rs", "src/main.rs"); + rfs::create_dir("incr"); + rfs::create_dir("src"); + rfs::create_dir("src/mydir"); + rfs::copy("main.rs", "src/main.rs"); rustc().input("src/main.rs").incremental("incr").arg("--test").run(); - fs_wrapper::rename("src/main.rs", "src/mydir/main.rs"); + rfs::rename("src/main.rs", "src/mydir/main.rs"); rustc().input("src/mydir/main.rs").incremental("incr").arg("--test").run(); } diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs index 1ef3af87353..985816ff5d7 100644 --- a/tests/run-make/incremental-debugger-visualizer/rmake.rs +++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs @@ -2,14 +2,14 @@ // (in this case, foo.py and foo.natvis) are picked up when compiling incrementally. // See https://github.com/rust-lang/rust/pull/111641 -use run_make_support::{fs_wrapper, invalid_utf8_contains, invalid_utf8_not_contains, rustc}; +use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rfs, rustc}; use std::io::Read; fn main() { - fs_wrapper::create_file("foo.py"); - fs_wrapper::write("foo.py", "GDB script v1"); - fs_wrapper::create_file("foo.natvis"); - fs_wrapper::write("foo.natvis", "Natvis v1"); + rfs::create_file("foo.py"); + rfs::write("foo.py", "GDB script v1"); + rfs::create_file("foo.natvis"); + rfs::write("foo.natvis", "Natvis v1"); rustc() .input("foo.rs") .crate_type("rlib") @@ -22,9 +22,9 @@ fn main() { invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); // Change only the GDB script and check that the change has been picked up - fs_wrapper::remove_file("foo.py"); - fs_wrapper::create_file("foo.py"); - fs_wrapper::write("foo.py", "GDB script v2"); + rfs::remove_file("foo.py"); + rfs::create_file("foo.py"); + rfs::write("foo.py", "GDB script v2"); rustc() .input("foo.rs") .crate_type("rlib") @@ -38,9 +38,9 @@ fn main() { invalid_utf8_contains("libfoo.rmeta", "Natvis v1"); // Now change the Natvis version and check that the change has been picked up - fs_wrapper::remove_file("foo.natvis"); - fs_wrapper::create_file("foo.natvis"); - fs_wrapper::write("foo.natvis", "Natvis v2"); + rfs::remove_file("foo.natvis"); + rfs::create_file("foo.natvis"); + rfs::write("foo.natvis", "Natvis v2"); rustc() .input("foo.rs") .crate_type("rlib") diff --git a/tests/run-make/incremental-session-fail/rmake.rs b/tests/run-make/incremental-session-fail/rmake.rs index 0283709f2cf..c6927c8a9f1 100644 --- a/tests/run-make/incremental-session-fail/rmake.rs +++ b/tests/run-make/incremental-session-fail/rmake.rs @@ -4,10 +4,10 @@ // the ensuing compilation failure is not an ICE. // See https://github.com/rust-lang/rust/pull/85698 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { - fs_wrapper::create_file("session"); + rfs::create_file("session"); // rustc should fail to create the session directory here. let out = rustc().input("foo.rs").crate_type("rlib").incremental("session").run_fail(); out.assert_stderr_contains("could not create incremental compilation crate directory"); diff --git a/tests/run-make/inline-always-many-cgu/rmake.rs b/tests/run-make/inline-always-many-cgu/rmake.rs index c55ea69f3b9..5a6929c855b 100644 --- a/tests/run-make/inline-always-many-cgu/rmake.rs +++ b/tests/run-make/inline-always-many-cgu/rmake.rs @@ -1,6 +1,6 @@ -use run_make_support::fs_wrapper::read_to_string; use run_make_support::regex::Regex; -use run_make_support::{read_dir, rustc}; +use run_make_support::rfs; +use run_make_support::rustc; use std::ffi::OsStr; @@ -8,9 +8,9 @@ fn main() { rustc().input("foo.rs").emit("llvm-ir").codegen_units(2).run(); let re = Regex::new(r"\bcall\b").unwrap(); let mut nb_ll = 0; - read_dir(".", |path| { + rfs::read_dir_entries(".", |path| { if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) { - assert!(!re.is_match(&read_to_string(path))); + assert!(!re.is_match(&rfs::read_to_string(path))); nb_ll += 1; } }); diff --git a/tests/run-make/intrinsic-unreachable/rmake.rs b/tests/run-make/intrinsic-unreachable/rmake.rs index 7e78c8288b8..bb189fbdcb5 100644 --- a/tests/run-make/intrinsic-unreachable/rmake.rs +++ b/tests/run-make/intrinsic-unreachable/rmake.rs @@ -8,13 +8,13 @@ //@ ignore-windows // Reason: Because of Windows exception handling, the code is not necessarily any shorter. -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rustc().opt().emit("asm").input("exit-ret.rs").run(); rustc().opt().emit("asm").input("exit-unreachable.rs").run(); assert!( - fs_wrapper::read_to_string("exit-unreachable.s").lines().count() - < fs_wrapper::read_to_string("exit-ret.s").lines().count() + rfs::read_to_string("exit-unreachable.s").lines().count() + < rfs::read_to_string("exit-ret.s").lines().count() ); } diff --git a/tests/run-make/invalid-library/rmake.rs b/tests/run-make/invalid-library/rmake.rs index 750fcd05c8a..42afb74a59e 100644 --- a/tests/run-make/invalid-library/rmake.rs +++ b/tests/run-make/invalid-library/rmake.rs @@ -1,8 +1,14 @@ -use run_make_support::fs_wrapper::create_file; -use run_make_support::{ar, rustc}; +// When the metadata format changes, old libraries used to cause librustc to abort +// when reading their metadata. The error message for this scenario was unhelpful at best. +// A better error message was implemented in #12645, and this test checks that it is the +// one appearing in stderr in this scenario. +// See https://github.com/rust-lang/rust/pull/12645 + +use run_make_support::rfs; +use run_make_support::{llvm_ar, rustc}; fn main() { - create_file("lib.rmeta"); - ar(&["lib.rmeta"], "libfoo-ffffffff-1.0.rlib"); + rfs::create_file("lib.rmeta"); + llvm_ar().obj_to_ar().output_input("libfoo-ffffffff-1.0.rlib", "lib.rmeta").run(); rustc().input("foo.rs").run_fail().assert_stderr_contains("found invalid metadata"); } diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs index 5cfda05334e..754c53a49b9 100644 --- a/tests/run-make/invalid-so/rmake.rs +++ b/tests/run-make/invalid-so/rmake.rs @@ -4,10 +4,10 @@ // explains that the file exists, but that its metadata is incorrect. // See https://github.com/rust-lang/rust/pull/88368 -use run_make_support::{dynamic_lib_name, fs_wrapper, rustc}; +use run_make_support::{dynamic_lib_name, rfs, rustc}; fn main() { - fs_wrapper::create_file(dynamic_lib_name("foo")); + rfs::create_file(dynamic_lib_name("foo")); rustc() .crate_type("lib") .extern_("foo", dynamic_lib_name("foo")) diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs index 45129293247..ba9e07dd07b 100644 --- a/tests/run-make/invalid-staticlib/rmake.rs +++ b/tests/run-make/invalid-staticlib/rmake.rs @@ -4,10 +4,10 @@ // an internal compiler error (ICE). // See https://github.com/rust-lang/rust/pull/28673 -use run_make_support::{fs_wrapper, rustc, static_lib_name}; +use run_make_support::{rfs, rustc, static_lib_name}; fn main() { - fs_wrapper::create_file(static_lib_name("foo")); + rfs::create_file(static_lib_name("foo")); rustc() .arg("-") .crate_type("rlib") diff --git a/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs b/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs new file mode 100644 index 00000000000..58c3e33bb6c --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs @@ -0,0 +1,5 @@ +extern crate foo; + +pub fn main() { + let _ = foo::hello_world(); +} diff --git a/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs b/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs new file mode 100644 index 00000000000..07b66f8ca45 --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs @@ -0,0 +1,3 @@ +pub fn hello_world() -> i32 { + 42 +} diff --git a/tests/run-make/invalid-symlink-search-path/rmake.rs b/tests/run-make/invalid-symlink-search-path/rmake.rs new file mode 100644 index 00000000000..ed2cd9c4bd2 --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/rmake.rs @@ -0,0 +1,33 @@ +// In this test, the symlink created is invalid (valid relative to the root, but not +// relatively to where it is located), and used to cause an internal +// compiler error (ICE) when passed as a library search path. This was fixed in #26044, +// and this test checks that the invalid symlink is instead simply ignored. +// See https://github.com/rust-lang/rust/issues/26006 + +//@ needs-symlink +//Reason: symlink requires elevated permission in Windows + +use run_make_support::{rfs, rustc}; + +fn main() { + // We create two libs: `bar` which depends on `foo`. We need to compile `foo` first. + rfs::create_dir("out"); + rfs::create_dir("out/foo"); + rustc() + .input("in/foo/lib.rs") + .crate_name("foo") + .crate_type("lib") + .metadata("foo") + .output("out/foo/libfoo.rlib") + .run(); + rfs::create_dir("out/bar"); + rfs::create_dir("out/bar/deps"); + rfs::create_symlink("out/foo/libfoo.rlib", "out/bar/deps/libfoo.rlib"); + // Check that the invalid symlink does not cause an ICE + rustc() + .input("in/bar/lib.rs") + .library_search_path("dependency=out/bar/deps") + .run_fail() + .assert_exit_code(1) + .assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index ee281fe0a5f..f47b8d7190f 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -3,7 +3,7 @@ #[cfg(unix)] extern crate libc; -use run_make_support::{aux_build, fs_wrapper}; +use run_make_support::{aux_build, rfs}; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; @@ -20,7 +20,7 @@ fn main() { } fn verify(path: &Path) { - let perm = fs_wrapper::metadata(path).permissions(); + let perm = rfs::metadata(path).permissions(); assert!(!perm.readonly()); diff --git a/tests/run-make/issue-18943/Makefile b/tests/run-make/issue-18943/Makefile deleted file mode 100644 index fc40d756d6f..00000000000 --- a/tests/run-make/issue-18943/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# Regression test for ICE #18943 when compiling as lib - -all: - $(RUSTC) foo.rs --crate-type lib - $(call REMOVE_RLIBS,foo) && exit 0 || exit 1 diff --git a/tests/run-make/issue-22131/Makefile b/tests/run-make/issue-22131/Makefile deleted file mode 100644 index 4f33a4659cc..00000000000 --- a/tests/run-make/issue-22131/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: foo.rs - $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs - $(RUSTDOC) --test --cfg 'feature="bar"' \ - -L $(TMPDIR) foo.rs |\ - $(CGREP) 'foo.rs - foo (line 1) ... ok' diff --git a/tests/run-make/issue-25581/Makefile b/tests/run-make/issue-25581/Makefile deleted file mode 100644 index 3cbbf383996..00000000000 --- a/tests/run-make/issue-25581/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/issue-26006/Makefile b/tests/run-make/issue-26006/Makefile deleted file mode 100644 index b679c121530..00000000000 --- a/tests/run-make/issue-26006/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows - -OUT := $(TMPDIR)/out - -all: time - -time: libc - mkdir -p $(OUT)/time $(OUT)/time/deps - ln -sf $(OUT)/libc/liblibc.rlib $(OUT)/time/deps/ - $(RUSTC) in/time/lib.rs -Ldependency=$(OUT)/time/deps/ - -libc: - mkdir -p $(OUT)/libc - $(RUSTC) in/libc/lib.rs --crate-name=libc -Cmetadata=foo -o $(OUT)/libc/liblibc.rlib diff --git a/tests/run-make/issue-26006/in/libc/lib.rs b/tests/run-make/issue-26006/in/libc/lib.rs deleted file mode 100644 index bad155a99bd..00000000000 --- a/tests/run-make/issue-26006/in/libc/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![crate_type = "rlib"] - -pub fn something() {} diff --git a/tests/run-make/issue-26006/in/time/lib.rs b/tests/run-make/issue-26006/in/time/lib.rs deleted file mode 100644 index 51ed27cd713..00000000000 --- a/tests/run-make/issue-26006/in/time/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![feature(rustc_private)] -extern crate libc; - -fn main() {} diff --git a/tests/run-make/issue-85401-static-mir/Makefile b/tests/run-make/issue-85401-static-mir/Makefile deleted file mode 100644 index 47a36b6e453..00000000000 --- a/tests/run-make/issue-85401-static-mir/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -include ../tools.mk - -# Regression test for issue #85401 -# Verify that we do not ICE when trying to access MIR for statics, -# but emit an error when linking. - -OUTPUT_FILE := $(TMPDIR)/build-output - -all: - $(RUSTC) --crate-type rlib --crate-name foo -Crelocation-model=pic --edition=2018 foo.rs -Zalways-encode-mir=yes --emit metadata -o $(TMPDIR)/libfoo.rmeta - $(RUSTC) --crate-type rlib --crate-name bar -Crelocation-model=pic --edition=2018 bar.rs -o $(TMPDIR)/libbar.rlib --extern=foo=$(TMPDIR)/libfoo.rmeta - $(RUSTC) --crate-type bin --crate-name baz -Crelocation-model=pic --edition=2018 baz.rs -o $(TMPDIR)/baz -L $(TMPDIR) --extern=bar=$(TMPDIR)/libbar.rlib > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] - cat $(OUTPUT_FILE) - $(CGREP) 'crate `foo` required to be available in rlib format, but was not found in this form' < $(OUTPUT_FILE) - # -v tests are fragile, hopefully this text won't change - $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) diff --git a/tests/run-make/issue-18943/foo.rs b/tests/run-make/lib-trait-for-trait-no-ice/foo.rs index 54daec8dd1e..54daec8dd1e 100644 --- a/tests/run-make/issue-18943/foo.rs +++ b/tests/run-make/lib-trait-for-trait-no-ice/foo.rs diff --git a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs new file mode 100644 index 00000000000..766acfc00da --- /dev/null +++ b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs @@ -0,0 +1,14 @@ +// Inside a library, implementing a trait for another trait +// with a lifetime used to cause an internal compiler error (ICE). +// This test checks that this bug does not make a resurgence - +// first by ensuring successful compilation, then verifying that +// the lib crate-type flag was actually followed. +// See https://github.com/rust-lang/rust/issues/18943 + +use run_make_support::{rust_lib_name, rustc}; +use std::path::Path; + +fn main() { + rustc().input("foo.rs").crate_type("lib").run(); + assert!(Path::new(&rust_lib_name("foo")).exists()); +} diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs index a6d68800792..c0bf8d972af 100644 --- a/tests/run-make/link-arg/rmake.rs +++ b/tests/run-make/link-arg/rmake.rs @@ -17,4 +17,5 @@ fn main() { .run_unchecked(); out.assert_stdout_contains("lfoo"); out.assert_stdout_contains("lbar"); + assert!(out.stdout_utf8().ends_with('\n')); } diff --git a/tests/run-make/link-path-order/Makefile b/tests/run-make/link-path-order/Makefile deleted file mode 100644 index a3831a63ac7..00000000000 --- a/tests/run-make/link-path-order/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Verifies that the -L arguments given to the linker is in the same order -# as the -L arguments on the rustc command line. - -CORRECT_DIR=$(TMPDIR)/correct -WRONG_DIR=$(TMPDIR)/wrong - -F := $(call NATIVE_STATICLIB_FILE,foo) - -all: $(call NATIVE_STATICLIB,correct) $(call NATIVE_STATICLIB,wrong) - mkdir -p $(CORRECT_DIR) $(WRONG_DIR) - mv $(call NATIVE_STATICLIB,correct) $(CORRECT_DIR)/$(F) - mv $(call NATIVE_STATICLIB,wrong) $(WRONG_DIR)/$(F) - $(RUSTC) main.rs -o $(TMPDIR)/should_succeed -L $(CORRECT_DIR) -L $(WRONG_DIR) - $(call RUN,should_succeed) - $(RUSTC) main.rs -o $(TMPDIR)/should_fail -L $(WRONG_DIR) -L $(CORRECT_DIR) - $(call FAIL,should_fail) diff --git a/tests/run-make/link-path-order/rmake.rs b/tests/run-make/link-path-order/rmake.rs new file mode 100644 index 00000000000..c8e41b2bcf8 --- /dev/null +++ b/tests/run-make/link-path-order/rmake.rs @@ -0,0 +1,33 @@ +// The order in which "library search path" `-L` arguments are given to the command line rustc +// is important. These arguments must match the order of the linker's arguments. In this test, +// fetching the Wrong library before the Correct one causes a function to return 0 instead of the +// expected 1, causing a runtime panic, as expected. +// See https://github.com/rust-lang/rust/pull/16904 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, path, rfs, run, run_fail, rustc, static_lib_name}; + +fn main() { + build_native_static_lib("correct"); + build_native_static_lib("wrong"); + rfs::create_dir("correct"); + rfs::create_dir("wrong"); + rfs::rename(static_lib_name("correct"), path("correct").join(static_lib_name("foo"))); + rfs::rename(static_lib_name("wrong"), path("wrong").join(static_lib_name("foo"))); + rustc() + .input("main.rs") + .output("should_succeed") + .library_search_path("correct") + .library_search_path("wrong") + .run(); + run("should_succeed"); + rustc() + .input("main.rs") + .output("should_fail") + .library_search_path("wrong") + .library_search_path("correct") + .run(); + run_fail("should_fail"); +} diff --git a/tests/run-make/longjmp-across-rust/Makefile b/tests/run-make/longjmp-across-rust/Makefile deleted file mode 100644 index 5fd2d4f855f..00000000000 --- a/tests/run-make/longjmp-across-rust/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,foo) - $(RUSTC) main.rs - $(call RUN,main) diff --git a/tests/run-make/longjmp-across-rust/rmake.rs b/tests/run-make/longjmp-across-rust/rmake.rs new file mode 100644 index 00000000000..90a527077d2 --- /dev/null +++ b/tests/run-make/longjmp-across-rust/rmake.rs @@ -0,0 +1,18 @@ +// longjmp, an error handling function used in C, is useful +// for jumping out of nested call chains... but it used to accidentally +// trigger Rust's cleanup system in a way that caused an unexpected abortion +// of the program. After this was fixed in #48572, this test compiles and executes +// a program that jumps between Rust and its C library, with longjmp included. For +// the test to succeed, no unexpected abortion should occur. +// See https://github.com/rust-lang/rust/pull/48572 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("foo"); + rustc().input("main.rs").run(); + run("main"); +} diff --git a/tests/run-make/ls-metadata/rmake.rs b/tests/run-make/ls-metadata/rmake.rs index 0e60f2c4678..45299a48c11 100644 --- a/tests/run-make/ls-metadata/rmake.rs +++ b/tests/run-make/ls-metadata/rmake.rs @@ -6,12 +6,12 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper; +use run_make_support::rfs; use run_make_support::rustc; fn main() { rustc().input("foo.rs").run(); rustc().arg("-Zls=root").input("foo").run(); - fs_wrapper::create_file("bar"); + rfs::create_file("bar"); rustc().arg("-Zls=root").input("bar").run(); } diff --git a/tests/run-make/lto-readonly-lib/rmake.rs b/tests/run-make/lto-readonly-lib/rmake.rs index 9eb135addd9..d0ba3fb37a2 100644 --- a/tests/run-make/lto-readonly-lib/rmake.rs +++ b/tests/run-make/lto-readonly-lib/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper; +use run_make_support::rfs; use run_make_support::{run, rust_lib_name, rustc, test_while_readonly}; fn main() { diff --git a/tests/run-make/lto-smoke-c/Makefile b/tests/run-make/lto-smoke-c/Makefile deleted file mode 100644 index f1ba3d95da2..00000000000 --- a/tests/run-make/lto-smoke-c/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Apparently older versions of GCC segfault if -g is passed... -CC := $(CC:-g=) - -all: - $(RUSTC) foo.rs -C lto - $(CC) bar.c $(call STATICLIB,foo) \ - $(call OUT_EXE,bar) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - $(call RUN,bar) diff --git a/tests/run-make/lto-smoke-c/rmake.rs b/tests/run-make/lto-smoke-c/rmake.rs new file mode 100644 index 00000000000..70760f730c0 --- /dev/null +++ b/tests/run-make/lto-smoke-c/rmake.rs @@ -0,0 +1,20 @@ +// LLVM's link-time-optimization (LTO) is a useful feature added to Rust in response +// to #10741. This test uses this feature with `-C lto` alongside a native C library, +// and checks that compilation and execution is successful. +// See https://github.com/rust-lang/rust/issues/10741 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib_name}; + +fn main() { + rustc().input("foo.rs").arg("-Clto").run(); + cc().input("bar.c") + .arg(static_lib_name("foo")) + .out_exe("bar") + .args(extra_c_flags()) + .args(extra_cxx_flags()) + .run(); + run("bar"); +} diff --git a/tests/run-make/macos-fat-archive/Makefile b/tests/run-make/macos-fat-archive/Makefile deleted file mode 100644 index 0feb39a23cb..00000000000 --- a/tests/run-make/macos-fat-archive/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# only-apple - -include ../tools.mk - -"$(TMPDIR)"/libnative-library.a: native-library.c - $(CC) -arch arm64 -arch x86_64 native-library.c -c -o "$(TMPDIR)"/native-library.o - $(AR) crs "$(TMPDIR)"/libnative-library.a "$(TMPDIR)"/native-library.o - -all: "$(TMPDIR)"/libnative-library.a - $(RUSTC) lib.rs --crate-type=lib -L "native=$(TMPDIR)" -l static=native-library diff --git a/tests/run-make/macos-fat-archive/rmake.rs b/tests/run-make/macos-fat-archive/rmake.rs new file mode 100644 index 00000000000..c9f0fa07693 --- /dev/null +++ b/tests/run-make/macos-fat-archive/rmake.rs @@ -0,0 +1,20 @@ +// macOS (and iOS) has a concept of universal (fat) binaries which contain code for multiple CPU +// architectures in the same file. Apple is migrating from x86_64 to aarch64 CPUs, +// so for the next few years it will be important for macOS developers to +// build "fat" binaries (executables and cdylibs). + +// Rustc used to be unable to handle these special libraries, which was fixed in #98736. If +// compilation in this test is successful, the native fat library was successfully linked to. +// See https://github.com/rust-lang/rust/issues/55235 + +//@ only-apple + +use run_make_support::{cc, llvm_ar, rustc}; + +fn main() { + cc().args(&["-arch", "arm64", "-arch", "x86_64", "native-library.c", "-c"]) + .out_exe("native-library.o") + .run(); + llvm_ar().obj_to_ar().output_input("libnative-library.a", "native-library.o").run(); + rustc().input("lib.rs").crate_type("lib").arg("-lstatic=native-library").run(); +} diff --git a/tests/run-make/manual-link/Makefile b/tests/run-make/manual-link/Makefile deleted file mode 100644 index 8dbf0460fff..00000000000 --- a/tests/run-make/manual-link/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(TMPDIR)/libbar.a - $(RUSTC) foo.rs -lstatic=bar - $(RUSTC) main.rs - $(call RUN,main) diff --git a/tests/run-make/manual-link/rmake.rs b/tests/run-make/manual-link/rmake.rs new file mode 100644 index 00000000000..1d362172263 --- /dev/null +++ b/tests/run-make/manual-link/rmake.rs @@ -0,0 +1,16 @@ +// A smoke test for the `-l` command line rustc flag, which manually links to the selected +// library. Useful for native libraries, this is roughly equivalent to `#[link]` in Rust code. +// If compilation succeeds, the flag successfully linked the native library. +// See https://github.com/rust-lang/rust/pull/18470 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("bar"); + rustc().input("foo.rs").arg("-lstatic=bar").run(); + rustc().input("main.rs").run(); + run("main"); +} diff --git a/tests/run-make/many-crates-but-no-match/rmake.rs b/tests/run-make/many-crates-but-no-match/rmake.rs index ea4f166b2bd..938ffce6a03 100644 --- a/tests/run-make/many-crates-but-no-match/rmake.rs +++ b/tests/run-make/many-crates-but-no-match/rmake.rs @@ -4,12 +4,12 @@ // what should be done to fix the issue. // See https://github.com/rust-lang/rust/issues/13266 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { - fs_wrapper::create_dir("a1"); - fs_wrapper::create_dir("a2"); - fs_wrapper::create_dir("a3"); + rfs::create_dir("a1"); + rfs::create_dir("a2"); + rfs::create_dir("a3"); rustc().crate_type("rlib").out_dir("a1").input("crateA1.rs").run(); rustc().crate_type("rlib").library_search_path("a1").input("crateB.rs").run(); rustc().crate_type("rlib").out_dir("a2").input("crateA2.rs").run(); diff --git a/tests/run-make/missing-crate-dependency/Makefile b/tests/run-make/missing-crate-dependency/Makefile deleted file mode 100644 index 7c271ab8a90..00000000000 --- a/tests/run-make/missing-crate-dependency/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --crate-type=rlib crateA.rs - $(RUSTC) --crate-type=rlib crateB.rs - $(call REMOVE_RLIBS,crateA) - # Ensure crateC fails to compile since dependency crateA is missing - $(RUSTC) crateC.rs 2>&1 | \ - $(CGREP) 'can'"'"'t find crate for `crateA` which `crateB` depends on' diff --git a/tests/run-make/missing-crate-dependency/rmake.rs b/tests/run-make/missing-crate-dependency/rmake.rs new file mode 100644 index 00000000000..dae77032f7d --- /dev/null +++ b/tests/run-make/missing-crate-dependency/rmake.rs @@ -0,0 +1,17 @@ +// A simple smoke test to check that rustc fails compilation +// and outputs a helpful message when a dependency is missing +// in a dependency chain. +// See https://github.com/rust-lang/rust/issues/12146 + +use run_make_support::{rfs, rust_lib_name, rustc}; + +fn main() { + rustc().crate_type("rlib").input("crateA.rs").run(); + rustc().crate_type("rlib").input("crateB.rs").run(); + rfs::remove_file(rust_lib_name("crateA")); + // Ensure that crateC fails to compile, as the crateA dependency is missing. + rustc() + .input("crateC.rs") + .run_fail() + .assert_stderr_contains("can't find crate for `crateA` which `crateB` depends on"); +} diff --git a/tests/run-make/mixing-libs/Makefile b/tests/run-make/mixing-libs/Makefile deleted file mode 100644 index 459db0dfdb2..00000000000 --- a/tests/run-make/mixing-libs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) rlib.rs --crate-type=rlib --crate-type=dylib - $(RUSTC) dylib.rs # no -Cprefer-dynamic so statically linking librlib.rlib - $(call REMOVE_DYLIBS,rlib) # remove librlib.so to test that prog.rs doesn't get confused about the removed dylib version of librlib - $(RUSTC) prog.rs && exit 1 || exit 0 diff --git a/tests/run-make/mixing-libs/rmake.rs b/tests/run-make/mixing-libs/rmake.rs new file mode 100644 index 00000000000..89fbf5589e3 --- /dev/null +++ b/tests/run-make/mixing-libs/rmake.rs @@ -0,0 +1,21 @@ +// Having multiple upstream crates available in different formats +// should result in failed compilation. This test causes multiple +// libraries to exist simultaneously as rust libs and dynamic libs, +// causing prog.rs to fail compilation. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile + +use run_make_support::{dynamic_lib_name, rfs, rustc}; + +fn main() { + rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run(); + + // Not putting `-C prefer-dynamic` here allows for static linking of librlib.rlib. + rustc().input("dylib.rs").run(); + + // librlib's dynamic version needs to be removed here to prevent prog.rs from fetching + // the wrong one. + rfs::remove_file(dynamic_lib_name("rlib")); + rustc().input("prog.rs").run_fail(); +} diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs index c6426029989..f63146e692a 100644 --- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -17,20 +17,20 @@ //@ ignore-nvptx64-nvidia-cuda // FIXME: can't find crate for 'std' -use run_make_support::{fs_wrapper, rust_lib_name, rustc}; +use run_make_support::{rfs, rust_lib_name, rustc}; fn main() { - fs_wrapper::create_dir("incr"); - fs_wrapper::create_dir("first_src"); - fs_wrapper::create_dir("output"); - fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs"); - fs_wrapper::rename("main.rs", "first_src/main.rs"); + rfs::create_dir("incr"); + rfs::create_dir("first_src"); + rfs::create_dir("output"); + rfs::rename("my_lib.rs", "first_src/my_lib.rs"); + rfs::rename("main.rs", "first_src/main.rs"); // Build from "first_src" std::env::set_current_dir("first_src").unwrap(); rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run(); std::env::set_current_dir("..").unwrap(); - fs_wrapper::rename("first_src", "second_src"); + rfs::rename("first_src", "second_src"); std::env::set_current_dir("second_src").unwrap(); // Build from "second_src" - the output and incremental directory remain identical rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run(); diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs index bffd9477f8f..0042e4d1e17 100644 --- a/tests/run-make/non-unicode-env/rmake.rs +++ b/tests/run-make/non-unicode-env/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::fs_wrapper; +use run_make_support::rfs; use run_make_support::rustc; fn main() { @@ -7,6 +7,6 @@ fn main() { #[cfg(windows)] let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]); let output = rustc().input("non_unicode_env.rs").env("NON_UNICODE_VAR", non_unicode).run_fail(); - let expected = fs_wrapper::read_to_string("non_unicode_env.stderr"); + let expected = rfs::read_to_string("non_unicode_env.stderr"); output.assert_stderr_equals(expected); } diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index 895d9e00a2d..ef316f11036 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { #[cfg(unix)] @@ -17,8 +17,8 @@ fn main() { } let incr_dir = "incr-dir"; rustc().input("foo.rs").incremental(&incr_dir).run(); - for crate_dir in fs_wrapper::read_dir(&incr_dir) { - fs_wrapper::create_dir(crate_dir.unwrap().path().join(&non_unicode)); + for crate_dir in rfs::read_dir(&incr_dir) { + rfs::create_dir(crate_dir.unwrap().path().join(&non_unicode)); } rustc().input("foo.rs").incremental(&incr_dir).run(); } diff --git a/tests/run-make/obey-crate-type-flag/Makefile b/tests/run-make/obey-crate-type-flag/Makefile deleted file mode 100644 index ecbb2e620ed..00000000000 --- a/tests/run-make/obey-crate-type-flag/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# check that rustc builds all crate_type attributes -# delete rlib -# delete whatever dylib is made for this system -# check that rustc only builds --crate-type flags, ignoring attributes -# fail if an rlib was built -all: - $(RUSTC) test.rs - $(call REMOVE_RLIBS,test) - $(call REMOVE_DYLIBS,test) - $(RUSTC) --crate-type dylib test.rs - $(call REMOVE_RLIBS,test) && exit 1 || exit 0 diff --git a/tests/run-make/obey-crate-type-flag/rmake.rs b/tests/run-make/obey-crate-type-flag/rmake.rs new file mode 100644 index 00000000000..8d6eb237982 --- /dev/null +++ b/tests/run-make/obey-crate-type-flag/rmake.rs @@ -0,0 +1,21 @@ +// test.rs should produce both an rlib and a dylib +// by default. When the crate_type flag is passed and +// forced to dylib, no rlibs should be produced. +// See https://github.com/rust-lang/rust/issues/11573 + +//@ ignore-cross-compile + +use run_make_support::{ + cwd, dynamic_lib_name, has_extension, rfs, rust_lib_name, rustc, shallow_find_files, +}; +use std::path::Path; + +fn main() { + rustc().input("test.rs").run(); + assert!(Path::new(&dynamic_lib_name("test")).exists()); + assert!(Path::new(&rust_lib_name("test")).exists()); + + rfs::remove_file(rust_lib_name("test")); + rustc().crate_type("dylib").input("test.rs").run(); + assert!(shallow_find_files(cwd(), |path| { has_extension(path, "rlib") }).is_empty()); +} diff --git a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs index 4b5c9e8d118..e49b5005fa0 100644 --- a/tests/run-make/output-filename-conflicts-with-directory/rmake.rs +++ b/tests/run-make/output-filename-conflicts-with-directory/rmake.rs @@ -4,10 +4,10 @@ // potentially-confusing linker error. // See https://github.com/rust-lang/rust/pull/47203 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { - fs_wrapper::create_dir("foo"); + rfs::create_dir("foo"); rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains( r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#, ); diff --git a/tests/run-make/output-filename-overwrites-input/rmake.rs b/tests/run-make/output-filename-overwrites-input/rmake.rs index c6055e818a1..1fa12259faf 100644 --- a/tests/run-make/output-filename-overwrites-input/rmake.rs +++ b/tests/run-make/output-filename-overwrites-input/rmake.rs @@ -4,14 +4,14 @@ //@ ignore-cross-compile -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { - fs_wrapper::copy("foo.rs", "foo"); + rfs::copy("foo.rs", "foo"); rustc().input("foo").output("foo").run_fail().assert_stderr_contains( r#"the input file "foo" would be overwritten by the generated executable"#, ); - fs_wrapper::copy("bar.rs", "bar.rlib"); + rfs::copy("bar.rs", "bar.rlib"); rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains( r#"the input file "bar.rlib" would be overwritten by the generated executable"#, ); diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs index 1d1637a744e..c51b2153945 100644 --- a/tests/run-make/output-type-permutations/rmake.rs +++ b/tests/run-make/output-type-permutations/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/12020 use run_make_support::{ - bin_name, dynamic_lib_name, filename_not_in_denylist, fs_wrapper, rust_lib_name, rustc, + bin_name, dynamic_lib_name, filename_not_in_denylist, rfs, rust_lib_name, rustc, shallow_find_files, static_lib_name, }; use std::path::PathBuf; @@ -20,10 +20,10 @@ fn assert_expected_output_files(expectations: Expectations, rustc_invocation: im let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } = expectations; - fs_wrapper::create_dir(&dir); + rfs::create_dir(&dir); rustc_invocation(); for file in must_exist { - fs_wrapper::remove_file(PathBuf::from(&dir).join(&file)); + rfs::remove_file(PathBuf::from(&dir).join(&file)); } let actual_output_files = shallow_find_files(dir, |path| filename_not_in_denylist(path, &can_exist)); @@ -526,17 +526,14 @@ fn main() { test_dir: "rlib-emits".to_string(), }, || { - fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); + rfs::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc"); rustc() .input("foo.rs") .emit("llvm-bc,link") .crate_type("rlib") .out_dir("rlib-emits") .run(); - assert_eq!( - fs_wrapper::read("rlib-emits/foo.bc"), - fs_wrapper::read("rlib-emits/bar.bc") - ); + assert_eq!(rfs::read("rlib-emits/foo.bc"), rfs::read("rlib-emits/bar.bc")); }, ); } diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs index 3f032cf3762..3f412bfefc8 100644 --- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -5,12 +5,12 @@ // conflicts. This test uses this flag and checks for successful compilation. // See https://github.com/rust-lang/rust/pull/83846 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; use std::sync::{Arc, Barrier}; use std::thread; fn main() { - fs_wrapper::create_file("lib.rs"); + rfs::create_file("lib.rs"); let barrier = Arc::new(Barrier::new(2)); let handle = { let barrier = Arc::clone(&barrier); diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs index d3cb79c39af..588c5c6dc31 100644 --- a/tests/run-make/pgo-branch-weights/rmake.rs +++ b/tests/run-make/pgo-branch-weights/rmake.rs @@ -10,14 +10,14 @@ //@ needs-profiler-support //@ ignore-cross-compile -use run_make_support::{fs_wrapper, llvm_filecheck, llvm_profdata, run_with_args, rustc}; +use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc}; use std::path::Path; fn main() { let path_prof_data_dir = Path::new("prof_data_dir"); let path_merged_profdata = path_prof_data_dir.join("merged.profdata"); rustc().input("opaque.rs").run(); - fs_wrapper::create_dir_all(&path_prof_data_dir); + rfs::create_dir_all(&path_prof_data_dir); rustc() .input("interesting.rs") .profile_generate(&path_prof_data_dir) @@ -34,8 +34,5 @@ fn main() { .codegen_units(1) .emit("llvm-ir") .run(); - llvm_filecheck() - .patterns("filecheck-patterns.txt") - .stdin(fs_wrapper::read("interesting.ll")) - .run(); + llvm_filecheck().patterns("filecheck-patterns.txt").stdin(rfs::read("interesting.ll")).run(); } diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs index 0f76aff80d0..cad49372266 100644 --- a/tests/run-make/pgo-use/rmake.rs +++ b/tests/run-make/pgo-use/rmake.rs @@ -9,8 +9,8 @@ //@ ignore-cross-compile use run_make_support::{ - cwd, fs_wrapper, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args, - rustc, shallow_find_files, + cwd, has_extension, has_prefix, llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc, + shallow_find_files, }; fn main() { @@ -47,7 +47,7 @@ fn main() { // line with the function name before the line with the function attributes. // FileCheck only supports checking that something matches on the next line, // but not if something matches on the previous line. - let ir = fs_wrapper::read_to_string("main.ll"); + let ir = rfs::read_to_string("main.ll"); let lines: Vec<_> = ir.lines().rev().collect(); let mut reversed_ir = lines.join("\n"); reversed_ir.push('\n'); diff --git a/tests/run-make/prefer-dylib/rmake.rs b/tests/run-make/prefer-dylib/rmake.rs index 6b3b3ad6d3b..264d184a6c7 100644 --- a/tests/run-make/prefer-dylib/rmake.rs +++ b/tests/run-make/prefer-dylib/rmake.rs @@ -1,6 +1,6 @@ //@ ignore-cross-compile -use run_make_support::{cwd, dynamic_lib_name, fs_wrapper, read_dir, run, run_fail, rustc}; +use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").arg("-Cprefer-dynamic").run(); @@ -8,7 +8,7 @@ fn main() { run("foo"); - fs_wrapper::remove_file(dynamic_lib_name("bar")); + rfs::remove_file(dynamic_lib_name("bar")); // This time the command should fail. run_fail("foo"); } diff --git a/tests/run-make/prefer-rlib/rmake.rs b/tests/run-make/prefer-rlib/rmake.rs index 96861a264e6..6d38282c2e3 100644 --- a/tests/run-make/prefer-rlib/rmake.rs +++ b/tests/run-make/prefer-rlib/rmake.rs @@ -3,13 +3,13 @@ //@ ignore-cross-compile -use run_make_support::{dynamic_lib_name, fs_wrapper, path, run, rust_lib_name, rustc}; +use run_make_support::{dynamic_lib_name, path, rfs, run, rust_lib_name, rustc}; fn main() { rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").run(); assert!(path(rust_lib_name("bar")).exists()); rustc().input("foo.rs").run(); - fs_wrapper::remove_file(rust_lib_name("bar")); - fs_wrapper::remove_file(dynamic_lib_name("bar")); + rfs::remove_file(rust_lib_name("bar")); + rfs::remove_file(dynamic_lib_name("bar")); run("foo"); } diff --git a/tests/run-make/pretty-print-with-dep-file/rmake.rs b/tests/run-make/pretty-print-with-dep-file/rmake.rs index 859a9781bb6..d7a29ff7d19 100644 --- a/tests/run-make/pretty-print-with-dep-file/rmake.rs +++ b/tests/run-make/pretty-print-with-dep-file/rmake.rs @@ -5,13 +5,13 @@ // does not get an unexpected dep-info file. // See https://github.com/rust-lang/rust/issues/112898 -use run_make_support::{fs_wrapper, invalid_utf8_contains, rustc}; +use run_make_support::{invalid_utf8_contains, rfs, rustc}; use std::path::Path; fn main() { rustc().emit("dep-info").arg("-Zunpretty=expanded").input("with-dep.rs").run(); invalid_utf8_contains("with-dep.d", "with-dep.rs"); - fs_wrapper::remove_file("with-dep.d"); + rfs::remove_file("with-dep.d"); rustc().emit("dep-info").arg("-Zunpretty=normal").input("with-dep.rs").run(); assert!(!Path::new("with-dep.d").exists()); } diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index d11eda1db2a..d83e8a36f2c 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -10,7 +10,7 @@ use std::ffi::OsString; use std::iter::FromIterator; use std::path::PathBuf; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; struct PrintCfg { target: &'static str, @@ -96,7 +96,7 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) { rustc().target(target).arg(print_arg).run(); - let output = fs_wrapper::read_to_string(&tmp_path); + let output = rfs::read_to_string(&tmp_path); check_(&output, includes, disallow); } diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index 66f62a7015a..d0cba725b36 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -4,7 +4,7 @@ use std::ffi::OsString; use std::path::PathBuf; -use run_make_support::{fs_wrapper, rustc, target}; +use run_make_support::{rfs, rustc, target}; struct Option<'a> { target: &'a str, @@ -49,7 +49,7 @@ fn check(args: Option) { rustc().target(args.target).arg(print_arg).run(); - fs_wrapper::read_to_string(&tmp_path) + rfs::read_to_string(&tmp_path) }; check_(&stdout, args.includes); diff --git a/tests/run-make/prune-link-args/Makefile b/tests/run-make/prune-link-args/Makefile deleted file mode 100644 index c21ba6ace38..00000000000 --- a/tests/run-make/prune-link-args/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows - -# Notice the space in the end, this emulates the output of pkg-config -RUSTC_FLAGS = -C link-args="-lc " - -all: - $(RUSTC) $(RUSTC_FLAGS) empty.rs diff --git a/tests/run-make/prune-link-args/rmake.rs b/tests/run-make/prune-link-args/rmake.rs new file mode 100644 index 00000000000..ea4ffa732bf --- /dev/null +++ b/tests/run-make/prune-link-args/rmake.rs @@ -0,0 +1,17 @@ +// Passing link-args with an unexpected space +// could result in the flag being parsed and receiving +// an unexpected, empty linker argument. This test +// ensures successful compilation even when a space is +// present. +// See https://github.com/rust-lang/rust/pull/10749 + +//@ ignore-cross-compile +//@ ignore-windows-gnu +// Reason: The space is parsed as an empty linker argument on windows-gnu. + +use run_make_support::rustc; + +fn main() { + // Notice the space at the end of -lc, which emulates the output of pkg-config. + rustc().arg("-Clink-args=-lc ").input("empty.rs").run(); +} diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile deleted file mode 100644 index f5d5360a3fb..00000000000 --- a/tests/run-make/raw-dylib-custom-dlltool/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary. - -# only-windows -# only-gnu -# needs-dlltool - -include ../tools.mk - -all: - $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd - $(DIFF) output.txt "$(TMPDIR)"/output.txt diff --git a/tests/run-make/raw-dylib-custom-dlltool/rmake.rs b/tests/run-make/raw-dylib-custom-dlltool/rmake.rs new file mode 100644 index 00000000000..86b952f0b45 --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/rmake.rs @@ -0,0 +1,24 @@ +// Instead of using the default dlltool, the rust compiler can also accept a custom +// command file with the -C dlltool flag. This test uses it to compile some rust code +// with the raw_dylib Windows-exclusive feature, and checks that the output contains +// the string passed from the custom dlltool, confirming that the default dlltool was +// successfully overridden. +// See https://github.com/rust-lang/rust/pull/109677 + +//@ only-windows +//@ only-gnu +//@ needs-dlltool +// Reason: this test specifically checks the custom dlltool feature, only +// available on Windows-gnu. + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc() + .crate_type("lib") + .crate_name("raw_dylib_test") + .input("lib.rs") + .arg("-Cdlltool=script.cmd") + .run(); + diff().expected_file("output.txt").actual_file("actual.txt").normalize(r#"\r"#, "").run(); +} diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd index 95f85c61c67..51834590be0 100644 --- a/tests/run-make/raw-dylib-custom-dlltool/script.cmd +++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd @@ -1,2 +1,2 @@ -echo Called dlltool via script.cmd> %TMPDIR%\output.txt +echo Called dlltool via script.cmd> actual.txt dlltool.exe %* diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile b/tests/run-make/raw-dylib-inline-cross-dylib/Makefile deleted file mode 100644 index 6b44b40e253..00000000000 --- a/tests/run-make/raw-dylib-inline-cross-dylib/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# Regression test for calling an inline function that uses a raw-dylib function. - -# only-windows - -include ../tools.mk - -# We'd be using the llvm-objdump instead of the system objdump to ensure compatibility -# with the LLVM bitcode generated by rustc but on Windows piping/IO redirection under MSYS2 is wonky with llvm-objdump. -OBJDUMP = objdump - -all: - $(RUSTC) --crate-type dylib --crate-name raw_dylib_test lib.rs -C prefer-dynamic - $(RUSTC) --crate-type dylib --crate-name raw_dylib_test_wrapper lib_wrapper.rs -C prefer-dynamic - $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)" -C prefer-dynamic - # Make sure we don't find an import to the functions we expect to be inlined. - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function" - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -v -e "inline_library_function_calls_inline" - # Make sure we do find an import to the functions we expect to be imported. - $(OBJDUMP) -p $(TMPDIR)/driver.exe | $(CGREP) -e "library_function" - $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c) - $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c) -ifdef IS_MSVC - $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib - $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib -else - $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll - $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll -endif - $(call RUN,driver) | tr -d '\r' > "$(TMPDIR)"/output.txt - $(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs new file mode 100644 index 00000000000..6e3b31a0cdb --- /dev/null +++ b/tests/run-make/raw-dylib-inline-cross-dylib/rmake.rs @@ -0,0 +1,61 @@ +// When we generate the import library for a dylib or bin crate, we should generate it +// for the symbols both for the current crate and all upstream crates. This allows for +// using the link kind `raw-dylib` inside inline functions successfully. This test checks +// that the import symbols in the object files match this convention, and that execution +// of the binary results in all function names exported successfully. +// See https://github.com/rust-lang/rust/pull/102988 + +//@ only-windows + +use run_make_support::{cc, diff, is_msvc, llvm_objdump, run, rustc}; + +fn main() { + rustc() + .crate_type("dylib") + .crate_name("raw_dylib_test") + .input("lib.rs") + .arg("-Cprefer-dynamic") + .run(); + rustc() + .crate_type("dylib") + .crate_name("raw_dylib_test_wrapper") + .input("lib_wrapper.rs") + .arg("-Cprefer-dynamic") + .run(); + rustc().crate_type("bin").input("driver.rs").arg("-Cprefer-dynamic").run(); + llvm_objdump() + .arg("--private-headers") + .input("driver.exe") + .run() + // Make sure we don't find an import to the functions we expect to be inlined. + .assert_stdout_not_contains("inline_library_function") + // Make sure we do find an import to the functions we expect to be imported. + .assert_stdout_contains("library_function"); + if is_msvc() { + cc().arg("-c").out_exe("extern_1").input("extern_1.c").run(); + cc().arg("-c").out_exe("extern_2").input("extern_2.c").run(); + cc().input("extern_1.obj") + .arg("-link") + .arg("-dll") + .arg("-out:extern_1.dll") + .arg("-noimplib") + .run(); + cc().input("extern_2.obj") + .arg("-link") + .arg("-dll") + .arg("-out:extern_2.dll") + .arg("-noimplib") + .run(); + } else { + cc().arg("-v").arg("-c").out_exe("extern_1").input("extern_1.c").run(); + cc().arg("-v").arg("-c").out_exe("extern_2").input("extern_2.c").run(); + cc().input("extern_1").out_exe("extern_1.dll").arg("-shared").run(); + cc().input("extern_2").out_exe("extern_2.dll").arg("-shared").run(); + } + let out = run("driver").stdout_utf8(); + diff() + .expected_file("output.txt") + .actual_text("actual_output", out) + .normalize(r#"\r"#, "") + .run(); +} diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index 62c0368e4b3..aeb30e72d5b 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/85344 use run_make_support::bstr::ByteSlice; -use run_make_support::{bstr, fs_wrapper, is_darwin, rustc}; +use run_make_support::{bstr, is_darwin, rfs, rustc}; fn main() { let mut out_simple = rustc(); @@ -60,12 +60,9 @@ fn main() { // helper functions. fn rmeta_contains(expected: &str) { // Normalize to account for path differences in Windows. - if !bstr::BString::from(fs_wrapper::read("liblib.rmeta")) - .replace(b"\\", b"/") - .contains_str(expected) - { + if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta"))); eprintln!("=== SPECIFIED TEXT ==="); eprintln!("{}", expected); panic!("specified text was not found in file"); @@ -74,12 +71,9 @@ fn rmeta_contains(expected: &str) { fn rmeta_not_contains(expected: &str) { // Normalize to account for path differences in Windows. - if bstr::BString::from(fs_wrapper::read("liblib.rmeta")) - .replace(b"\\", b"/") - .contains_str(expected) - { + if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { eprintln!("=== FILE CONTENTS (LOSSY) ==="); - eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta"))); + eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta"))); eprintln!("=== SPECIFIED TEXT ==="); eprintln!("{}", expected); panic!("specified text was not found in file"); diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index a65cf234edf..824ca6e1876 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -3,7 +3,7 @@ use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; -use run_make_support::{fs_wrapper, gimli, object, rustc}; +use run_make_support::{gimli, object, rfs, rustc}; use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; @@ -19,7 +19,7 @@ fn main() { .join("DWARF") .join("repr128"); let output = - fs_wrapper::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output }); + rfs::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output }); let obj = object::File::parse(output.as_slice()).unwrap(); let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big }; let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> { diff --git a/tests/run-make/reset-codegen-1/rmake.rs b/tests/run-make/reset-codegen-1/rmake.rs index 19d42b3d6d5..cc6bb7d5e39 100644 --- a/tests/run-make/reset-codegen-1/rmake.rs +++ b/tests/run-make/reset-codegen-1/rmake.rs @@ -7,7 +7,7 @@ //@ ignore-cross-compile -use run_make_support::{bin_name, fs_wrapper, rustc}; +use run_make_support::{bin_name, rfs, rustc}; use std::path::Path; fn compile(output_file: &str, emit: Option<&str>) { diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs index 09bd4165b2a..16ee7b02885 100644 --- a/tests/run-make/resolve-rename/rmake.rs +++ b/tests/run-make/resolve-rename/rmake.rs @@ -5,12 +5,12 @@ // the renamed library. // See https://github.com/rust-lang/rust/pull/49253 -use run_make_support::fs_wrapper; +use run_make_support::rfs; use run_make_support::rustc; fn main() { rustc().extra_filename("-hash").input("foo.rs").run(); rustc().input("bar.rs").run(); - fs_wrapper::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib"); + rfs::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib"); rustc().input("baz.rs").run(); } diff --git a/tests/run-make/rlib-chain/rmake.rs b/tests/run-make/rlib-chain/rmake.rs index 0947262bf62..306a472f473 100644 --- a/tests/run-make/rlib-chain/rmake.rs +++ b/tests/run-make/rlib-chain/rmake.rs @@ -8,7 +8,7 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -use run_make_support::{fs_wrapper, run, rust_lib_name, rustc}; +use run_make_support::{rfs, run, rust_lib_name, rustc}; fn main() { rustc().input("m1.rs").run(); @@ -16,8 +16,8 @@ fn main() { rustc().input("m3.rs").run(); rustc().input("m4.rs").run(); run("m4"); - fs_wrapper::remove_file(rust_lib_name("m1")); - fs_wrapper::remove_file(rust_lib_name("m2")); - fs_wrapper::remove_file(rust_lib_name("m3")); + rfs::remove_file(rust_lib_name("m1")); + rfs::remove_file(rust_lib_name("m2")); + rfs::remove_file(rust_lib_name("m3")); run("m4"); } diff --git a/tests/run-make/issue-22131/foo.rs b/tests/run-make/rustdoc-cfgspec-parsing/foo.rs index 7b955a07b97..7b955a07b97 100644 --- a/tests/run-make/issue-22131/foo.rs +++ b/tests/run-make/rustdoc-cfgspec-parsing/foo.rs diff --git a/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs new file mode 100644 index 00000000000..9c8c71b19a6 --- /dev/null +++ b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs @@ -0,0 +1,21 @@ +// A rustdoc bug caused the `feature=bar` syntax for the cfg flag to be interpreted +// wrongly, with `feature=bar` instead of just `bar` being understood as the feature name. +// After this was fixed in #22135, this test checks that this bug does not make a resurgence. +// See https://github.com/rust-lang/rust/issues/22131 + +//@ ignore-cross-compile +// Reason: rustdoc fails to find the "foo" crate + +use run_make_support::{cwd, rustc, rustdoc}; + +fn main() { + rustc().cfg(r#"feature="bar""#).crate_type("lib").input("foo.rs").run(); + rustdoc() + .arg("--test") + .arg("--cfg") + .arg(r#"feature="bar""#) + .library_search_path(cwd()) + .input("foo.rs") + .run() + .assert_stdout_contains("foo.rs - foo (line 1) ... ok"); +} diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs index 5d67ee2580f..3feee78f2e1 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs @@ -1,10 +1,10 @@ -use run_make_support::{fs_wrapper, htmldocck, rustc, rustdoc, source_root}; +use run_make_support::{htmldocck, rfs, rustc, rustdoc, source_root}; use std::path::Path; pub fn scrape(extra_args: &[&str]) { let out_dir = Path::new("rustdoc"); let crate_name = "foobar"; - let deps = fs_wrapper::read_dir("examples") + let deps = rfs::read_dir("examples") .filter_map(|entry| entry.ok().map(|e| e.path())) .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs")) .collect::<Vec<_>>(); diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index 80eb768c14c..69dea83de4f 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,10 +1,10 @@ -use run_make_support::{fs_wrapper, rustdoc}; +use run_make_support::{rfs, rustdoc}; use std::iter; use std::path::Path; fn generate_a_lot_of_cfgs(path: &Path) { let content = iter::repeat("--cfg=a\n").take(100_000).collect::<String>(); - fs_wrapper::write(path, content.as_bytes()); + rfs::write(path, content.as_bytes()); } fn main() { diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs index 4174c0552be..981db358f29 100644 --- a/tests/run-make/rustdoc-themes/rmake.rs +++ b/tests/run-make/rustdoc-themes/rmake.rs @@ -1,15 +1,14 @@ // Test that rustdoc will properly load in a theme file and display it in the theme selector. -use run_make_support::{fs_wrapper, htmldocck, rustdoc, source_root}; +use run_make_support::{htmldocck, rfs, rustdoc, source_root}; use std::path::Path; fn main() { let out_dir = Path::new("rustdoc-themes"); let test_css = "test.css"; - let no_script = fs_wrapper::read_to_string( - source_root().join("src/librustdoc/html/static/css/noscript.css"), - ); + let no_script = + rfs::read_to_string(source_root().join("src/librustdoc/html/static/css/noscript.css")); let mut test_content = String::new(); let mut found_begin_light = false; @@ -24,8 +23,8 @@ fn main() { } } assert!(!test_content.is_empty()); - fs_wrapper::create_dir_all(&out_dir); - fs_wrapper::write(&test_css, test_content); + rfs::create_dir_all(&out_dir); + rfs::write(&test_css, test_content); rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run(); htmldocck().arg(out_dir).arg("foo.rs").run(); diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index 1bf41c68114..d1ff2e330f5 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::fs_wrapper::copy; +use run_make_support::rfs; use std::path::{Path, PathBuf}; -use run_make_support::{copy_dir_all, recursive_diff, rustdoc}; +use run_make_support::{assert_dirs_are_equal, rustdoc}; #[derive(PartialEq)] enum JsonOutput { @@ -26,7 +26,7 @@ fn main() { generate_docs(&out_dir, JsonOutput::No); // Copy first output for to check if it's exactly same after second compilation. - copy_dir_all(&out_dir, &tmp_out_dir); + rfs::copy_dir_all(&out_dir, &tmp_out_dir); // Generate html docs once again on same output. generate_docs(&out_dir, JsonOutput::No); @@ -38,12 +38,12 @@ fn main() { assert!(out_dir.join("foobar.json").is_file()); // Copy first json output to check if it's exactly same after second compilation. - copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")); + rfs::copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json")); // Generate json doc on the same output. generate_docs(&out_dir, JsonOutput::Yes); // Check if all docs(including both json and html formats) are still the same after multiple // compilations. - recursive_diff(&out_dir, &tmp_out_dir); + assert_dirs_are_equal(&out_dir, &tmp_out_dir); } diff --git a/tests/run-make/sepcomp-cci-copies/rmake.rs b/tests/run-make/sepcomp-cci-copies/rmake.rs index 612a73977fe..e244f546580 100644 --- a/tests/run-make/sepcomp-cci-copies/rmake.rs +++ b/tests/run-make/sepcomp-cci-copies/rmake.rs @@ -5,7 +5,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-inlining/rmake.rs b/tests/run-make/sepcomp-inlining/rmake.rs index de7551b9a51..b7a6bed05b8 100644 --- a/tests/run-make/sepcomp-inlining/rmake.rs +++ b/tests/run-make/sepcomp-inlining/rmake.rs @@ -6,7 +6,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/sepcomp-separate/rmake.rs b/tests/run-make/sepcomp-separate/rmake.rs index 6f1d22424b5..90017572c4c 100644 --- a/tests/run-make/sepcomp-separate/rmake.rs +++ b/tests/run-make/sepcomp-separate/rmake.rs @@ -4,7 +4,7 @@ // See https://github.com/rust-lang/rust/pull/16367 use run_make_support::{ - count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc, + count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc, shallow_find_files, }; diff --git a/tests/run-make/silly-file-names/rmake.rs b/tests/run-make/silly-file-names/rmake.rs index 9df116146fe..2acf2be8648 100644 --- a/tests/run-make/silly-file-names/rmake.rs +++ b/tests/run-make/silly-file-names/rmake.rs @@ -11,13 +11,13 @@ //@ ignore-windows // Reason: Windows refuses files with < and > in their names -use run_make_support::{diff, fs_wrapper, run, rustc}; +use run_make_support::{diff, rfs, run, rustc}; fn main() { - fs_wrapper::create_file("<leading-lt"); - fs_wrapper::write("<leading-lt", r#""comes from a file with a name that begins with <""#); - fs_wrapper::create_file("trailing-gt>"); - fs_wrapper::write("trailing-gt>", r#""comes from a file with a name that ends with >""#); + rfs::create_file("<leading-lt"); + rfs::write("<leading-lt", r#""comes from a file with a name that begins with <""#); + rfs::create_file("trailing-gt>"); + rfs::write("trailing-gt>", r#""comes from a file with a name that ends with >""#); rustc().input("silly-file-names.rs").output("silly-file-names").run(); let out = run("silly-file-names").stdout_utf8(); diff().expected_file("silly-file-names.run.stdout").actual_text("actual-stdout", out).run(); diff --git a/tests/run-make/split-debuginfo/Makefile b/tests/run-make/split-debuginfo/Makefile index cb2439093b6..5f463ffe8cd 100644 --- a/tests/run-make/split-debuginfo/Makefile +++ b/tests/run-make/split-debuginfo/Makefile @@ -1,4 +1,6 @@ # ignore-cross-compile +# ignore-riscv64 On this platform only `-Csplit-debuginfo=off` is supported, see #120518 + include ../tools.mk all: off packed unpacked diff --git a/tests/run-make/static-extern-type/Makefile b/tests/run-make/static-extern-type/Makefile deleted file mode 100644 index 77897154322..00000000000 --- a/tests/run-make/static-extern-type/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,define-foo) - $(RUSTC) -ldefine-foo use-foo.rs - $(call RUN,use-foo) || exit 1 diff --git a/tests/run-make/static-extern-type/rmake.rs b/tests/run-make/static-extern-type/rmake.rs new file mode 100644 index 00000000000..d30153f9c68 --- /dev/null +++ b/tests/run-make/static-extern-type/rmake.rs @@ -0,0 +1,16 @@ +// Static variables coming from a C library through foreign function interface (FFI) are unsized +// at compile time - and assuming they are sized used to cause an internal compiler error (ICE). +// After this was fixed in #58192, this test checks that external statics can be safely used in +// a program that both compiles and executes successfully. +// See https://github.com/rust-lang/rust/issues/57876 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("define-foo"); + rustc().arg("-ldefine-foo").input("use-foo.rs").run(); + run("use-foo"); +} diff --git a/tests/run-make/std-core-cycle/Makefile b/tests/run-make/std-core-cycle/Makefile deleted file mode 100644 index 5ed6be905df..00000000000 --- a/tests/run-make/std-core-cycle/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -ifeq ($(UNAME),Darwin) -FLAGS := -else -ifdef IS_WINDOWS -FLAGS := -else -FLAGS := -C link-args=-Wl,--no-undefined -endif -endif - -all: - $(RUSTC) bar.rs - $(RUSTC) foo.rs $(FLAGS) - $(RUSTC) foo.rs $(FLAGS) -C panic=abort diff --git a/tests/run-make/std-core-cycle/rmake.rs b/tests/run-make/std-core-cycle/rmake.rs new file mode 100644 index 00000000000..162b783aeb9 --- /dev/null +++ b/tests/run-make/std-core-cycle/rmake.rs @@ -0,0 +1,27 @@ +// In some cases, linking libraries with GNU used to fail due to how +// `std` and `core` possess a circular dependency with one another, and +// how the linker could not go back through its symbol processing to resolve +// the circular link. #49316 fixed this, and this test reproduces a minimal +// version of one such linking attempt which used to fail. +// See https://github.com/rust-lang/rust/issues/18807 + +//@ ignore-cross-compile + +use run_make_support::{is_darwin, is_windows, rustc}; + +fn main() { + rustc().input("bar.rs").run(); + + let mut rustc_foo = rustc(); + rustc_foo.input("foo.rs"); + let mut rustc_foo_panic = rustc(); + rustc_foo_panic.input("foo.rs").panic("abort"); + + if !is_darwin() && !is_windows() { + rustc_foo.arg("-Clink-args=-Wl,--no-undefined"); + rustc_foo_panic.arg("-Clink-args=-Wl,--no-undefined"); + } + + rustc_foo.run(); + rustc_foo_panic.run(); +} diff --git a/tests/run-make/symlinked-extern/rmake.rs b/tests/run-make/symlinked-extern/rmake.rs index 9ed5b76edcb..7a4a8ce18cb 100644 --- a/tests/run-make/symlinked-extern/rmake.rs +++ b/tests/run-make/symlinked-extern/rmake.rs @@ -11,12 +11,12 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, cwd, fs_wrapper, rustc}; +use run_make_support::{cwd, rfs, rustc}; fn main() { rustc().input("foo.rs").run(); - fs_wrapper::create_dir_all("other"); - create_symlink("libfoo.rlib", "other"); + rfs::create_dir_all("other"); + rfs::create_symlink("libfoo.rlib", "other"); rustc().input("bar.rs").library_search_path(cwd()).run(); rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run(); } diff --git a/tests/run-make/symlinked-libraries/rmake.rs b/tests/run-make/symlinked-libraries/rmake.rs index 1d1dce5b5cf..e6449b61a1c 100644 --- a/tests/run-make/symlinked-libraries/rmake.rs +++ b/tests/run-make/symlinked-libraries/rmake.rs @@ -8,11 +8,11 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc}; +use run_make_support::{dynamic_lib_name, rfs, rustc}; fn main() { rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); - fs_wrapper::create_dir_all("other"); - create_symlink(dynamic_lib_name("foo"), "other"); + rfs::create_dir_all("other"); + rfs::create_symlink(dynamic_lib_name("foo"), "other"); rustc().input("bar.rs").library_search_path("other").run(); } diff --git a/tests/run-make/symlinked-rlib/rmake.rs b/tests/run-make/symlinked-rlib/rmake.rs index 65ebb191428..10ba6ba7cbb 100644 --- a/tests/run-make/symlinked-rlib/rmake.rs +++ b/tests/run-make/symlinked-rlib/rmake.rs @@ -8,10 +8,10 @@ //@ ignore-cross-compile //@ needs-symlink -use run_make_support::{create_symlink, cwd, rustc}; +use run_make_support::{cwd, rfs, rustc}; fn main() { rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run(); - create_symlink("foo.xxx", "libfoo.rlib"); + rfs::create_symlink("foo.xxx", "libfoo.rlib"); rustc().input("bar.rs").library_search_path(cwd()).run(); } diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index d2b5f650838..499c6c2079a 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -5,11 +5,11 @@ // using them correctly, or fails with the right error message when using them improperly. // See https://github.com/rust-lang/rust/pull/16156 -use run_make_support::{diff, fs_wrapper, rustc}; +use run_make_support::{diff, rfs, rustc}; fn main() { rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run(); - assert!(!fs_wrapper::read_to_string("foo.s").contains("morestack")); + assert!(!rfs::read_to_string("foo.s").contains("morestack")); rustc() .input("foo.rs") .target("my-invalid-platform.json") @@ -40,8 +40,8 @@ fn main() { .print("target-spec-json") .run() .stdout_utf8(); - fs_wrapper::create_file("test-platform.json"); - fs_wrapper::write("test-platform.json", test_platform.as_bytes()); + rfs::create_file("test-platform.json"); + rfs::write("test-platform.json", test_platform.as_bytes()); let test_platform_2 = rustc() .arg("-Zunstable-options") .target("test-platform.json") diff --git a/tests/run-make/track-path-dep-info/rmake.rs b/tests/run-make/track-path-dep-info/rmake.rs index f108dc66051..9b21644c41b 100644 --- a/tests/run-make/track-path-dep-info/rmake.rs +++ b/tests/run-make/track-path-dep-info/rmake.rs @@ -4,10 +4,10 @@ // output successfully added the file as a dependency. // See https://github.com/rust-lang/rust/pull/84029 -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rustc().input("macro_def.rs").run(); rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run(); - assert!(fs_wrapper::read_to_string("macro_use.d").contains("emojis.txt:")); + assert!(rfs::read_to_string("macro_use.d").contains("emojis.txt:")); } diff --git a/tests/run-make/track-pgo-dep-info/rmake.rs b/tests/run-make/track-pgo-dep-info/rmake.rs index acfe05cf8ea..84f4e0bd383 100644 --- a/tests/run-make/track-pgo-dep-info/rmake.rs +++ b/tests/run-make/track-pgo-dep-info/rmake.rs @@ -8,7 +8,7 @@ // Reason: the binary is executed //@ needs-profiler-support -use run_make_support::{fs_wrapper, llvm_profdata, run, rustc}; +use run_make_support::{llvm_profdata, rfs, run, rustc}; fn main() { // Generate the profile-guided-optimization (PGO) profiles @@ -19,5 +19,5 @@ fn main() { // Use the profiles in compilation rustc().profile_use("merged.profdata").emit("dep-info").input("main.rs").run(); // Check that the profile file is in the dep-info emit file - assert!(fs_wrapper::read_to_string("main.d").contains("merged.profdata")); + assert!(rfs::read_to_string("main.d").contains("merged.profdata")); } diff --git a/tests/run-make/unstable-flag-required/Makefile b/tests/run-make/unstable-flag-required/Makefile deleted file mode 100644 index 17dd15b079c..00000000000 --- a/tests/run-make/unstable-flag-required/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr diff --git a/tests/run-make/unstable-flag-required/rmake.rs b/tests/run-make/unstable-flag-required/rmake.rs new file mode 100644 index 00000000000..c521436c203 --- /dev/null +++ b/tests/run-make/unstable-flag-required/rmake.rs @@ -0,0 +1,12 @@ +// The flag `--output-format` is unauthorized on beta and stable releases, which led +// to confusion for maintainers doing testing on nightly. Tying it to an unstable flag +// elucidates this, and this test checks that `--output-format` cannot be passed on its +// own. +// See https://github.com/rust-lang/rust/pull/82497 + +use run_make_support::{diff, rustdoc}; + +fn main() { + let out = rustdoc().output_format("json").input("x.html").run_fail().stderr_utf8(); + diff().expected_file("output-format-json.stderr").actual_text("actual-json", out).run(); +} diff --git a/tests/run-make/volatile-intrinsics/rmake.rs b/tests/run-make/volatile-intrinsics/rmake.rs index fb9be4bb9ba..66bc6f953c2 100644 --- a/tests/run-make/volatile-intrinsics/rmake.rs +++ b/tests/run-make/volatile-intrinsics/rmake.rs @@ -1,6 +1,6 @@ //@ ignore-cross-compile -use run_make_support::fs_wrapper::read; +use run_make_support::rfs; use run_make_support::{assert_contains, run, rustc}; fn main() { @@ -11,7 +11,7 @@ fn main() { // ... and the loads/stores must not be optimized out. rustc().input("main.rs").emit("llvm-ir").run(); - let raw_llvm_ir = read("main.ll"); + let raw_llvm_ir = rfs::read("main.ll"); let llvm_ir = String::from_utf8_lossy(&raw_llvm_ir); assert_contains(&llvm_ir, "load volatile"); assert_contains(&llvm_ir, "store volatile"); diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index e958f5086ac..756a72f11b1 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,13 +1,13 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::HashMap; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = fs_wrapper::read("bar.wasm"); + let file = rfs::read("bar.wasm"); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index 346cffecc77..0be863fdb6e 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; @@ -12,7 +12,7 @@ fn main() { fn verify(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index 41a2eaaafc3..9ea541a1752 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; use wasmparser::ExternalKind::*; @@ -33,7 +33,7 @@ fn test(args: &[&str]) { fn verify_exports(path: &Path, exports: &[(&str, wasmparser::ExternalKind)]) { println!("verify {path:?}"); - let file = fs_wrapper::read(path); + let file = rfs::read(path); let mut wasm_exports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index 881242c59a2..c240d4780b2 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::HashMap; use wasmparser::TypeRef::Func; @@ -8,7 +8,7 @@ fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = fs_wrapper::read("bar.wasm"); + let file = rfs::read("bar.wasm"); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 891cac4bc9f..8d0944ed98d 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,7 +1,7 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { test("a"); @@ -15,7 +15,7 @@ fn test(cfg: &str) { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run(); - let bytes = fs_wrapper::read("foo.wasm"); + let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); assert!(bytes.len() < 40_000); } diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 88e4c83c94c..9cfd202eae1 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::HashMap; fn main() { @@ -13,7 +13,7 @@ fn main() { .arg("-Copt-level=z") .run(); - let file = fs_wrapper::read("main.wasm"); + let file = rfs::read("main.wasm"); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 42e415b3a86..93eb38b0987 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,12 +1,12 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let bytes = fs_wrapper::read("foo.wasm"); + let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); assert!(bytes.len() < 50_000); } diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 734f79d834a..6b69f76ee17 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::collections::{HashMap, HashSet}; use std::path::Path; @@ -23,7 +23,7 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { rustc().input(file).target("wasm32-wasip1").args(args).run(); - let file = fs_wrapper::read(Path::new(file).with_extension("wasm")); + let file = rfs::read(Path::new(file).with_extension("wasm")); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 4c817a6fd82..ad31351ba95 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::path::Path; fn main() { @@ -17,7 +17,7 @@ fn main() { fn verify_symbols(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index 58c9f9c6f45..36c600c49f5 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{fs_wrapper, rustc, wasmparser}; +use run_make_support::{rfs, rustc, wasmparser}; use std::path::Path; fn main() { @@ -16,7 +16,7 @@ fn main() { fn verify_symbols(path: &Path) { eprintln!("verify {path:?}"); - let file = fs_wrapper::read(&path); + let file = rfs::read(&path); for payload in wasmparser::Parser::new(0).parse_all(&file) { let payload = payload.unwrap(); diff --git a/tests/run-make/weird-output-filenames/rmake.rs b/tests/run-make/weird-output-filenames/rmake.rs index ed331a0b8d4..3d1b5f4007c 100644 --- a/tests/run-make/weird-output-filenames/rmake.rs +++ b/tests/run-make/weird-output-filenames/rmake.rs @@ -1,17 +1,17 @@ -use run_make_support::fs_wrapper::copy; use run_make_support::regex::Regex; +use run_make_support::rfs; use run_make_support::{cwd, rustc}; fn main() { let invalid_characters = [".foo.rs", ".foo.bar", "+foo+bar.rs"]; let re = Regex::new(r"invalid character.*in crate name:").unwrap(); for f in invalid_characters { - copy("foo.rs", f); + rfs::copy("foo.rs", f); let stderr = rustc().input(f).run_fail().stderr_utf8(); assert!(re.is_match(&stderr)); } - copy("foo.rs", "-foo.rs"); + rfs::copy("foo.rs", "-foo.rs"); rustc() .input(cwd().join("-foo.rs")) .run_fail() diff --git a/tests/run-make/windows-ws2_32/rmake.rs b/tests/run-make/windows-ws2_32/rmake.rs index fde59452bc5..6457d74f97e 100644 --- a/tests/run-make/windows-ws2_32/rmake.rs +++ b/tests/run-make/windows-ws2_32/rmake.rs @@ -3,7 +3,7 @@ // Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 use run_make_support::object::{self, read::Object}; -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{rfs, rustc}; fn main() { rustc().input("empty.rs").run(); @@ -14,7 +14,7 @@ fn main() { } fn links_ws2_32(exe: &str) -> bool { - let binary_data = fs_wrapper::read(exe); + let binary_data = rfs::read(exe); let file = object::File::parse(&*binary_data).unwrap(); for import in file.imports().unwrap() { if import.library().eq_ignore_ascii_case(b"WS2_32.dll") { diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml index e4e5cb1ec74..d207ab5bb37 100644 --- a/tests/rustdoc-gui/huge-logo.goml +++ b/tests/rustdoc-gui/huge-logo.goml @@ -3,9 +3,11 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" set-window-size: (1280, 1024) -// offsetWidth = width of sidebar -assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "48", "offsetHeight": 48}) -assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48}) +// offsetWidth = width of sidebar + left and right margins +assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "96", "offsetHeight": 48}) +// offsetWidth = width of sidebar, offsetHeight = height + top padding +assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 64}) +assert-css: (".sidebar-crate .logo-container img", {"border-top-width": "16px", "margin-top": "-16px"}) set-window-size: (400, 600) // offset = size + margin diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 452545958f9..e499c159c6c 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -72,6 +72,7 @@ click: "#structs + .item-table .item-name > a" assert-count: (".sidebar .sidebar-crate", 1) assert-count: (".sidebar .location", 1) assert-count: (".sidebar h2", 3) +assert-text: (".sidebar-elems ul.block > li.current > a", "Foo") // We check that there is no crate listed outside of the top level. assert-false: ".sidebar-elems > .crate" @@ -110,6 +111,7 @@ click: "#functions + .item-table .item-name > a" assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-count: (".sidebar .location", 0) assert-count: (".sidebar h2", 1) +assert-text: (".sidebar-elems ul.block > li.current > a", "foobar") // We check that we don't have the crate list. assert-false: ".sidebar-elems > .crate" @@ -118,6 +120,7 @@ assert-property: (".sidebar", {"clientWidth": "200"}) assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar > .location", "Module module") assert-count: (".sidebar .location", 1) +assert-text: (".sidebar-elems ul.block > li.current > a", "module") // Module page requires three headings: // - Presistent crate branding (name and version) // - Module name, followed by TOC for module headings @@ -138,6 +141,7 @@ assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module") assert-property: (".sidebar > .sidebar-elems > h2 > a", { "href": "/module/sub_module/index.html", }, ENDS_WITH) +assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module") // We check that we don't have the crate list. assert-false: ".sidebar-elems .crate" assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") @@ -179,3 +183,18 @@ assert-property: (".sidebar .sidebar-crate h2 a", { "offsetTop": |index_sidebar_y|, "offsetLeft": |index_sidebar_x|, }) + +// Check that the sidebar links touch the left side of the box +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +assert-position: (".sidebar .block a", {"x": -4}) +assert-position: (".sidebar-crate > h2 > a", {"x": -3}) + +// Check that the main sidebar links touch the left side of the box +// but the crate name doesn't, because the logo takes that space +go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" +assert-position: (".sidebar .block a", {"x": -4}) +// when side-by-side, it's not line wrapped +assert-position-false: (".sidebar-crate > h2 > a", {"x": -3}) +// when line-wrapped, see that it becomes flush-left again +drag-and-drop: ((205, 100), (108, 100)) +assert-position: (".sidebar-crate > h2 > a", {"x": -3}) diff --git a/tests/rustdoc-gui/src/lib2/lib.rs b/tests/rustdoc-gui/src/lib2/lib.rs index b467b044052..2467c7adae1 100644 --- a/tests/rustdoc-gui/src/lib2/lib.rs +++ b/tests/rustdoc-gui/src/lib2/lib.rs @@ -117,6 +117,7 @@ pub mod too_long { pub type ReallyLongTypeNameLongLongLong = Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>; + /// Short doc. pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0; /// This also has a really long doccomment. Lorem ipsum dolor sit amet, diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml index 3709aa10266..fdf84c3fd29 100644 --- a/tests/rustdoc-gui/type-declation-overflow.goml +++ b/tests/rustdoc-gui/type-declation-overflow.goml @@ -16,7 +16,11 @@ assert-property: ("pre.item-decl", {"scrollWidth": "1324"}) // In the table-ish view on the module index, the name should not be wrapped more than necessary. go-to: "file://" + |DOC_PATH| + "/lib2/too_long/index.html" -assert-property: (".item-table .struct", {"offsetWidth": "684"}) + +// We'll ensure that items with short documentation have the same width. +store-property: ("//*[@class='item-table']//*[@class='struct']/..", {"offsetWidth": offset_width}) +assert: |offset_width| == "277" +assert-property: ("//*[@class='item-table']//*[@class='constant']/..", {"offsetWidth": |offset_width|}) // We now make the same check on type declaration... go-to: "file://" + |DOC_PATH| + "/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html" diff --git a/tests/rustdoc-json/assoc_items.rs b/tests/rustdoc-json/assoc_items.rs index 05c2d428393..7fd0fe2b898 100644 --- a/tests/rustdoc-json/assoc_items.rs +++ b/tests/rustdoc-json/assoc_items.rs @@ -3,32 +3,32 @@ pub struct Simple; impl Simple { - // @has "$.index[*][?(@.name=='CONSTANT')].inner.assoc_const" + //@ has "$.index[*][?(@.name=='CONSTANT')].inner.assoc_const" pub const CONSTANT: usize = 0; } pub trait EasyToImpl { - // @has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type" - // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.default" null - // @is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" [] + //@ has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type" + //@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.default" null + //@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" [] /// ToDeclare trait type ToDeclare; - // @has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.default" null - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"' + //@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const" + //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.default" null + //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"' /// AN_ATTRIBUTE trait const AN_ATTRIBUTE: usize; } impl EasyToImpl for Simple { - // @has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type" - // @is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.default.primitive" \"usize\" + //@ has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type" + //@ is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.default.primitive" \"usize\" /// ToDeclare impl type ToDeclare = usize; - // @has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\" - // @is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.default" \"12\" + //@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const" + //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\" + //@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.default" \"12\" /// AN_ATTRIBUTE impl const AN_ATTRIBUTE: usize = 12; } diff --git a/tests/rustdoc-json/assoc_type.rs b/tests/rustdoc-json/assoc_type.rs index edc1f73c866..43b4d387d92 100644 --- a/tests/rustdoc-json/assoc_type.rs +++ b/tests/rustdoc-json/assoc_type.rs @@ -1,9 +1,9 @@ // Regression test for <https://github.com/rust-lang/rust/issues/98547>. -// @has "$.index[*][?(@.name=='Trait')]" -// @has "$.index[*][?(@.name=='AssocType')]" -// @has "$.index[*][?(@.name=='S')]" -// @has "$.index[*][?(@.name=='S2')]" +//@ has "$.index[*][?(@.name=='Trait')]" +//@ has "$.index[*][?(@.name=='AssocType')]" +//@ has "$.index[*][?(@.name=='S')]" +//@ has "$.index[*][?(@.name=='S2')]" pub trait Trait { type AssocType; diff --git a/tests/rustdoc-json/blanket_impls.rs b/tests/rustdoc-json/blanket_impls.rs index a2a5c4a7146..bc2c98dcbb7 100644 --- a/tests/rustdoc-json/blanket_impls.rs +++ b/tests/rustdoc-json/blanket_impls.rs @@ -2,7 +2,7 @@ #![no_std] -// @has "$.index[*][?(@.name=='Error')].inner.assoc_type" -// @has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path" -// @has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path.name" \"Infallible\" +//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type" +//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path" +//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path.name" \"Infallible\" pub struct ForBlanketTryFromImpl; diff --git a/tests/rustdoc-json/doc_hidden_failure.rs b/tests/rustdoc-json/doc_hidden_failure.rs index e2ce66c99e4..249e35b7243 100644 --- a/tests/rustdoc-json/doc_hidden_failure.rs +++ b/tests/rustdoc-json/doc_hidden_failure.rs @@ -11,8 +11,8 @@ mod auto { } } -// @count "$.index[*][?(@.name=='builders')]" 1 -// @has "$.index[*][?(@.name == 'ActionRowBuilder')"] +//@ count "$.index[*][?(@.name=='builders')]" 1 +//@ has "$.index[*][?(@.name == 'ActionRowBuilder')"] pub use auto::*; pub mod builders { diff --git a/tests/rustdoc-json/enums/discriminant/basic.rs b/tests/rustdoc-json/enums/discriminant/basic.rs index dbfc5c2cf6b..06a240404fb 100644 --- a/tests/rustdoc-json/enums/discriminant/basic.rs +++ b/tests/rustdoc-json/enums/discriminant/basic.rs @@ -1,12 +1,12 @@ #[repr(i8)] pub enum Ordering { - // @is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.expr" '"-1"' - // @is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.value" '"-1"' + //@ is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.expr" '"-1"' + //@ is "$.index[*][?(@.name=='Less')].inner.variant.discriminant.value" '"-1"' Less = -1, - // @is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.expr" '"0"' - // @is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.expr" '"0"' + //@ is "$.index[*][?(@.name=='Equal')].inner.variant.discriminant.value" '"0"' Equal = 0, - // @is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.expr" '"1"' - // @is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.value" '"1"' + //@ is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.expr" '"1"' + //@ is "$.index[*][?(@.name=='Greater')].inner.variant.discriminant.value" '"1"' Greater = 1, } diff --git a/tests/rustdoc-json/enums/discriminant/expr.rs b/tests/rustdoc-json/enums/discriminant/expr.rs index ddcad58a550..bf2bce85108 100644 --- a/tests/rustdoc-json/enums/discriminant/expr.rs +++ b/tests/rustdoc-json/enums/discriminant/expr.rs @@ -1,30 +1,30 @@ pub enum Foo { - // @is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[*][?(@.name=='Addition')].inner.variant.discriminant.expr" '"{ _ }"' Addition = 0 + 0, - // @is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.value" '"1"' - // @is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.expr" '"0b1"' + //@ is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.value" '"1"' + //@ is "$.index[*][?(@.name=='Bin')].inner.variant.discriminant.expr" '"0b1"' Bin = 0b1, - // @is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.value" '"2"' - // @is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.expr" '"0o2"' + //@ is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.value" '"2"' + //@ is "$.index[*][?(@.name=='Oct')].inner.variant.discriminant.expr" '"0o2"' Oct = 0o2, - // @is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.value" '"3"' - // @is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.expr" '"THREE"' + //@ is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.value" '"3"' + //@ is "$.index[*][?(@.name=='PubConst')].inner.variant.discriminant.expr" '"THREE"' PubConst = THREE, - // @is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.value" '"4"' - // @is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.expr" '"0x4"' + //@ is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.value" '"4"' + //@ is "$.index[*][?(@.name=='Hex')].inner.variant.discriminant.expr" '"0x4"' Hex = 0x4, - // @is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.value" '"5"' - // @is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.value" '"5"' + //@ is "$.index[*][?(@.name=='Cast')].inner.variant.discriminant.expr" '"{ _ }"' Cast = 5 as isize, - // @is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.value" '"6"' - // @is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.value" '"6"' + //@ is "$.index[*][?(@.name=='PubCall')].inner.variant.discriminant.expr" '"{ _ }"' PubCall = six(), - // @is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.value" '"7"' - // @is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.expr" '"{ _ }"' + //@ is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.value" '"7"' + //@ is "$.index[*][?(@.name=='PrivCall')].inner.variant.discriminant.expr" '"{ _ }"' PrivCall = seven(), - // @is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.value" '"8"' - // @is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.expr" '"EIGHT"' + //@ is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.value" '"8"' + //@ is "$.index[*][?(@.name=='PrivConst')].inner.variant.discriminant.expr" '"EIGHT"' PrivConst = EIGHT, } diff --git a/tests/rustdoc-json/enums/discriminant/limits.rs b/tests/rustdoc-json/enums/discriminant/limits.rs index 47fb7040896..a023c9fbf6e 100644 --- a/tests/rustdoc-json/enums/discriminant/limits.rs +++ b/tests/rustdoc-json/enums/discriminant/limits.rs @@ -4,40 +4,40 @@ #[repr(u64)] pub enum U64 { - // @is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.expr" '"u64::MIN"' + //@ is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[*][?(@.name=='U64Min')].inner.variant.discriminant.expr" '"u64::MIN"' U64Min = u64::MIN, - // @is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.value" '"18446744073709551615"' - // @is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.expr" '"u64::MAX"' + //@ is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.value" '"18446744073709551615"' + //@ is "$.index[*][?(@.name=='U64Max')].inner.variant.discriminant.expr" '"u64::MAX"' U64Max = u64::MAX, } #[repr(i64)] pub enum I64 { - // @is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.value" '"-9223372036854775808"' - // @is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.expr" '"i64::MIN"' + //@ is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.value" '"-9223372036854775808"' + //@ is "$.index[*][?(@.name=='I64Min')].inner.variant.discriminant.expr" '"i64::MIN"' I64Min = i64::MIN, - // @is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.value" '"9223372036854775807"' - // @is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.expr" '"i64::MAX"' + //@ is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.value" '"9223372036854775807"' + //@ is "$.index[*][?(@.name=='I64Max')].inner.variant.discriminant.expr" '"i64::MAX"' I64Max = i64::MAX, } #[repr(u128)] pub enum U128 { - // @is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.expr" '"u128::MIN"' + //@ is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[*][?(@.name=='U128Min')].inner.variant.discriminant.expr" '"u128::MIN"' U128Min = u128::MIN, - // @is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.value" '"340282366920938463463374607431768211455"' - // @is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.expr" '"u128::MAX"' + //@ is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.value" '"340282366920938463463374607431768211455"' + //@ is "$.index[*][?(@.name=='U128Max')].inner.variant.discriminant.expr" '"u128::MAX"' U128Max = u128::MAX, } #[repr(i128)] pub enum I128 { - // @is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.value" '"-170141183460469231731687303715884105728"' - // @is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.expr" '"i128::MIN"' + //@ is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.value" '"-170141183460469231731687303715884105728"' + //@ is "$.index[*][?(@.name=='I128Min')].inner.variant.discriminant.expr" '"i128::MIN"' I128Min = i128::MIN, - // @is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.value" '"170141183460469231731687303715884105727"' - // @is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.expr" '"i128::MAX"' + //@ is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.value" '"170141183460469231731687303715884105727"' + //@ is "$.index[*][?(@.name=='I128Max')].inner.variant.discriminant.expr" '"i128::MAX"' I128Max = i128::MAX, } diff --git a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs index 9c3db81c663..f16a74d638b 100644 --- a/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs +++ b/tests/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs @@ -2,16 +2,16 @@ #[repr(u32)] pub enum Foo { - // @is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.value" '"0"' - // @is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.expr" '"0"' + //@ is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.value" '"0"' + //@ is "$.index[*][?(@.name=='Basic')].inner.variant.discriminant.expr" '"0"' Basic = 0, - // @is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.value" '"10"' - // @is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.expr" '"10u32"' + //@ is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.value" '"10"' + //@ is "$.index[*][?(@.name=='Suffix')].inner.variant.discriminant.expr" '"10u32"' Suffix = 10u32, - // @is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.value" '"100"' - // @is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.expr" '"1_0_0"' + //@ is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.value" '"100"' + //@ is "$.index[*][?(@.name=='Underscore')].inner.variant.discriminant.expr" '"1_0_0"' Underscore = 1_0_0, - // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.value" '"1000"' - // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.expr" '"1_0_0_0u32"' + //@ is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.value" '"1000"' + //@ is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant.discriminant.expr" '"1_0_0_0u32"' SuffixUnderscore = 1_0_0_0u32, } diff --git a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs index 38ba1caf140..522545d34d0 100644 --- a/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs +++ b/tests/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs @@ -1,12 +1,12 @@ // ignore-tidy-linelength pub enum Foo { - // @is "$.index[*][?(@.name=='Has')].inner.variant.discriminant" '{"expr":"0", "value":"0"}' + //@ is "$.index[*][?(@.name=='Has')].inner.variant.discriminant" '{"expr":"0", "value":"0"}' Has = 0, - // @is "$.index[*][?(@.name=='Doesnt')].inner.variant.discriminant" null + //@ is "$.index[*][?(@.name=='Doesnt')].inner.variant.discriminant" null Doesnt, - // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant.discriminant" null + //@ is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant.discriminant" null AlsoDoesnt, - // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant.discriminant" '{"expr":"44", "value":"44"}' + //@ is "$.index[*][?(@.name=='AlsoHas')].inner.variant.discriminant" '{"expr":"44", "value":"44"}' AlsoHas = 44, } diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index c4b087c3635..0ac40cda733 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,15 +1,15 @@ // ignore-tidy-linelength #[repr(i32)] -// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' pub enum Foo { - // @is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null - // @count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 + //@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null + //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 Struct {}, - // @is "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.discriminant" '{"expr": "42", "value": "42"}' - // @count "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.kind.struct.fields[*]" 1 + //@ is "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.discriminant" '{"expr": "42", "value": "42"}' + //@ count "$.index[*][?(@.name=='StructWithDiscr')].inner.variant.kind.struct.fields[*]" 1 StructWithDiscr { x: i32 } = 42, - // @is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.discriminant" '{"expr": "0x42", "value": "66"}' - // @count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.kind.struct.fields[*]" 2 + //@ is "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.discriminant" '{"expr": "0x42", "value": "66"}' + //@ count "$.index[*][?(@.name=='StructWithHexDiscr')].inner.variant.kind.struct.fields[*]" 2 StructWithHexDiscr { x: i32, y: bool } = 0x42, } diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index 7da82ec8ea4..fbff5aacd67 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,15 +1,15 @@ // ignore-tidy-linelength #[repr(u32)] -// @is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' +//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' pub enum Foo { - // @is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null - // @count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 + //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null + //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 Tuple(), - // @is "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.discriminant" '{"expr": "1", "value": "1"}' - // @count "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.discriminant" '{"expr": "1", "value": "1"}' + //@ count "$.index[*][?(@.name=='TupleWithDiscr')].inner.variant.kind.tuple[*]" 1 TupleWithDiscr(i32) = 1, - // @is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.discriminant" '{"expr": "0b10", "value": "2"}' - // @count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.discriminant" '{"expr": "0b10", "value": "2"}' + //@ count "$.index[*][?(@.name=='TupleWithBinDiscr')].inner.variant.kind.tuple[*]" 2 TupleWithBinDiscr(i32, i32) = 0b10, } diff --git a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs index 784a93c893a..6aec6960b5f 100644 --- a/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs +++ b/tests/rustdoc-json/enums/doc_link_to_foreign_variant.rs @@ -5,7 +5,7 @@ extern crate color; use color::Color::Red; -// @set red = "$.index[*][?(@.inner.module.is_crate)].links.Red" +//@ set red = "$.index[*][?(@.inner.module.is_crate)].links.Red" -// @!has "$.index[*][?(@.name == 'Red')]" -// @!has "$.index[*][?(@.name == 'Color')]" +//@ !has "$.index[*][?(@.name == 'Red')]" +//@ !has "$.index[*][?(@.name == 'Color')]" diff --git a/tests/rustdoc-json/enums/field_hidden.rs b/tests/rustdoc-json/enums/field_hidden.rs index 74d96248d5c..b353678ac92 100644 --- a/tests/rustdoc-json/enums/field_hidden.rs +++ b/tests/rustdoc-json/enums/field_hidden.rs @@ -1,9 +1,9 @@ // Regression test for <https://github.com/rust-lang/rust/issues/100529>. -// @has "$.index[*][?(@.name=='ParseError')]" -// @has "$.index[*][?(@.name=='UnexpectedEndTag')]" -// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.kind.tuple" [null] -// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.discriminant" null +//@ has "$.index[*][?(@.name=='ParseError')]" +//@ has "$.index[*][?(@.name=='UnexpectedEndTag')]" +//@ is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.kind.tuple" [null] +//@ is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant.discriminant" null pub enum ParseError { UnexpectedEndTag(#[doc(hidden)] u32), diff --git a/tests/rustdoc-json/enums/field_order.rs b/tests/rustdoc-json/enums/field_order.rs index e89add9cbbd..a78be200b41 100644 --- a/tests/rustdoc-json/enums/field_order.rs +++ b/tests/rustdoc-json/enums/field_order.rs @@ -17,24 +17,24 @@ pub enum Whatever { }, } -// @set 0 = '$.index[*][?(@.name == "ews_0")].id' -// @set 1 = '$.index[*][?(@.name == "dik_1")].id' -// @set 2 = '$.index[*][?(@.name == "hsk_2")].id' -// @set 3 = '$.index[*][?(@.name == "djt_3")].id' -// @set 4 = '$.index[*][?(@.name == "jnr_4")].id' -// @set 5 = '$.index[*][?(@.name == "dfs_5")].id' -// @set 6 = '$.index[*][?(@.name == "bja_6")].id' -// @set 7 = '$.index[*][?(@.name == "lyc_7")].id' -// @set 8 = '$.index[*][?(@.name == "yqd_8")].id' -// @set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' +//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' +//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' +//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' +//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[0]' $0 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[1]' $1 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[2]' $2 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[3]' $3 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[4]' $4 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[5]' $5 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[6]' $6 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[7]' $7 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[8]' $8 -// @is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[9]' $9 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[0]' $0 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[1]' $1 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[2]' $2 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[3]' $3 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[4]' $4 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[5]' $5 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[6]' $6 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[7]' $7 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[8]' $8 +//@ is '$.index[*][?(@.name == "Foo")].inner.variant.kind.struct.fields[9]' $9 diff --git a/tests/rustdoc-json/enums/kind.rs b/tests/rustdoc-json/enums/kind.rs index 68483683464..ef3d9363d64 100644 --- a/tests/rustdoc-json/enums/kind.rs +++ b/tests/rustdoc-json/enums/kind.rs @@ -1,29 +1,29 @@ // ignore-tidy-linelength pub enum Foo { - // @set Unit = "$.index[*][?(@.name=='Unit')].id" - // @is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"' + //@ set Unit = "$.index[*][?(@.name=='Unit')].id" + //@ is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"' Unit, - // @set Named = "$.index[*][?(@.name=='Named')].id" - // @is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "fields_stripped": false}' + //@ set Named = "$.index[*][?(@.name=='Named')].id" + //@ is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "fields_stripped": false}' Named {}, - // @set Tuple = "$.index[*][?(@.name=='Tuple')].id" - // @is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" [] + //@ set Tuple = "$.index[*][?(@.name=='Tuple')].id" + //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" [] Tuple(), - // @set NamedField = "$.index[*][?(@.name=='NamedField')].id" - // @set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id" - // @is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x - // @is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields_stripped" false + //@ set NamedField = "$.index[*][?(@.name=='NamedField')].id" + //@ set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id" + //@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x + //@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields_stripped" false NamedField { x: i32 }, - // @set TupleField = "$.index[*][?(@.name=='TupleField')].id" - // @set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id" - // @is "$.index[*][?(@.name=='TupleField')].inner.variant.kind.tuple[*]" $tup_field + //@ set TupleField = "$.index[*][?(@.name=='TupleField')].id" + //@ set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id" + //@ is "$.index[*][?(@.name=='TupleField')].inner.variant.kind.tuple[*]" $tup_field TupleField(i32), } -// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[0]" $Unit -// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[1]" $Named -// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[2]" $Tuple -// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[3]" $NamedField -// @is "$.index[*][?(@.name=='Foo')].inner.enum.variants[4]" $TupleField -// @count "$.index[*][?(@.name=='Foo')].inner.enum.variants[*]" 5 +//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[0]" $Unit +//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[1]" $Named +//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[2]" $Tuple +//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[3]" $NamedField +//@ is "$.index[*][?(@.name=='Foo')].inner.enum.variants[4]" $TupleField +//@ count "$.index[*][?(@.name=='Foo')].inner.enum.variants[*]" 5 diff --git a/tests/rustdoc-json/enums/struct_field_hidden.rs b/tests/rustdoc-json/enums/struct_field_hidden.rs index 2676c4e4157..b724f9abb71 100644 --- a/tests/rustdoc-json/enums/struct_field_hidden.rs +++ b/tests/rustdoc-json/enums/struct_field_hidden.rs @@ -2,15 +2,15 @@ pub enum Foo { Variant { #[doc(hidden)] a: i32, - // @set b = "$.index[*][?(@.name=='b')].id" + //@ set b = "$.index[*][?(@.name=='b')].id" b: i32, #[doc(hidden)] x: i32, - // @set y = "$.index[*][?(@.name=='y')].id" + //@ set y = "$.index[*][?(@.name=='y')].id" y: i32, }, - // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields_stripped" true - // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b - // @is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y - // @count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2 + //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields_stripped" true + //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b + //@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y + //@ count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2 } diff --git a/tests/rustdoc-json/enums/tuple_fields_hidden.rs b/tests/rustdoc-json/enums/tuple_fields_hidden.rs index 53cdf83ffa6..3ac7a3ce0fc 100644 --- a/tests/rustdoc-json/enums/tuple_fields_hidden.rs +++ b/tests/rustdoc-json/enums/tuple_fields_hidden.rs @@ -1,80 +1,80 @@ -// @set 1.1.0 = "$.index[*][?(@.docs=='1.1.0')].id" -// @set 2.1.0 = "$.index[*][?(@.docs=='2.1.0')].id" -// @set 2.1.1 = "$.index[*][?(@.docs=='2.1.1')].id" -// @set 2.2.1 = "$.index[*][?(@.docs=='2.2.1')].id" -// @set 2.3.0 = "$.index[*][?(@.docs=='2.3.0')].id" -// @set 3.1.1 = "$.index[*][?(@.docs=='3.1.1')].id" -// @set 3.1.2 = "$.index[*][?(@.docs=='3.1.2')].id" -// @set 3.2.0 = "$.index[*][?(@.docs=='3.2.0')].id" -// @set 3.2.2 = "$.index[*][?(@.docs=='3.2.2')].id" -// @set 3.3.0 = "$.index[*][?(@.docs=='3.3.0')].id" -// @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id" +//@ set 1.1.0 = "$.index[*][?(@.docs=='1.1.0')].id" +//@ set 2.1.0 = "$.index[*][?(@.docs=='2.1.0')].id" +//@ set 2.1.1 = "$.index[*][?(@.docs=='2.1.1')].id" +//@ set 2.2.1 = "$.index[*][?(@.docs=='2.2.1')].id" +//@ set 2.3.0 = "$.index[*][?(@.docs=='2.3.0')].id" +//@ set 3.1.1 = "$.index[*][?(@.docs=='3.1.1')].id" +//@ set 3.1.2 = "$.index[*][?(@.docs=='3.1.2')].id" +//@ set 3.2.0 = "$.index[*][?(@.docs=='3.2.0')].id" +//@ set 3.2.2 = "$.index[*][?(@.docs=='3.2.2')].id" +//@ set 3.3.0 = "$.index[*][?(@.docs=='3.3.0')].id" +//@ set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id" pub enum EnumWithStrippedTupleVariants { - // @count "$.index[*][?(@.name=='None')].inner.variant.kind.tuple[*]" 0 + //@ count "$.index[*][?(@.name=='None')].inner.variant.kind.tuple[*]" 0 None(), - // @count "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[*]" 1 - // @is "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[0]" $1.1.0 + //@ count "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[*][?(@.name=='One')].inner.variant.kind.tuple[0]" $1.1.0 One(/** 1.1.0*/ bool), - // @count "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[*]" 1 - // @is "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[0]" null + //@ count "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[*]" 1 + //@ is "$.index[*][?(@.name=='OneHidden')].inner.variant.kind.tuple[0]" null OneHidden(#[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[0]" $2.1.0 - // @is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[1]" $2.1.1 + //@ count "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[0]" $2.1.0 + //@ is "$.index[*][?(@.name=='Two')].inner.variant.kind.tuple[1]" $2.1.1 Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool), - // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[1]" $2.2.1 + //@ count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[0]" null + //@ is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant.kind.tuple[1]" $2.2.1 TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool), - // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[0]" $2.3.0 - // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[1]" null + //@ count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[0]" $2.3.0 + //@ is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant.kind.tuple[1]" null TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[*]" 2 - // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[1]" null + //@ count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[*]" 2 + //@ is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[0]" null + //@ is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant.kind.tuple[1]" null TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool), - // @count "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[0]" null - // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[1]" $3.1.1 - // @is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[2]" $3.1.2 + //@ count "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[0]" null + //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[1]" $3.1.1 + //@ is "$.index[*][?(@.name=='Three1')].inner.variant.kind.tuple[2]" $3.1.2 Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool), - // @count "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[0]" $3.2.0 - // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[1]" null - // @is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[2]" $3.2.2 + //@ count "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[0]" $3.2.0 + //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[1]" null + //@ is "$.index[*][?(@.name=='Three2')].inner.variant.kind.tuple[2]" $3.2.2 Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool), - // @count "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[*]" 3 - // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[0]" $3.3.0 - // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[1]" $3.3.1 - // @is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[2]" null + //@ count "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[*]" 3 + //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[0]" $3.3.0 + //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[1]" $3.3.1 + //@ is "$.index[*][?(@.name=='Three3')].inner.variant.kind.tuple[2]" null Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool), } -// @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"' -// @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"' -// @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"' -// @is "$.index[*][?(@.docs=='2.2.1')].name" '"1"' -// @is "$.index[*][?(@.docs=='2.3.0')].name" '"0"' -// @is "$.index[*][?(@.docs=='3.1.1')].name" '"1"' -// @is "$.index[*][?(@.docs=='3.1.2')].name" '"2"' -// @is "$.index[*][?(@.docs=='3.2.0')].name" '"0"' -// @is "$.index[*][?(@.docs=='3.2.2')].name" '"2"' -// @is "$.index[*][?(@.docs=='3.3.0')].name" '"0"' -// @is "$.index[*][?(@.docs=='3.3.1')].name" '"1"' +//@ is "$.index[*][?(@.docs=='1.1.0')].name" '"0"' +//@ is "$.index[*][?(@.docs=='2.1.0')].name" '"0"' +//@ is "$.index[*][?(@.docs=='2.1.1')].name" '"1"' +//@ is "$.index[*][?(@.docs=='2.2.1')].name" '"1"' +//@ is "$.index[*][?(@.docs=='2.3.0')].name" '"0"' +//@ is "$.index[*][?(@.docs=='3.1.1')].name" '"1"' +//@ is "$.index[*][?(@.docs=='3.1.2')].name" '"2"' +//@ is "$.index[*][?(@.docs=='3.2.0')].name" '"0"' +//@ is "$.index[*][?(@.docs=='3.2.2')].name" '"2"' +//@ is "$.index[*][?(@.docs=='3.3.0')].name" '"0"' +//@ is "$.index[*][?(@.docs=='3.3.1')].name" '"1"' -// @is "$.index[*][?(@.docs=='1.1.0')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='2.1.0')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='2.1.1')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='2.2.1')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='2.3.0')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.1.1')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.1.2')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.2.0')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.2.2')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.3.0')].inner.struct_field" '{"primitive": "bool"}' -// @is "$.index[*][?(@.docs=='3.3.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='1.1.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='2.1.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='2.1.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='2.2.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='2.3.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.1.1')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.1.2')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.2.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.2.2')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.3.0')].inner.struct_field" '{"primitive": "bool"}' +//@ is "$.index[*][?(@.docs=='3.3.1')].inner.struct_field" '{"primitive": "bool"}' diff --git a/tests/rustdoc-json/enums/use_glob.rs b/tests/rustdoc-json/enums/use_glob.rs index bec89530b05..61766d2a629 100644 --- a/tests/rustdoc-json/enums/use_glob.rs +++ b/tests/rustdoc-json/enums/use_glob.rs @@ -1,15 +1,15 @@ // Regression test for <https://github.com/rust-lang/rust/issues/104942> -// @set Color = "$.index[*][?(@.name == 'Color')].id" +//@ set Color = "$.index[*][?(@.name == 'Color')].id" pub enum Color { Red, Green, Blue, } -// @set use_Color = "$.index[*][?(@.inner.import)].id" -// @is "$.index[*][?(@.inner.import)].inner.import.id" $Color -// @is "$.index[*][?(@.inner.import)].inner.import.glob" true +//@ set use_Color = "$.index[*][?(@.inner.import)].id" +//@ is "$.index[*][?(@.inner.import)].inner.import.id" $Color +//@ is "$.index[*][?(@.inner.import)].inner.import.glob" true pub use Color::*; -// @ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color +//@ ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color diff --git a/tests/rustdoc-json/enums/use_variant.rs b/tests/rustdoc-json/enums/use_variant.rs index c7e0c21f1ef..9010d616493 100644 --- a/tests/rustdoc-json/enums/use_variant.rs +++ b/tests/rustdoc-json/enums/use_variant.rs @@ -1,12 +1,12 @@ -// @set AlwaysNone = "$.index[*][?(@.name == 'AlwaysNone')].id" +//@ set AlwaysNone = "$.index[*][?(@.name == 'AlwaysNone')].id" pub enum AlwaysNone { - // @set None = "$.index[*][?(@.name == 'None')].id" + //@ set None = "$.index[*][?(@.name == 'None')].id" None, } -// @is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None +//@ is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None -// @set use_None = "$.index[*][?(@.inner.import)].id" -// @is "$.index[*][?(@.inner.import)].inner.import.id" $None +//@ set use_None = "$.index[*][?(@.inner.import)].id" +//@ is "$.index[*][?(@.inner.import)].inner.import.id" $None pub use AlwaysNone::None; -// @ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None +//@ ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None diff --git a/tests/rustdoc-json/enums/use_variant_foreign.rs b/tests/rustdoc-json/enums/use_variant_foreign.rs index c42ead64461..0f3f16ff835 100644 --- a/tests/rustdoc-json/enums/use_variant_foreign.rs +++ b/tests/rustdoc-json/enums/use_variant_foreign.rs @@ -2,8 +2,8 @@ extern crate color; -// @has "$.index[*].inner.import[?(@.name == 'Red')]" +//@ has "$.index[*].inner.import[?(@.name == 'Red')]" pub use color::Color::Red; -// @!has "$.index[*][?(@.name == 'Red')]" -// @!has "$.index[*][?(@.name == 'Color')]" +//@ !has "$.index[*][?(@.name == 'Red')]" +//@ !has "$.index[*][?(@.name == 'Color')]" diff --git a/tests/rustdoc-json/enums/variant_order.rs b/tests/rustdoc-json/enums/variant_order.rs index 17ca96213de..6ebe28c94ca 100644 --- a/tests/rustdoc-json/enums/variant_order.rs +++ b/tests/rustdoc-json/enums/variant_order.rs @@ -15,24 +15,24 @@ pub enum Foo { Vll9, } -// @set 0 = '$.index[*][?(@.name == "Ews0")].id' -// @set 1 = '$.index[*][?(@.name == "Dik1")].id' -// @set 2 = '$.index[*][?(@.name == "Hsk2")].id' -// @set 3 = '$.index[*][?(@.name == "Djt3")].id' -// @set 4 = '$.index[*][?(@.name == "Jnr4")].id' -// @set 5 = '$.index[*][?(@.name == "Dfs5")].id' -// @set 6 = '$.index[*][?(@.name == "Bja6")].id' -// @set 7 = '$.index[*][?(@.name == "Lyc7")].id' -// @set 8 = '$.index[*][?(@.name == "Yqd8")].id' -// @set 9 = '$.index[*][?(@.name == "Vll9")].id' +//@ set 0 = '$.index[*][?(@.name == "Ews0")].id' +//@ set 1 = '$.index[*][?(@.name == "Dik1")].id' +//@ set 2 = '$.index[*][?(@.name == "Hsk2")].id' +//@ set 3 = '$.index[*][?(@.name == "Djt3")].id' +//@ set 4 = '$.index[*][?(@.name == "Jnr4")].id' +//@ set 5 = '$.index[*][?(@.name == "Dfs5")].id' +//@ set 6 = '$.index[*][?(@.name == "Bja6")].id' +//@ set 7 = '$.index[*][?(@.name == "Lyc7")].id' +//@ set 8 = '$.index[*][?(@.name == "Yqd8")].id' +//@ set 9 = '$.index[*][?(@.name == "Vll9")].id' -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[0]' $0 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[1]' $1 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[2]' $2 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[3]' $3 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[4]' $4 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[5]' $5 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[6]' $6 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[7]' $7 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[8]' $8 -// @is '$.index[*][?(@.name == "Foo")].inner.enum.variants[9]' $9 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[0]' $0 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[1]' $1 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[2]' $2 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[3]' $3 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[4]' $4 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[5]' $5 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[6]' $6 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[7]' $7 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[8]' $8 +//@ is '$.index[*][?(@.name == "Foo")].inner.enum.variants[9]' $9 diff --git a/tests/rustdoc-json/enums/variant_struct.rs b/tests/rustdoc-json/enums/variant_struct.rs index fe40f1a5d5d..44a0c946711 100644 --- a/tests/rustdoc-json/enums/variant_struct.rs +++ b/tests/rustdoc-json/enums/variant_struct.rs @@ -1,10 +1,10 @@ -// @is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" -// @has "$.index[*][?(@.name=='EnumStruct')].inner.enum" +//@ is "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='EnumStruct')].inner.enum" pub enum EnumStruct { - // @has "$.index[*][?(@.name=='x')].inner.struct_field" - // @set x = "$.index[*][?(@.name=='x')].id" - // @has "$.index[*][?(@.name=='y')].inner.struct_field" - // @set y = "$.index[*][?(@.name=='y')].id" - // @ismany "$.index[*][?(@.name=='VariantS')].inner.variant.kind.struct.fields[*]" $x $y + //@ has "$.index[*][?(@.name=='x')].inner.struct_field" + //@ set x = "$.index[*][?(@.name=='x')].id" + //@ has "$.index[*][?(@.name=='y')].inner.struct_field" + //@ set y = "$.index[*][?(@.name=='y')].id" + //@ ismany "$.index[*][?(@.name=='VariantS')].inner.variant.kind.struct.fields[*]" $x $y VariantS { x: u32, y: String }, } diff --git a/tests/rustdoc-json/enums/variant_tuple_struct.rs b/tests/rustdoc-json/enums/variant_tuple_struct.rs index 358fc1079cb..04f0cbb40c4 100644 --- a/tests/rustdoc-json/enums/variant_tuple_struct.rs +++ b/tests/rustdoc-json/enums/variant_tuple_struct.rs @@ -1,10 +1,10 @@ -// @is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" -// @has "$.index[*][?(@.name=='EnumTupleStruct')].inner.enum" +//@ is "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='EnumTupleStruct')].inner.enum" pub enum EnumTupleStruct { - // @has "$.index[*][?(@.name=='0')].inner.struct_field" - // @set f0 = "$.index[*][?(@.name=='0')].id" - // @has "$.index[*][?(@.name=='1')].inner.struct_field" - // @set f1 = "$.index[*][?(@.name=='1')].id" - // @ismany "$.index[*][?(@.name=='VariantA')].inner.variant.kind.tuple[*]" $f0 $f1 + //@ has "$.index[*][?(@.name=='0')].inner.struct_field" + //@ set f0 = "$.index[*][?(@.name=='0')].id" + //@ has "$.index[*][?(@.name=='1')].inner.struct_field" + //@ set f1 = "$.index[*][?(@.name=='1')].id" + //@ ismany "$.index[*][?(@.name=='VariantA')].inner.variant.kind.tuple[*]" $f0 $f1 VariantA(u32, String), } diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs index dbe316f573d..03fbb3b795d 100644 --- a/tests/rustdoc-json/fn_pointer/abi.rs +++ b/tests/rustdoc-json/fn_pointer/abi.rs @@ -2,23 +2,23 @@ #![feature(abi_vectorcall)] -// @is "$.index[*][?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" +//@ is "$.index[*][?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" pub type AbiRust = fn(); -// @is "$.index[*][?(@.name=='AbiC')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": false}}' +//@ is "$.index[*][?(@.name=='AbiC')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": false}}' pub type AbiC = extern "C" fn(); -// @is "$.index[*][?(@.name=='AbiSystem')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": false}}' +//@ is "$.index[*][?(@.name=='AbiSystem')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": false}}' pub type AbiSystem = extern "system" fn(); -// @is "$.index[*][?(@.name=='AbiCUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": true}}' +//@ is "$.index[*][?(@.name=='AbiCUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"C": {"unwind": true}}' pub type AbiCUnwind = extern "C-unwind" fn(); -// @is "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' +//@ is "$.index[*][?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' pub type AbiSystemUnwind = extern "system-unwind" fn(); -// @is "$.index[*][?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' +//@ is "$.index[*][?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' pub type AbiVecorcall = extern "vectorcall" fn(); -// @is "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' +//@ is "$.index[*][?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); diff --git a/tests/rustdoc-json/fn_pointer/generics.rs b/tests/rustdoc-json/fn_pointer/generics.rs index 8b3a8c0a74e..9f5d23ae421 100644 --- a/tests/rustdoc-json/fn_pointer/generics.rs +++ b/tests/rustdoc-json/fn_pointer/generics.rs @@ -1,10 +1,10 @@ // ignore-tidy-linelength -// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][0]" '"val"' -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][1].borrowed_ref.lifetime" \"\'c\" -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.output.primitive" \"i32\" -// @count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\" -// @is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][0]" '"val"' +//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][1].borrowed_ref.lifetime" \"\'c\" +//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.output.primitive" \"i32\" +//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1 +//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\" +//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' pub type WithHigherRankTraitBounds = for<'c> fn(val: &'c i32) -> i32; diff --git a/tests/rustdoc-json/fn_pointer/qualifiers.rs b/tests/rustdoc-json/fn_pointer/qualifiers.rs index 1a62eb2bae8..9c0e6c0ccf1 100644 --- a/tests/rustdoc-json/fn_pointer/qualifiers.rs +++ b/tests/rustdoc-json/fn_pointer/qualifiers.rs @@ -1,11 +1,11 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.unsafe" false -// @is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.const" false -// @is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.async" false +//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.unsafe" false +//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.const" false +//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.async" false pub type FnPointer = fn(); -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.unsafe" true -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.const" false -// @is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.async" false +//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.unsafe" true +//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.const" false +//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.async" false pub type UnsafePointer = unsafe fn(); diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs index d7b98b5924b..2f6413cee6f 100644 --- a/tests/rustdoc-json/fns/abi.rs +++ b/tests/rustdoc-json/fns/abi.rs @@ -2,23 +2,23 @@ #![feature(abi_vectorcall)] -// @is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" +//@ is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} -// @is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' +//@ is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} -// @is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' +//@ is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} -// @is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' +//@ is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} -// @is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' +//@ is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} -// @is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' +//@ is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} -// @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' +//@ is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} diff --git a/tests/rustdoc-json/fns/async_return.rs b/tests/rustdoc-json/fns/async_return.rs index 32117d73657..e029c72df21 100644 --- a/tests/rustdoc-json/fns/async_return.rs +++ b/tests/rustdoc-json/fns/async_return.rs @@ -5,30 +5,30 @@ use std::future::Future; -// @is "$.index[*][?(@.name=='get_int')].inner.function.decl.output.primitive" \"i32\" -// @is "$.index[*][?(@.name=='get_int')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='get_int')].inner.function.decl.output.primitive" \"i32\" +//@ is "$.index[*][?(@.name=='get_int')].inner.function.header.async" false pub fn get_int() -> i32 { 42 } -// @is "$.index[*][?(@.name=='get_int_async')].inner.function.decl.output.primitive" \"i32\" -// @is "$.index[*][?(@.name=='get_int_async')].inner.function.header.async" true +//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.decl.output.primitive" \"i32\" +//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.header.async" true pub async fn get_int_async() -> i32 { 42 } -// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' -// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' -// @is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" -// @is "$.index[*][?(@.name=='get_int_future')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' +//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' +//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" +//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.async" false pub fn get_int_future() -> impl Future<Output = i32> { async { 42 } } -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" -// @is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.async" true +//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"' +//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"' +//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\" +//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.async" true pub async fn get_int_future_async() -> impl Future<Output = i32> { async { 42 } } diff --git a/tests/rustdoc-json/fns/extern_c_variadic.rs b/tests/rustdoc-json/fns/extern_c_variadic.rs index eef9ae99eb0..defe66345e8 100644 --- a/tests/rustdoc-json/fns/extern_c_variadic.rs +++ b/tests/rustdoc-json/fns/extern_c_variadic.rs @@ -1,6 +1,6 @@ extern "C" { - // @is "$.index[*][?(@.name == 'not_variadic')].inner.function.decl.c_variadic" false + //@ is "$.index[*][?(@.name == 'not_variadic')].inner.function.decl.c_variadic" false pub fn not_variadic(_: i32); - // @is "$.index[*][?(@.name == 'variadic')].inner.function.decl.c_variadic" true + //@ is "$.index[*][?(@.name == 'variadic')].inner.function.decl.c_variadic" true pub fn variadic(_: i32, ...); } diff --git a/tests/rustdoc-json/fns/generic_args.rs b/tests/rustdoc-json/fns/generic_args.rs index 2f6cf3bf65a..75c5fcbb01f 100644 --- a/tests/rustdoc-json/fns/generic_args.rs +++ b/tests/rustdoc-json/fns/generic_args.rs @@ -1,60 +1,60 @@ // ignore-tidy-linelength -// @set foo = "$.index[*][?(@.name=='Foo')].id" +//@ set foo = "$.index[*][?(@.name=='Foo')].id" pub trait Foo {} -// @set generic_foo = "$.index[*][?(@.name=='GenericFoo')].id" +//@ set generic_foo = "$.index[*][?(@.name=='GenericFoo')].id" pub trait GenericFoo<'a> {} -// @is "$.index[*][?(@.name=='generics')].inner.function.generics.where_predicates" "[]" -// @count "$.index[*][?(@.name=='generics')].inner.function.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].name" '"F"' -// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null' -// @count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' -// @count "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][0]" '"f"' -// @is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][1].generic" '"F"' +//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.where_predicates" "[]" +//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[*]" 1 +//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].name" '"F"' +//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null' +//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo' +//@ count "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][0]" '"f"' +//@ is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][1].generic" '"F"' pub fn generics<F: Foo>(f: F) {} -// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]" -// @count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"' -// @is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo -// @count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][0]" '"f"' -// @count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[*]" 1 -// @is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo +//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]" +//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1 +//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"' +//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo +//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][0]" '"f"' +//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[*]" 1 +//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo pub fn impl_trait(f: impl Foo) {} -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"' -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}' -// @count "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][0]" '"f"' -// @is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][1].generic" '"F"' -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3 +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"' +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}' +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[*]" 3 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][0]" '"f"' +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][1].generic" '"F"' +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\" -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\" +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].trait_bound.trait.id" $foo -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.type.generic" \"G\" -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind.lifetime.outlives" "[]" -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.generic_params" "[]" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.type.generic" \"G\" +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.trait.id" $generic_foo +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[*]" 1 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].name" \"\'a\" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.bounds[0].trait_bound.generic_params[0].kind.lifetime.outlives" "[]" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[1].bound_predicate.generic_params" "[]" -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.lifetime" \"\'b\" -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.type.generic" \"H\" -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" -// @count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" -// @is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].kind.lifetime.outlives" "[]" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.lifetime" \"\'b\" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.type.borrowed_ref.type.generic" \"H\" +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.trait.id" $foo +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.bounds[0].trait_bound.generic_params" "[]" +//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[*]" 1 +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].name" \"\'b\" +//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[2].bound_predicate.generic_params[0].kind.lifetime.outlives" "[]" pub fn where_clase<F, G, H>(f: F, g: G, h: H) where F: Foo, diff --git a/tests/rustdoc-json/fns/generic_returns.rs b/tests/rustdoc-json/fns/generic_returns.rs index 8e82efef4be..07dc691b933 100644 --- a/tests/rustdoc-json/fns/generic_returns.rs +++ b/tests/rustdoc-json/fns/generic_returns.rs @@ -1,13 +1,13 @@ // ignore-tidy-linelength -// @count "$.index[*][?(@.name=='generic_returns')].inner.module.items[*]" 2 +//@ count "$.index[*][?(@.name=='generic_returns')].inner.module.items[*]" 2 -// @set foo = "$.index[*][?(@.name=='Foo')].id" +//@ set foo = "$.index[*][?(@.name=='Foo')].id" pub trait Foo {} -// @is "$.index[*][?(@.name=='get_foo')].inner.function.decl.inputs" [] -// @count "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[*]" 1 -// @is "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $foo +//@ is "$.index[*][?(@.name=='get_foo')].inner.function.decl.inputs" [] +//@ count "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[*]" 1 +//@ is "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $foo pub fn get_foo() -> impl Foo { Fooer {} } diff --git a/tests/rustdoc-json/fns/generics.rs b/tests/rustdoc-json/fns/generics.rs index 44dc6d854aa..43fc7279ded 100644 --- a/tests/rustdoc-json/fns/generics.rs +++ b/tests/rustdoc-json/fns/generics.rs @@ -1,22 +1,22 @@ // ignore-tidy-linelength -// @set wham_id = "$.index[*][?(@.name=='Wham')].id" +//@ set wham_id = "$.index[*][?(@.name=='Wham')].id" pub trait Wham {} -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"' -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" false -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -// @is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.decl.inputs" '[["w", {"generic": "T"}]]' +//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" [] +//@ count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1 +//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"' +//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" false +//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.decl.inputs" '[["w", {"generic": "T"}]]' pub fn one_generic_param_fn<T: Wham>(w: T) {} -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"' -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" true -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id -// @count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][0]" '"w"' -// @is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" [] +//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1 +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"' +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" true +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id +//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][0]" '"w"' +//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id pub fn one_synthetic_generic_param_fn(w: impl Wham) {} diff --git a/tests/rustdoc-json/fns/pattern_arg.rs b/tests/rustdoc-json/fns/pattern_arg.rs index 55f24797ac0..3fa423bcefd 100644 --- a/tests/rustdoc-json/fns/pattern_arg.rs +++ b/tests/rustdoc-json/fns/pattern_arg.rs @@ -1,7 +1,7 @@ -// @is "$.index[*][?(@.name=='fst')].inner.function.decl.inputs[0][0]" '"(x, _)"' +//@ is "$.index[*][?(@.name=='fst')].inner.function.decl.inputs[0][0]" '"(x, _)"' pub fn fst<X, Y>((x, _): (X, Y)) -> X { x } -// @is "$.index[*][?(@.name=='drop_int')].inner.function.decl.inputs[0][0]" '"_"' +//@ is "$.index[*][?(@.name=='drop_int')].inner.function.decl.inputs[0][0]" '"_"' pub fn drop_int(_: i32) {} diff --git a/tests/rustdoc-json/fns/qualifiers.rs b/tests/rustdoc-json/fns/qualifiers.rs index 6293b811226..beb1b4ccd10 100644 --- a/tests/rustdoc-json/fns/qualifiers.rs +++ b/tests/rustdoc-json/fns/qualifiers.rs @@ -1,33 +1,33 @@ //@ edition:2018 -// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.async" false -// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.const" false -// @is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.unsafe" false +//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.const" false +//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.unsafe" false pub fn nothing_fn() {} -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.async" false -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.const" false -// @is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.unsafe" true +//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.const" false +//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.unsafe" true pub unsafe fn unsafe_fn() {} -// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.async" false -// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.const" true -// @is "$.index[*][?(@.name=='const_fn')].inner.function.header.unsafe" false +//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.const" true +//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.unsafe" false pub const fn const_fn() {} -// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.async" true -// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.const" false -// @is "$.index[*][?(@.name=='async_fn')].inner.function.header.unsafe" false +//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.async" true +//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.const" false +//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.unsafe" false pub async fn async_fn() {} -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.async" true -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.const" false -// @is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.unsafe" true +//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.async" true +//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.const" false +//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.unsafe" true pub async unsafe fn async_unsafe_fn() {} -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.async" false -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.const" true -// @is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.unsafe" true +//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.async" false +//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.const" true +//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.unsafe" true pub const unsafe fn const_unsafe_fn() {} // It's impossible for a function to be both const and async, so no test for that diff --git a/tests/rustdoc-json/fns/return_type_alias.rs b/tests/rustdoc-json/fns/return_type_alias.rs index e8a7dce8b0a..67bc46a8740 100644 --- a/tests/rustdoc-json/fns/return_type_alias.rs +++ b/tests/rustdoc-json/fns/return_type_alias.rs @@ -1,9 +1,9 @@ // Regression test for <https://github.com/rust-lang/rust/issues/104851> -/// @set foo = "$.index[*][?(@.name=='Foo')].id" +///@ set foo = "$.index[*][?(@.name=='Foo')].id" pub type Foo = i32; -// @is "$.index[*][?(@.name=='demo')].inner.function.decl.output.resolved_path.id" $foo +//@ is "$.index[*][?(@.name=='demo')].inner.function.decl.output.resolved_path.id" $foo pub fn demo() -> Foo { 42 } diff --git a/tests/rustdoc-json/generic-associated-types/gats.rs b/tests/rustdoc-json/generic-associated-types/gats.rs index 56d6e7a49db..8a38230bb5d 100644 --- a/tests/rustdoc-json/generic-associated-types/gats.rs +++ b/tests/rustdoc-json/generic-associated-types/gats.rs @@ -3,32 +3,32 @@ pub trait Display {} pub trait LendingIterator { - // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*]" 1 - // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*].name" \"\'a\" - // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*]" 1 - // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.type.generic" \"Self\" - // @is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" - // @count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.bounds[*]" 1 + //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*]" 1 + //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.params[*].name" \"\'a\" + //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*]" 1 + //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.type.generic" \"Self\" + //@ is "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.generics.where_predicates[*].bound_predicate.bounds[*].outlives" \"\'a\" + //@ count "$.index[*][?(@.name=='LendingItem')].inner.assoc_type.bounds[*]" 1 type LendingItem<'a>: Display where Self: 'a; - // @count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 1 - // @count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 - // @is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" - // @is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.name" \"LendingItem\" + //@ count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 1 + //@ count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + //@ is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" + //@ is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.name" \"LendingItem\" fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>; } pub trait Iterator { - // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.params[*]" 0 - // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.where_predicates[*]" 0 - // @count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1 + //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.params[*]" 0 + //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.generics.where_predicates[*]" 0 + //@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1 type Item: Display; - // @count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 0 - // @count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 - // @is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" - // @is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.name" \"Item\" + //@ count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 0 + //@ count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0 + //@ is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\" + //@ is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.name" \"Item\" fn next<'a>(&'a self) -> Self::Item; } diff --git a/tests/rustdoc-json/generic_impl.rs b/tests/rustdoc-json/generic_impl.rs index 31f41d0f335..e7a5d2a78c1 100644 --- a/tests/rustdoc-json/generic_impl.rs +++ b/tests/rustdoc-json/generic_impl.rs @@ -1,8 +1,8 @@ // Regression test for <https://github.com/rust-lang/rust/issues/97986>. -// @has "$.index[*][?(@.name=='f')]" -// @has "$.index[*][?(@.name=='AssocTy')]" -// @has "$.index[*][?(@.name=='AssocConst')]" +//@ has "$.index[*][?(@.name=='f')]" +//@ has "$.index[*][?(@.name=='AssocTy')]" +//@ has "$.index[*][?(@.name=='AssocConst')]" pub mod m { pub struct S; diff --git a/tests/rustdoc-json/glob_import.rs b/tests/rustdoc-json/glob_import.rs index 7de1ed78f2f..a67a99a37cb 100644 --- a/tests/rustdoc-json/glob_import.rs +++ b/tests/rustdoc-json/glob_import.rs @@ -2,8 +2,8 @@ #![no_std] -// @has "$.index[*][?(@.name=='glob')]" -// @has "$.index[*][?(@.inner.import)].inner.import.name" \"*\" +//@ has "$.index[*][?(@.name=='glob')]" +//@ has "$.index[*][?(@.inner.import)].inner.import.name" \"*\" mod m1 { pub fn f() {} diff --git a/tests/rustdoc-json/impl-trait-precise-capturing.rs b/tests/rustdoc-json/impl-trait-precise-capturing.rs index bf98868d145..f9fee788ffe 100644 --- a/tests/rustdoc-json/impl-trait-precise-capturing.rs +++ b/tests/rustdoc-json/impl-trait-precise-capturing.rs @@ -1,6 +1,6 @@ #![feature(precise_capturing)] -// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\" -// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\" -// @is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\" +//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\" pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs index 96c3ab08b99..84a1e6ed7d5 100644 --- a/tests/rustdoc-json/impls/auto.rs +++ b/tests/rustdoc-json/impls/auto.rs @@ -15,8 +15,8 @@ impl Foo { } // Testing spans, so all tests below code -// @is "$.index[*][?(@.docs=='has span')].span.begin" "[13, 0]" -// @is "$.index[*][?(@.docs=='has span')].span.end" "[15, 1]" +//@ is "$.index[*][?(@.docs=='has span')].span.begin" "[13, 0]" +//@ is "$.index[*][?(@.docs=='has span')].span.end" "[15, 1]" // FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91 // is "$.index[*][?(@.inner.impl.synthetic==true)].span" null pub struct Foo; diff --git a/tests/rustdoc-json/impls/blanket_with_local.rs b/tests/rustdoc-json/impls/blanket_with_local.rs index 2fb4a84b9a6..de92dafae0b 100644 --- a/tests/rustdoc-json/impls/blanket_with_local.rs +++ b/tests/rustdoc-json/impls/blanket_with_local.rs @@ -1,11 +1,11 @@ // Test for the ICE in rust/83718 // A blanket impl plus a local type together shouldn't result in mismatched ID issues -// @has "$.index[*][?(@.name=='Load')]" +//@ has "$.index[*][?(@.name=='Load')]" pub trait Load { - // @has "$.index[*][?(@.name=='load')]" + //@ has "$.index[*][?(@.name=='load')]" fn load() {} - // @has "$.index[*][?(@.name=='write')]" + //@ has "$.index[*][?(@.name=='write')]" fn write(self) {} } @@ -14,5 +14,5 @@ impl<P> Load for P { fn write(self) {} } -// @has "$.index[*][?(@.name=='Wrapper')]" +//@ has "$.index[*][?(@.name=='Wrapper')]" pub struct Wrapper {} diff --git a/tests/rustdoc-json/impls/foreign_for_local.rs b/tests/rustdoc-json/impls/foreign_for_local.rs index d5265ba11bd..20690f26851 100644 --- a/tests/rustdoc-json/impls/foreign_for_local.rs +++ b/tests/rustdoc-json/impls/foreign_for_local.rs @@ -3,16 +3,16 @@ extern crate foreign_trait; /// ForeignTrait id hack pub use foreign_trait::ForeignTrait as _; -// @set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.import.id" +//@ set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.import.id" pub struct LocalStruct; -// @set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id" +//@ set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id" /// foreign for local impl foreign_trait::ForeignTrait for LocalStruct {} -// @set impl = "$.index[*][?(@.docs=='foreign for local')].id" -// @is "$.index[*][?(@.docs=='foreign for local')].inner.impl.for.resolved_path.id" $LocalStruct -// @is "$.index[*][?(@.docs=='foreign for local')].inner.impl.trait.id" $ForeignTrait +//@ set impl = "$.index[*][?(@.docs=='foreign for local')].id" +//@ is "$.index[*][?(@.docs=='foreign for local')].inner.impl.for.resolved_path.id" $LocalStruct +//@ is "$.index[*][?(@.docs=='foreign for local')].inner.impl.trait.id" $ForeignTrait -// @has "$.index[*][?(@.name=='LocalStruct')].inner.struct.impls[*]" $impl +//@ has "$.index[*][?(@.name=='LocalStruct')].inner.struct.impls[*]" $impl diff --git a/tests/rustdoc-json/impls/impl_item_visibility.rs b/tests/rustdoc-json/impls/impl_item_visibility.rs index d3c15cd23e4..293dd965804 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility.rs @@ -4,13 +4,13 @@ pub struct Foo; impl Foo { fn baz() {} } -// @!has '$.index[*][?(@.docs=="impl Foo priv")]' +//@ !has '$.index[*][?(@.docs=="impl Foo priv")]' /// impl Foo pub impl Foo { pub fn qux() {} } -// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -18,4 +18,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs index 431220a473d..77ee717b03a 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs @@ -7,13 +7,13 @@ impl Foo { fn baz() {} } // FIXME(#111564): Is this the right behaviour? -// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' /// impl Foo pub impl Foo { pub fn qux() {} } -// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -21,4 +21,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs index aa1eb989665..80c47eee6cb 100644 --- a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs @@ -6,13 +6,13 @@ pub struct Foo; impl Foo { fn baz() {} } -// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' /// impl Foo pub impl Foo { pub fn qux() {} } -// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' /// impl Foo hidden impl Foo { @@ -20,4 +20,4 @@ impl Foo { pub fn __quazl() {} } // FIXME(#111564): Is this the right behaviour? -// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' +//@ is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/import_from_private.rs b/tests/rustdoc-json/impls/import_from_private.rs index 3da03df2546..e386252e83b 100644 --- a/tests/rustdoc-json/impls/import_from_private.rs +++ b/tests/rustdoc-json/impls/import_from_private.rs @@ -1,20 +1,20 @@ // https://github.com/rust-lang/rust/issues/100252 mod bar { - // @set baz = "$.index[*][?(@.name == 'Baz')].id" + //@ set baz = "$.index[*][?(@.name == 'Baz')].id" pub struct Baz; - // @set impl = "$.index[*][?(@.docs == 'impl')].id" + //@ set impl = "$.index[*][?(@.docs == 'impl')].id" /// impl impl Baz { - // @set doit = "$.index[*][?(@.name == 'doit')].id" + //@ set doit = "$.index[*][?(@.name == 'doit')].id" pub fn doit() {} } } -// @set import = "$.index[*][?(@.inner.import)].id" +//@ set import = "$.index[*][?(@.inner.import)].id" pub use bar::Baz; -// @is "$.index[*].inner.module.items[*]" $import -// @is "$.index[*].inner.import.id" $baz -// @has "$.index[*][?(@.name == 'Baz')].inner.struct.impls[*]" $impl -// @is "$.index[*][?(@.docs=='impl')].inner.impl.items[*]" $doit +//@ is "$.index[*].inner.module.items[*]" $import +//@ is "$.index[*].inner.import.id" $baz +//@ has "$.index[*][?(@.name == 'Baz')].inner.struct.impls[*]" $impl +//@ is "$.index[*][?(@.docs=='impl')].inner.impl.items[*]" $doit diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs index 7857626d66e..4a313044920 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-2.rs @@ -1,8 +1,8 @@ -// @has "$.index[*][?(@.docs=='Here')]" -// @!has "$.index[*][?(@.docs=='Not Here')]" -// @!has "$.index[*][?(@.name == 'HiddenPubStruct')]" -// @has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" -// @has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[*][?(@.docs=='Here')]" +//@ !has "$.index[*][?(@.docs=='Not Here')]" +//@ !has "$.index[*][?(@.name == 'HiddenPubStruct')]" +//@ has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" +//@ has "$.index[*][?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs index c09c916a530..d3f2180f22c 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id-3.rs @@ -1,8 +1,8 @@ //@ compile-flags: --document-hidden-items -// @has "$.index[*][?(@.name == 'HiddenPubStruct')]" -// @has "$.index[*][?(@.inner.impl)]" -// @has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[*][?(@.name == 'HiddenPubStruct')]" +//@ has "$.index[*][?(@.inner.impl)]" +//@ has "$.index[*][?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] diff --git a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs index 97db9c93a0f..a3f05818842 100644 --- a/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs +++ b/tests/rustdoc-json/impls/issue-112852-dangling-trait-impl-id.rs @@ -1,21 +1,21 @@ -// @has "$.index[*][?(@.name=='PubTrait')]" +//@ has "$.index[*][?(@.name=='PubTrait')]" pub trait PubTrait {} #[doc(hidden)] pub mod hidden { - // @!has "$.index[*][?(@.name == 'HiddenPubStruct')]" + //@ !has "$.index[*][?(@.name == 'HiddenPubStruct')]" pub struct HiddenPubStruct; - // @!has "$.index[*][?(@.docs == 'Not Here')]" + //@ !has "$.index[*][?(@.docs == 'Not Here')]" /// Not Here impl crate::PubTrait for HiddenPubStruct {} } pub mod not_hidden { - // @has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" + //@ has "$.index[*][?(@.name == 'NotHiddenPubStruct')]" pub struct NotHiddenPubStruct; - // @has "$.index[*][?(@.docs == 'Here')]" + //@ has "$.index[*][?(@.docs == 'Here')]" /// Here impl crate::PubTrait for NotHiddenPubStruct {} } diff --git a/tests/rustdoc-json/impls/local_for_foreign.rs b/tests/rustdoc-json/impls/local_for_foreign.rs index 019f7d625cb..bd49269104f 100644 --- a/tests/rustdoc-json/impls/local_for_foreign.rs +++ b/tests/rustdoc-json/impls/local_for_foreign.rs @@ -3,16 +3,16 @@ extern crate foreign_struct; /// ForeignStruct id hack pub use foreign_struct::ForeignStruct as _; -// @set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.import.id" +//@ set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.import.id" pub trait LocalTrait {} -// @set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id" +//@ set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id" /// local for foreign impl LocalTrait for foreign_struct::ForeignStruct {} -// @set impl = "$.index[*][?(@.docs=='local for foreign')].id" -// @is "$.index[*][?(@.docs=='local for foreign')].inner.impl.trait.id" $LocalTrait -// @is "$.index[*][?(@.docs=='local for foreign')].inner.impl.for.resolved_path.id" $ForeignStruct +//@ set impl = "$.index[*][?(@.docs=='local for foreign')].id" +//@ is "$.index[*][?(@.docs=='local for foreign')].inner.impl.trait.id" $LocalTrait +//@ is "$.index[*][?(@.docs=='local for foreign')].inner.impl.for.resolved_path.id" $ForeignStruct -// @is "$.index[*][?(@.name=='LocalTrait')].inner.trait.implementations[*]" $impl +//@ is "$.index[*][?(@.name=='LocalTrait')].inner.trait.implementations[*]" $impl diff --git a/tests/rustdoc-json/impls/local_for_local.rs b/tests/rustdoc-json/impls/local_for_local.rs index 015e89c2281..1d141d6e4de 100644 --- a/tests/rustdoc-json/impls/local_for_local.rs +++ b/tests/rustdoc-json/impls/local_for_local.rs @@ -1,12 +1,12 @@ -// @set struct = "$.index[*][?(@.name=='Struct')].id" +//@ set struct = "$.index[*][?(@.name=='Struct')].id" pub struct Struct; -// @set trait = "$.index[*][?(@.name=='Trait')].id" +//@ set trait = "$.index[*][?(@.name=='Trait')].id" pub trait Trait {} -// @set impl = "$.index[*][?(@.docs=='impl')].id" +//@ set impl = "$.index[*][?(@.docs=='impl')].id" /// impl impl Trait for Struct {} -// @has "$.index[*][?(@.name=='Struct')].inner.struct.impls[*]" $impl -// @is "$.index[*][?(@.name=='Trait')].inner.trait.implementations[*]" $impl -// @is "$.index[*][?(@.docs=='impl')].inner.impl.trait.id" $trait -// @is "$.index[*][?(@.docs=='impl')].inner.impl.for.resolved_path.id" $struct +//@ has "$.index[*][?(@.name=='Struct')].inner.struct.impls[*]" $impl +//@ is "$.index[*][?(@.name=='Trait')].inner.trait.implementations[*]" $impl +//@ is "$.index[*][?(@.docs=='impl')].inner.impl.trait.id" $trait +//@ is "$.index[*][?(@.docs=='impl')].inner.impl.for.resolved_path.id" $struct diff --git a/tests/rustdoc-json/impls/local_for_local_primitive.rs b/tests/rustdoc-json/impls/local_for_local_primitive.rs index acc3a879fe1..8c1eb044eae 100644 --- a/tests/rustdoc-json/impls/local_for_local_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_local_primitive.rs @@ -1,18 +1,18 @@ #![feature(rustc_attrs)] -// @set Local = "$.index[*][?(@.name=='Local')].id" +//@ set Local = "$.index[*][?(@.name=='Local')].id" pub trait Local {} -// @is "$.index[*][?(@.docs=='Local for bool')].inner.impl.trait.id" $Local -// @is "$.index[*][?(@.docs=='Local for bool')].inner.impl.for.primitive" '"bool"' +//@ is "$.index[*][?(@.docs=='Local for bool')].inner.impl.trait.id" $Local +//@ is "$.index[*][?(@.docs=='Local for bool')].inner.impl.for.primitive" '"bool"' /// Local for bool impl Local for bool {} -// @set impl = "$.index[*][?(@.docs=='Local for bool')].id" -// @is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl +//@ set impl = "$.index[*][?(@.docs=='Local for bool')].id" +//@ is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl // FIXME(#101695): Test bool's `impls` include "Local for bool" -// @has "$.index[*][?(@.name=='bool')]" +//@ has "$.index[*][?(@.name=='bool')]" #[rustc_doc_primitive = "bool"] /// Boolean docs mod prim_bool {} diff --git a/tests/rustdoc-json/impls/local_for_primitive.rs b/tests/rustdoc-json/impls/local_for_primitive.rs index 85278c0e08c..56d930ca5c4 100644 --- a/tests/rustdoc-json/impls/local_for_primitive.rs +++ b/tests/rustdoc-json/impls/local_for_primitive.rs @@ -1,7 +1,7 @@ -// @set local = "$.index[*][?(@.name=='Local')]" +//@ set local = "$.index[*][?(@.name=='Local')]" pub trait Local {} -// @set impl = "$.index[*][?(@.docs=='local for bool')].id" -// @is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl +//@ set impl = "$.index[*][?(@.docs=='local for bool')].id" +//@ is "$.index[*][?(@.name=='Local')].inner.trait.implementations[*]" $impl /// local for bool impl Local for bool {} diff --git a/tests/rustdoc-json/intra-doc-links/foreign_variant.rs b/tests/rustdoc-json/intra-doc-links/foreign_variant.rs index 40e1f6b1f0a..251c4884fbb 100644 --- a/tests/rustdoc-json/intra-doc-links/foreign_variant.rs +++ b/tests/rustdoc-json/intra-doc-links/foreign_variant.rs @@ -8,6 +8,6 @@ pub struct Local; /// local impl impl enum_variant_in_trait_method::Trait for Local {} -// @!has "$.index[*][?(@.name == 'Trait')]" -// @!has "$.index[*][?(@.name == 'method')]" -// @count "$.index[*][?(@.docs == 'local impl')].inner.items[*]" 0 +//@ !has "$.index[*][?(@.name == 'Trait')]" +//@ !has "$.index[*][?(@.name == 'method')]" +//@ count "$.index[*][?(@.docs == 'local impl')].inner.items[*]" 0 diff --git a/tests/rustdoc-json/intra-doc-links/non_page.rs b/tests/rustdoc-json/intra-doc-links/non_page.rs index 73c5334bb5c..00987d93c1e 100644 --- a/tests/rustdoc-json/intra-doc-links/non_page.rs +++ b/tests/rustdoc-json/intra-doc-links/non_page.rs @@ -7,17 +7,17 @@ //! [`Trait::ASSOC_CONST`] //! [`Trait::method`] -// @set struct_field = "$.index[*][?(@.name=='struct_field')].id" -// @set Variant = "$.index[*][?(@.name=='Variant')].id" -// @set AssocType = "$.index[*][?(@.name=='AssocType')].id" -// @set ASSOC_CONST = "$.index[*][?(@.name=='ASSOC_CONST')].id" -// @set method = "$.index[*][?(@.name=='method')].id" +//@ set struct_field = "$.index[*][?(@.name=='struct_field')].id" +//@ set Variant = "$.index[*][?(@.name=='Variant')].id" +//@ set AssocType = "$.index[*][?(@.name=='AssocType')].id" +//@ set ASSOC_CONST = "$.index[*][?(@.name=='ASSOC_CONST')].id" +//@ set method = "$.index[*][?(@.name=='method')].id" -// @is "$.index[*][?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field -// @is "$.index[*][?(@.name=='non_page')].links['`Enum::Variant`']" $Variant -// @is "$.index[*][?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType -// @is "$.index[*][?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST -// @is "$.index[*][?(@.name=='non_page')].links['`Trait::method`']" $method +//@ is "$.index[*][?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field +//@ is "$.index[*][?(@.name=='non_page')].links['`Enum::Variant`']" $Variant +//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType +//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST +//@ is "$.index[*][?(@.name=='non_page')].links['`Trait::method`']" $method pub struct Struct { pub struct_field: i32, diff --git a/tests/rustdoc-json/intra-doc-links/user_written.rs b/tests/rustdoc-json/intra-doc-links/user_written.rs index 6871dfea44a..c3f9df95a8f 100644 --- a/tests/rustdoc-json/intra-doc-links/user_written.rs +++ b/tests/rustdoc-json/intra-doc-links/user_written.rs @@ -4,5 +4,5 @@ /// To test rustdoc json pub fn foo() {} -// @set foo = "$.index[*][?(@.name=='foo')].id" -// @is "$.index[*][?(@.name=='user_written')].links['foo#reasons']" $foo +//@ set foo = "$.index[*][?(@.name=='foo')].id" +//@ is "$.index[*][?(@.name=='user_written')].links['foo#reasons']" $foo diff --git a/tests/rustdoc-json/keyword.rs b/tests/rustdoc-json/keyword.rs index 3446b212c56..7a820cd1487 100644 --- a/tests/rustdoc-json/keyword.rs +++ b/tests/rustdoc-json/keyword.rs @@ -6,15 +6,15 @@ #![feature(rustdoc_internals)] #![no_std] -// @!has "$.index[*][?(@.name=='match')]" -// @has "$.index[*][?(@.name=='foo')]" +//@ !has "$.index[*][?(@.name=='match')]" +//@ has "$.index[*][?(@.name=='foo')]" #[doc(keyword = "match")] /// this is a test! pub mod foo {} -// @!has "$.index[*][?(@.name=='hello')]" -// @!has "$.index[*][?(@.name=='bar')]" +//@ !has "$.index[*][?(@.name=='hello')]" +//@ !has "$.index[*][?(@.name=='bar')]" #[doc(keyword = "hello")] /// hello mod bar {} diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index 1c2b7d02155..7a030041f7c 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -3,18 +3,18 @@ //@ compile-flags: --document-private-items #![feature(rustdoc_internals)] -// @!has "$.index[*][?(@.name=='match')]" -// @has "$.index[*][?(@.name=='foo')]" -// @is "$.index[*][?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' -// @is "$.index[*][?(@.name=='foo')].docs" '"this is a test!"' +//@ !has "$.index[*][?(@.name=='match')]" +//@ has "$.index[*][?(@.name=='foo')]" +//@ is "$.index[*][?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[*][?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! pub mod foo {} -// @!has "$.index[*][?(@.name=='hello')]" -// @has "$.index[*][?(@.name=='bar')]" -// @is "$.index[*][?(@.name=='bar')].attrs" '["#[doc(keyword = \"hello\")]"]' -// @is "$.index[*][?(@.name=='bar')].docs" '"hello"' +//@ !has "$.index[*][?(@.name=='hello')]" +//@ has "$.index[*][?(@.name=='bar')]" +//@ is "$.index[*][?(@.name=='bar')].attrs" '["#[doc(keyword = \"hello\")]"]' +//@ is "$.index[*][?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "hello")] /// hello mod bar {} diff --git a/tests/rustdoc-json/lifetime/longest.rs b/tests/rustdoc-json/lifetime/longest.rs index dccad41a861..39f791d2b09 100644 --- a/tests/rustdoc-json/lifetime/longest.rs +++ b/tests/rustdoc-json/lifetime/longest.rs @@ -1,26 +1,26 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -// @is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' -// @count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1 -// @is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" [] +//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].name" \"\'a\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.params[0].kind" '{"lifetime": {"outlives": []}}' +//@ count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1 +//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" [] -// @count "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[*]" 2 -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][0]" '"l"' -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][0]" '"r"' +//@ count "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[*]" 2 +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][0]" '"l"' +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][0]" '"r"' -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.type.primitive" \"str\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.type.primitive" \"str\" -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.type.primitive" \"str\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.mutable" false +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.type.primitive" \"str\" -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.mutable" false -// @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.type.primitive" \"str\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.mutable" false +//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.type.primitive" \"str\" pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str { if l.len() > r.len() { l } else { r } diff --git a/tests/rustdoc-json/lifetime/outlives.rs b/tests/rustdoc-json/lifetime/outlives.rs index 549e4c200dc..c98555d5737 100644 --- a/tests/rustdoc-json/lifetime/outlives.rs +++ b/tests/rustdoc-json/lifetime/outlives.rs @@ -1,18 +1,18 @@ // ignore-tidy-linelength -// @count "$.index[*][?(@.name=='foo')].inner.function.generics.params[*]" 3 -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates" [] -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].name" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].name" '"T"' -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.lifetime.outlives" [] -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].kind.lifetime.outlives" [\"\'a\"] -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.default" null -// @count "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[*]" 1 -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false -// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.lifetime" \"\'b\" -// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.mutable" false -// @is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.type.generic" \"T\" +//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.params[*]" 3 +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates" [] +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].name" \"\'a\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].name" \"\'b\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].name" '"T"' +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[0].kind.lifetime.outlives" [] +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[1].kind.lifetime.outlives" [\"\'a\"] +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.default" null +//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.params[2].kind.type.bounds[0].outlives" \"\'b\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false +//@ is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.lifetime" \"\'b\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.mutable" false +//@ is "$.index[*][?(@.name=='foo')].inner.function.decl.inputs[0][1].borrowed_ref.type.borrowed_ref.type.generic" \"T\" pub fn foo<'a, 'b: 'a, T: 'b>(_: &'a &'b T) {} diff --git a/tests/rustdoc-json/lifetime/outlives_in_param.rs b/tests/rustdoc-json/lifetime/outlives_in_param.rs index f6db93c9183..3eee6d9ea46 100644 --- a/tests/rustdoc-json/lifetime/outlives_in_param.rs +++ b/tests/rustdoc-json/lifetime/outlives_in_param.rs @@ -1,8 +1,8 @@ // ignore-tidy-linelength -// @count '$.index[*][?(@.name=="outlives")].inner.function.generics.params[*]' 2 -// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\" -// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' [] -// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"' -// @is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]' +//@ count '$.index[*][?(@.name=="outlives")].inner.function.generics.params[*]' 2 +//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].name' \"\'a\" +//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[0].kind.lifetime.outlives' [] +//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].name' '"T"' +//@ is '$.index[*][?(@.name=="outlives")].inner.function.generics.params[1].kind.type.bounds' '[{"outlives": "'\''a"}]' pub fn outlives<'a, T: 'a>() {} diff --git a/tests/rustdoc-json/lifetime/outlives_in_where.rs b/tests/rustdoc-json/lifetime/outlives_in_where.rs index ca3e1a150ce..a8f88be01da 100644 --- a/tests/rustdoc-json/lifetime/outlives_in_where.rs +++ b/tests/rustdoc-json/lifetime/outlives_in_where.rs @@ -1,22 +1,22 @@ // ignore-tidy-linelength -// @is '$.index[*][?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]' +//@ is '$.index[*][?(@.name=="on_lifetimes")].inner.function.generics.where_predicates' '[{"lifetime_predicate": {"lifetime": "'\''all", "outlives": ["'\''a", "'\''b", "'\''c"]}}]' pub fn on_lifetimes<'a, 'b, 'c, 'all>() where 'all: 'a + 'b + 'c, { } -// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[*]' 2 -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\" -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' [] -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"' -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] -// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1 -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"' -// @count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1 -// @is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\" +//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[*]' 2 +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].name' \"\'a\" +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[0].kind.lifetime.outlives' [] +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].name' '"T"' +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.params[1].kind.type.bounds' [] +//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[*]' 1 +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.type.generic' '"T"' +//@ count '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[*]' 1 +//@ is '$.index[*][?(@.name=="on_trait")].inner.function.generics.where_predicates[0].bound_predicate.bounds[0].outlives' \"\'a\" pub fn on_trait<'a, T>() where T: 'a, diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs index 917e9e0790c..6d33dfca373 100644 --- a/tests/rustdoc-json/methods/abi.rs +++ b/tests/rustdoc-json/methods/abi.rs @@ -2,51 +2,51 @@ #![feature(abi_vectorcall)] -// @has "$.index[*][?(@.name=='Foo')]" +//@ has "$.index[*][?(@.name=='Foo')]" pub struct Foo; impl Foo { - // @is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" + //@ is "$.index[*][?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} - // @is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' + //@ is "$.index[*][?(@.name=='abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' pub extern "C" fn abi_c() {} - // @is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' + //@ is "$.index[*][?(@.name=='abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' pub extern "system" fn abi_system() {} - // @is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' + //@ is "$.index[*][?(@.name=='abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' pub extern "C-unwind" fn abi_c_unwind() {} - // @is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' + //@ is "$.index[*][?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} - // @is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + //@ is "$.index[*][?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' pub extern "vectorcall" fn abi_vectorcall() {} - // @is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + //@ is "$.index[*][?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} } pub trait Bar { - // @is "$.index[*][?(@.name=='trait_abi_rust')].inner.function.header.abi" \"Rust\" + //@ is "$.index[*][?(@.name=='trait_abi_rust')].inner.function.header.abi" \"Rust\" fn trait_abi_rust() {} - // @is "$.index[*][?(@.name=='trait_abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' + //@ is "$.index[*][?(@.name=='trait_abi_c')].inner.function.header.abi" '{"C": {"unwind": false}}' extern "C" fn trait_abi_c() {} - // @is "$.index[*][?(@.name=='trait_abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' + //@ is "$.index[*][?(@.name=='trait_abi_system')].inner.function.header.abi" '{"System": {"unwind": false}}' extern "system" fn trait_abi_system() {} - // @is "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' + //@ is "$.index[*][?(@.name=='trait_abi_c_unwind')].inner.function.header.abi" '{"C": {"unwind": true}}' extern "C-unwind" fn trait_abi_c_unwind() {} - // @is "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' + //@ is "$.index[*][?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' extern "system-unwind" fn trait_abi_system_unwind() {} - // @is "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + //@ is "$.index[*][?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' extern "vectorcall" fn trait_abi_vectorcall() {} - // @is "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + //@ is "$.index[*][?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} } diff --git a/tests/rustdoc-json/methods/qualifiers.rs b/tests/rustdoc-json/methods/qualifiers.rs index dac90b7ff6f..8de8cfd4c15 100644 --- a/tests/rustdoc-json/methods/qualifiers.rs +++ b/tests/rustdoc-json/methods/qualifiers.rs @@ -3,34 +3,34 @@ pub struct Foo; impl Foo { - // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.async" false - // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.const" true - // @is "$.index[*][?(@.name=='const_meth')].inner.function.header.unsafe" false + //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.async" false + //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.const" true + //@ is "$.index[*][?(@.name=='const_meth')].inner.function.header.unsafe" false pub const fn const_meth() {} - // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.async" false - // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.const" false - // @is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.unsafe" false + //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.async" false + //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.const" false + //@ is "$.index[*][?(@.name=='nothing_meth')].inner.function.header.unsafe" false pub fn nothing_meth() {} - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.async" false - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.const" false - // @is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.unsafe" true + //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.async" false + //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.const" false + //@ is "$.index[*][?(@.name=='unsafe_meth')].inner.function.header.unsafe" true pub unsafe fn unsafe_meth() {} - // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.async" true - // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.const" false - // @is "$.index[*][?(@.name=='async_meth')].inner.function.header.unsafe" false + //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.async" true + //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.const" false + //@ is "$.index[*][?(@.name=='async_meth')].inner.function.header.unsafe" false pub async fn async_meth() {} - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.async" true - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.const" false - // @is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.unsafe" true + //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.async" true + //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.const" false + //@ is "$.index[*][?(@.name=='async_unsafe_meth')].inner.function.header.unsafe" true pub async unsafe fn async_unsafe_meth() {} - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.async" false - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.const" true - // @is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.unsafe" true + //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.async" false + //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.const" true + //@ is "$.index[*][?(@.name=='const_unsafe_meth')].inner.function.header.unsafe" true pub const unsafe fn const_unsafe_meth() {} // It's impossible for a method to be both const and async, so no test for that diff --git a/tests/rustdoc-json/nested.rs b/tests/rustdoc-json/nested.rs index c0a47c467e3..ae2d9fe0ac5 100644 --- a/tests/rustdoc-json/nested.rs +++ b/tests/rustdoc-json/nested.rs @@ -1,32 +1,32 @@ //@ edition:2018 //@ compile-flags: --crate-version 1.0.0 -// @is "$.crate_version" \"1.0.0\" -// @has "$.index[*][?(@.name=='nested')].inner.module" -// @is "$.index[*][?(@.name=='nested')].inner.module.is_crate" true +//@ is "$.crate_version" \"1.0.0\" +//@ has "$.index[*][?(@.name=='nested')].inner.module" +//@ is "$.index[*][?(@.name=='nested')].inner.module.is_crate" true -// @set l1_id = "$.index[*][?(@.name=='l1')].id" -// @ismany "$.index[*][?(@.name=='nested')].inner.module.items[*]" $l1_id +//@ set l1_id = "$.index[*][?(@.name=='l1')].id" +//@ ismany "$.index[*][?(@.name=='nested')].inner.module.items[*]" $l1_id -// @has "$.index[*][?(@.name=='l1')].inner.module" -// @is "$.index[*][?(@.name=='l1')].inner.module.is_crate" false +//@ has "$.index[*][?(@.name=='l1')].inner.module" +//@ is "$.index[*][?(@.name=='l1')].inner.module.is_crate" false pub mod l1 { - // @has "$.index[*][?(@.name=='l3')].inner.module" - // @is "$.index[*][?(@.name=='l3')].inner.module.is_crate" false - // @set l3_id = "$.index[*][?(@.name=='l3')].id" + //@ has "$.index[*][?(@.name=='l3')].inner.module" + //@ is "$.index[*][?(@.name=='l3')].inner.module.is_crate" false + //@ set l3_id = "$.index[*][?(@.name=='l3')].id" pub mod l3 { - // @has "$.index[*][?(@.name=='L4')].inner.struct" - // @is "$.index[*][?(@.name=='L4')].inner.struct.kind" '"unit"' - // @set l4_id = "$.index[*][?(@.name=='L4')].id" - // @ismany "$.index[*][?(@.name=='l3')].inner.module.items[*]" $l4_id + //@ has "$.index[*][?(@.name=='L4')].inner.struct" + //@ is "$.index[*][?(@.name=='L4')].inner.struct.kind" '"unit"' + //@ set l4_id = "$.index[*][?(@.name=='L4')].id" + //@ ismany "$.index[*][?(@.name=='l3')].inner.module.items[*]" $l4_id pub struct L4; } - // @is "$.index[*][?(@.inner.import)].inner.import.glob" false - // @is "$.index[*][?(@.inner.import)].inner.import.source" '"l3::L4"' - // @is "$.index[*][?(@.inner.import)].inner.import.glob" false - // @is "$.index[*][?(@.inner.import)].inner.import.id" $l4_id - // @set l4_use_id = "$.index[*][?(@.inner.import)].id" + //@ is "$.index[*][?(@.inner.import)].inner.import.glob" false + //@ is "$.index[*][?(@.inner.import)].inner.import.source" '"l3::L4"' + //@ is "$.index[*][?(@.inner.import)].inner.import.glob" false + //@ is "$.index[*][?(@.inner.import)].inner.import.id" $l4_id + //@ set l4_use_id = "$.index[*][?(@.inner.import)].id" pub use l3::L4; } -// @ismany "$.index[*][?(@.name=='l1')].inner.module.items[*]" $l3_id $l4_use_id +//@ ismany "$.index[*][?(@.name=='l1')].inner.module.items[*]" $l3_id $l4_use_id diff --git a/tests/rustdoc-json/non_lifetime_binders.rs b/tests/rustdoc-json/non_lifetime_binders.rs index 6f0732646ca..06f6e10aa85 100644 --- a/tests/rustdoc-json/non_lifetime_binders.rs +++ b/tests/rustdoc-json/non_lifetime_binders.rs @@ -7,11 +7,11 @@ pub trait Trait {} pub struct Wrapper<T_>(std::marker::PhantomData<T_>); -// @count "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" -// @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' +//@ count "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[*]" 2 +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].name" \"\'a\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" +//@ is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' pub fn foo() where for<'a, T> &'a Wrapper<T>: Trait, diff --git a/tests/rustdoc-json/output_generics.rs b/tests/rustdoc-json/output_generics.rs index e9df64b79e3..3454f421636 100644 --- a/tests/rustdoc-json/output_generics.rs +++ b/tests/rustdoc-json/output_generics.rs @@ -2,11 +2,11 @@ // This is a regression test for #98009. -// @has "$.index[*][?(@.name=='this_compiles')]" -// @has "$.index[*][?(@.name=='this_does_not')]" -// @has "$.index[*][?(@.name=='Events')]" -// @has "$.index[*][?(@.name=='Other')]" -// @has "$.index[*][?(@.name=='Trait')]" +//@ has "$.index[*][?(@.name=='this_compiles')]" +//@ has "$.index[*][?(@.name=='this_does_not')]" +//@ has "$.index[*][?(@.name=='Events')]" +//@ has "$.index[*][?(@.name=='Other')]" +//@ has "$.index[*][?(@.name=='Trait')]" struct Events<R>(R); diff --git a/tests/rustdoc-json/primitives/local_primitive.rs b/tests/rustdoc-json/primitives/local_primitive.rs index 562c7e4d79b..b10ae45f3ec 100644 --- a/tests/rustdoc-json/primitives/local_primitive.rs +++ b/tests/rustdoc-json/primitives/local_primitive.rs @@ -11,11 +11,11 @@ #[rustc_doc_primitive = "i32"] mod prim_i32 {} -// @set local_i32 = "$.index[*][?(@.name=='i32')].id" +//@ set local_i32 = "$.index[*][?(@.name=='i32')].id" -// @has "$.index[*][?(@.name=='local_primitive')]" -// @ismany "$.index[*][?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 -// @is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32 +//@ has "$.index[*][?(@.name=='local_primitive')]" +//@ ismany "$.index[*][?(@.name=='local_primitive')].inner.module.items[*]" $local_i32 +//@ is "$.index[*][?(@.name=='local_primitive')].links['prim@i32']" $local_i32 // Let's ensure the `prim_i32` module isn't present in the output JSON: -// @!has "$.index[*][?(@.name=='prim_i32')]" +//@ !has "$.index[*][?(@.name=='prim_i32')]" diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs index 4b7b7646b89..77d1d68f8e4 100644 --- a/tests/rustdoc-json/primitives/primitive_impls.rs +++ b/tests/rustdoc-json/primitives/primitive_impls.rs @@ -4,23 +4,23 @@ #![no_core] #![rustc_coherence_is_core] -// @set impl_i32 = "$.index[*][?(@.docs=='Only core can do this')].id" +//@ set impl_i32 = "$.index[*][?(@.docs=='Only core can do this')].id" /// Only core can do this impl i32 { - // @set identity = "$.index[*][?(@.docs=='Do Nothing')].id" + //@ set identity = "$.index[*][?(@.docs=='Do Nothing')].id" /// Do Nothing pub fn identity(self) -> Self { self } - // @is "$.index[*][?(@.docs=='Only core can do this')].inner.impl.items[*]" $identity + //@ is "$.index[*][?(@.docs=='Only core can do this')].inner.impl.items[*]" $identity } -// @set Trait = "$.index[*][?(@.name=='Trait')].id" +//@ set Trait = "$.index[*][?(@.name=='Trait')].id" pub trait Trait {} -// @set impl_trait_for_i32 = "$.index[*][?(@.docs=='impl Trait for i32')].id" +//@ set impl_trait_for_i32 = "$.index[*][?(@.docs=='impl Trait for i32')].id" /// impl Trait for i32 impl Trait for i32 {} @@ -28,7 +28,7 @@ impl Trait for i32 {} #[rustc_doc_primitive = "i32"] mod prim_i32 {} -// @set i32 = "$.index[*][?(@.docs=='i32')].id" -// @is "$.index[*][?(@.docs=='i32')].name" '"i32"' -// @is "$.index[*][?(@.docs=='i32')].inner.primitive.name" '"i32"' -// @ismany "$.index[*][?(@.docs=='i32')].inner.primitive.impls[*]" $impl_i32 $impl_trait_for_i32 +//@ set i32 = "$.index[*][?(@.docs=='i32')].id" +//@ is "$.index[*][?(@.docs=='i32')].name" '"i32"' +//@ is "$.index[*][?(@.docs=='i32')].inner.primitive.name" '"i32"' +//@ ismany "$.index[*][?(@.docs=='i32')].inner.primitive.impls[*]" $impl_i32 $impl_trait_for_i32 diff --git a/tests/rustdoc-json/primitives/primitive_overloading.rs b/tests/rustdoc-json/primitives/primitive_overloading.rs index e4ffbdf0295..5e5f3974ab3 100644 --- a/tests/rustdoc-json/primitives/primitive_overloading.rs +++ b/tests/rustdoc-json/primitives/primitive_overloading.rs @@ -4,8 +4,8 @@ #![feature(rustc_attrs)] -// @has "$.index[*][?(@.name=='usize')]" -// @has "$.index[*][?(@.name=='prim')]" +//@ has "$.index[*][?(@.name=='usize')]" +//@ has "$.index[*][?(@.name=='prim')]" #[rustc_doc_primitive = "usize"] /// This is the built-in type `usize`. diff --git a/tests/rustdoc-json/primitives/primitive_type.rs b/tests/rustdoc-json/primitives/primitive_type.rs index 89c5d06c0b2..21ef5ab7196 100644 --- a/tests/rustdoc-json/primitives/primitive_type.rs +++ b/tests/rustdoc-json/primitives/primitive_type.rs @@ -1,17 +1,17 @@ #![feature(never_type)] -// @is "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" -// @is "$.index[*][?(@.name=='PrimNever')].inner.type_alias.type.primitive" \"never\" +//@ is "$.index[*][?(@.name=='PrimNever')].visibility" \"public\" +//@ is "$.index[*][?(@.name=='PrimNever')].inner.type_alias.type.primitive" \"never\" pub type PrimNever = !; -// @is "$.index[*][?(@.name=='PrimStr')].inner.type_alias.type.primitive" \"str\" +//@ is "$.index[*][?(@.name=='PrimStr')].inner.type_alias.type.primitive" \"str\" pub type PrimStr = str; -// @is "$.index[*][?(@.name=='PrimBool')].inner.type_alias.type.primitive" \"bool\" +//@ is "$.index[*][?(@.name=='PrimBool')].inner.type_alias.type.primitive" \"bool\" pub type PrimBool = bool; -// @is "$.index[*][?(@.name=='PrimChar')].inner.type_alias.type.primitive" \"char\" +//@ is "$.index[*][?(@.name=='PrimChar')].inner.type_alias.type.primitive" \"char\" pub type PrimChar = char; -// @is "$.index[*][?(@.name=='PrimU8')].inner.type_alias.type.primitive" \"u8\" +//@ is "$.index[*][?(@.name=='PrimU8')].inner.type_alias.type.primitive" \"u8\" pub type PrimU8 = u8; diff --git a/tests/rustdoc-json/primitives/use_primitive.rs b/tests/rustdoc-json/primitives/use_primitive.rs index 7f5ffc04309..e97db42705f 100644 --- a/tests/rustdoc-json/primitives/use_primitive.rs +++ b/tests/rustdoc-json/primitives/use_primitive.rs @@ -5,16 +5,16 @@ #[rustc_doc_primitive = "usize"] mod usize {} -// @set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id" +//@ set local_crate_id = "$.index[*][?(@.name=='use_primitive')].crate_id" -// @has "$.index[*][?(@.name=='ilog10')]" -// @!is "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id -// @has "$.index[*][?(@.name=='checked_add')]" -// @!is "$.index[*][?(@.name=='checked_add')]" $local_crate_id -// @!has "$.index[*][?(@.name=='is_ascii_uppercase')]" +//@ has "$.index[*][?(@.name=='ilog10')]" +//@ !is "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id +//@ has "$.index[*][?(@.name=='checked_add')]" +//@ !is "$.index[*][?(@.name=='checked_add')]" $local_crate_id +//@ !has "$.index[*][?(@.name=='is_ascii_uppercase')]" -// @is "$.index[*].inner.import[?(@.name=='my_i32')].id" null +//@ is "$.index[*].inner.import[?(@.name=='my_i32')].id" null pub use i32 as my_i32; -// @is "$.index[*].inner.import[?(@.name=='u32')].id" null +//@ is "$.index[*].inner.import[?(@.name=='u32')].id" null pub use u32; diff --git a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs index 7326649d904..512c741798b 100644 --- a/tests/rustdoc-json/reexport/doc_inline_external_crate.rs +++ b/tests/rustdoc-json/reexport/doc_inline_external_crate.rs @@ -5,7 +5,7 @@ #[doc(inline)] pub extern crate enum_with_discriminant; -// @!has '$.index[*][?(@.docs == "Should not be inlined")]' -// @has '$.index[*][?(@.name == "enum_with_discriminant")].inner.extern_crate' -// @set enum_with_discriminant = '$.index[*][?(@.name == "enum_with_discriminant")].id' -// @is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.module.items[*]' $enum_with_discriminant +//@ !has '$.index[*][?(@.docs == "Should not be inlined")]' +//@ has '$.index[*][?(@.name == "enum_with_discriminant")].inner.extern_crate' +//@ set enum_with_discriminant = '$.index[*][?(@.name == "enum_with_discriminant")].id' +//@ is '$.index[*][?(@.name == "doc_inline_external_crate")].inner.module.items[*]' $enum_with_discriminant diff --git a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs index a8f5500d629..6e9b5044816 100644 --- a/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs +++ b/tests/rustdoc-json/reexport/export_extern_crate_as_self.rs @@ -4,5 +4,5 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.inner.module)].name" \"export_extern_crate_as_self\" +//@ is "$.index[*][?(@.inner.module)].name" \"export_extern_crate_as_self\" pub extern crate self as export_extern_crate_as_self; // Must be the same name as the crate already has diff --git a/tests/rustdoc-json/reexport/extern_crate_glob.rs b/tests/rustdoc-json/reexport/extern_crate_glob.rs index 07497f6d7be..a0b4cb8ab2c 100644 --- a/tests/rustdoc-json/reexport/extern_crate_glob.rs +++ b/tests/rustdoc-json/reexport/extern_crate_glob.rs @@ -5,7 +5,7 @@ extern crate enum_with_discriminant; #[doc(inline)] pub use enum_with_discriminant::*; -// @!has '$.index[*][?(@.docs == "Should not be inlined")]' -// @is '$.index[*][?(@.inner.import)].inner.import.name' \"enum_with_discriminant\" -// @set use = '$.index[*][?(@.inner.import)].id' -// @is '$.index[*][?(@.name == "extern_crate_glob")].inner.module.items[*]' $use +//@ !has '$.index[*][?(@.docs == "Should not be inlined")]' +//@ is '$.index[*][?(@.inner.import)].inner.import.name' \"enum_with_discriminant\" +//@ set use = '$.index[*][?(@.inner.import)].id' +//@ is '$.index[*][?(@.name == "extern_crate_glob")].inner.module.items[*]' $use diff --git a/tests/rustdoc-json/reexport/glob_collision.rs b/tests/rustdoc-json/reexport/glob_collision.rs index 9a75f4c0cf3..3a034afab65 100644 --- a/tests/rustdoc-json/reexport/glob_collision.rs +++ b/tests/rustdoc-json/reexport/glob_collision.rs @@ -1,27 +1,27 @@ // Regression test for https://github.com/rust-lang/rust/issues/100973 -// @set m1 = "$.index[*][?(@.name == 'm1' && @.inner.module)].id" -// @is "$.index[*][?(@.name == 'm1')].inner.module.items" [] -// @is "$.index[*][?(@.name == 'm1')].inner.module.is_stripped" true +//@ set m1 = "$.index[*][?(@.name == 'm1' && @.inner.module)].id" +//@ is "$.index[*][?(@.name == 'm1')].inner.module.items" [] +//@ is "$.index[*][?(@.name == 'm1')].inner.module.is_stripped" true mod m1 { pub fn f() {} } -// @set m2 = "$.index[*][?(@.name == 'm2' && @.inner.module)].id" -// @is "$.index[*][?(@.name == 'm2')].inner.module.items" [] -// @is "$.index[*][?(@.name == 'm2')].inner.module.is_stripped" true +//@ set m2 = "$.index[*][?(@.name == 'm2' && @.inner.module)].id" +//@ is "$.index[*][?(@.name == 'm2')].inner.module.items" [] +//@ is "$.index[*][?(@.name == 'm2')].inner.module.is_stripped" true mod m2 { pub fn f(_: u8) {} } -// @set m1_use = "$.index[*][?(@.docs=='m1 re-export')].id" -// @is "$.index[*].inner.import[?(@.name=='m1')].id" $m1 -// @is "$.index[*].inner.import[?(@.name=='m1')].glob" true +//@ set m1_use = "$.index[*][?(@.docs=='m1 re-export')].id" +//@ is "$.index[*].inner.import[?(@.name=='m1')].id" $m1 +//@ is "$.index[*].inner.import[?(@.name=='m1')].glob" true /// m1 re-export pub use m1::*; -// @set m2_use = "$.index[*][?(@.docs=='m2 re-export')].id" -// @is "$.index[*].inner.import[?(@.name=='m2')].id" $m2 -// @is "$.index[*].inner.import[?(@.name=='m2')].glob" true +//@ set m2_use = "$.index[*][?(@.docs=='m2 re-export')].id" +//@ is "$.index[*].inner.import[?(@.name=='m2')].id" $m2 +//@ is "$.index[*].inner.import[?(@.name=='m2')].glob" true /// m2 re-export pub use m2::*; -// @ismany "$.index[*].inner.module[?(@.is_crate==true)].items[*]" $m1_use $m2_use +//@ ismany "$.index[*].inner.module[?(@.is_crate==true)].items[*]" $m1_use $m2_use diff --git a/tests/rustdoc-json/reexport/glob_empty_mod.rs b/tests/rustdoc-json/reexport/glob_empty_mod.rs index 8b7150c8fd7..326df5fdb61 100644 --- a/tests/rustdoc-json/reexport/glob_empty_mod.rs +++ b/tests/rustdoc-json/reexport/glob_empty_mod.rs @@ -1,8 +1,8 @@ // Regression test for https://github.com/rust-lang/rust/issues/100973 -// @is "$.index[*][?(@.name=='m1' && @.inner.module)].inner.module.is_stripped" true -// @set m1 = "$.index[*][?(@.name=='m1')].id" +//@ is "$.index[*][?(@.name=='m1' && @.inner.module)].inner.module.is_stripped" true +//@ set m1 = "$.index[*][?(@.name=='m1')].id" mod m1 {} -// @is "$.index[*][?(@.inner.import)].inner.import.id" $m1 +//@ is "$.index[*][?(@.inner.import)].inner.import.id" $m1 pub use m1::*; diff --git a/tests/rustdoc-json/reexport/glob_extern.rs b/tests/rustdoc-json/reexport/glob_extern.rs index b95765410d5..ff5d986d377 100644 --- a/tests/rustdoc-json/reexport/glob_extern.rs +++ b/tests/rustdoc-json/reexport/glob_extern.rs @@ -1,19 +1,19 @@ //@ edition:2018 -// @is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" +//@ is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { extern "C" { - // @set public_fn_id = "$.index[*][?(@.name=='public_fn')].id" + //@ set public_fn_id = "$.index[*][?(@.name=='public_fn')].id" pub fn public_fn(); - // @!has "$.index[*][?(@.name=='private_fn')]" + //@ !has "$.index[*][?(@.name=='private_fn')]" fn private_fn(); } - // @ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $public_fn_id - // @set mod1_id = "$.index[*][?(@.name=='mod1')].id" + //@ ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $public_fn_id + //@ set mod1_id = "$.index[*][?(@.name=='mod1')].id" } -// @is "$.index[*][?(@.inner.import)].inner.import.glob" true -// @is "$.index[*][?(@.inner.import)].inner.import.id" $mod1_id -// @set use_id = "$.index[*][?(@.inner.import)].id" -// @ismany "$.index[*][?(@.name=='glob_extern')].inner.module.items[*]" $use_id +//@ is "$.index[*][?(@.inner.import)].inner.import.glob" true +//@ is "$.index[*][?(@.inner.import)].inner.import.id" $mod1_id +//@ set use_id = "$.index[*][?(@.inner.import)].id" +//@ ismany "$.index[*][?(@.name=='glob_extern')].inner.module.items[*]" $use_id pub use mod1::*; diff --git a/tests/rustdoc-json/reexport/glob_private.rs b/tests/rustdoc-json/reexport/glob_private.rs index 9764b404682..0a889107592 100644 --- a/tests/rustdoc-json/reexport/glob_private.rs +++ b/tests/rustdoc-json/reexport/glob_private.rs @@ -1,32 +1,32 @@ //@ edition:2018 -// @is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" +//@ is "$.index[*][?(@.name=='mod1')].inner.module.is_stripped" "true" mod mod1 { - // @is "$.index[*][?(@.name=='mod2')].inner.module.is_stripped" "true" + //@ is "$.index[*][?(@.name=='mod2')].inner.module.is_stripped" "true" mod mod2 { - // @set m2pub_id = "$.index[*][?(@.name=='Mod2Public')].id" + //@ set m2pub_id = "$.index[*][?(@.name=='Mod2Public')].id" pub struct Mod2Public; - // @!has "$.index[*][?(@.name=='Mod2Private')]" + //@ !has "$.index[*][?(@.name=='Mod2Private')]" struct Mod2Private; } - // @set mod2_use_id = "$.index[*][?(@.docs=='Mod2 re-export')].id" - // @is "$.index[*][?(@.docs=='Mod2 re-export')].inner.import.name" \"mod2\" + //@ set mod2_use_id = "$.index[*][?(@.docs=='Mod2 re-export')].id" + //@ is "$.index[*][?(@.docs=='Mod2 re-export')].inner.import.name" \"mod2\" /// Mod2 re-export pub use self::mod2::*; - // @set m1pub_id = "$.index[*][?(@.name=='Mod1Public')].id" + //@ set m1pub_id = "$.index[*][?(@.name=='Mod1Public')].id" pub struct Mod1Public; - // @!has "$.index[*][?(@.name=='Mod1Private')]" + //@ !has "$.index[*][?(@.name=='Mod1Private')]" struct Mod1Private; } -// @set mod1_use_id = "$.index[*][?(@.docs=='Mod1 re-export')].id" -// @is "$.index[*][?(@.docs=='Mod1 re-export')].inner.import.name" \"mod1\" +//@ set mod1_use_id = "$.index[*][?(@.docs=='Mod1 re-export')].id" +//@ is "$.index[*][?(@.docs=='Mod1 re-export')].inner.import.name" \"mod1\" /// Mod1 re-export pub use mod1::*; -// @ismany "$.index[*][?(@.name=='mod2')].inner.module.items[*]" $m2pub_id -// @ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $m1pub_id $mod2_use_id -// @ismany "$.index[*][?(@.name=='glob_private')].inner.module.items[*]" $mod1_use_id +//@ ismany "$.index[*][?(@.name=='mod2')].inner.module.items[*]" $m2pub_id +//@ ismany "$.index[*][?(@.name=='mod1')].inner.module.items[*]" $m1pub_id $mod2_use_id +//@ ismany "$.index[*][?(@.name=='glob_private')].inner.module.items[*]" $mod1_use_id diff --git a/tests/rustdoc-json/reexport/in_root_and_mod.rs b/tests/rustdoc-json/reexport/in_root_and_mod.rs index a4133e2f0c7..f94e416c00f 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod.rs @@ -1,13 +1,13 @@ -// @!has "$.index[*][?(@.name=='foo')]" +//@ !has "$.index[*][?(@.name=='foo')]" mod foo { - // @has "$.index[*][?(@.name=='Foo')]" + //@ has "$.index[*][?(@.name=='Foo')]" pub struct Foo; } -// @has "$.index[*].inner[?(@.import.source=='foo::Foo')]" +//@ has "$.index[*].inner[?(@.import.source=='foo::Foo')]" pub use foo::Foo; pub mod bar { - // @has "$.index[*].inner[?(@.import.source=='crate::foo::Foo')]" + //@ has "$.index[*].inner[?(@.import.source=='crate::foo::Foo')]" pub use crate::foo::Foo; } diff --git a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs index 37f7b26fc85..13dee323542 100644 --- a/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs +++ b/tests/rustdoc-json/reexport/in_root_and_mod_pub.rs @@ -1,19 +1,19 @@ pub mod foo { - // @set bar_id = "$.index[*][?(@.name=='Bar')].id" - // @ismany "$.index[*][?(@.name=='foo')].inner.module.items[*]" $bar_id + //@ set bar_id = "$.index[*][?(@.name=='Bar')].id" + //@ ismany "$.index[*][?(@.name=='foo')].inner.module.items[*]" $bar_id pub struct Bar; } -// @set root_import_id = "$.index[*][?(@.docs=='Outer re-export')].id" -// @is "$.index[*].inner[?(@.import.source=='foo::Bar')].import.id" $bar_id -// @has "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id +//@ set root_import_id = "$.index[*][?(@.docs=='Outer re-export')].id" +//@ is "$.index[*].inner[?(@.import.source=='foo::Bar')].import.id" $bar_id +//@ has "$.index[*][?(@.name=='in_root_and_mod_pub')].inner.module.items[*]" $root_import_id /// Outer re-export pub use foo::Bar; pub mod baz { - // @set baz_import_id = "$.index[*][?(@.docs=='Inner re-export')].id" - // @is "$.index[*].inner[?(@.import.source=='crate::foo::Bar')].import.id" $bar_id - // @ismany "$.index[*][?(@.name=='baz')].inner.module.items[*]" $baz_import_id + //@ set baz_import_id = "$.index[*][?(@.docs=='Inner re-export')].id" + //@ is "$.index[*].inner[?(@.import.source=='crate::foo::Bar')].import.id" $bar_id + //@ ismany "$.index[*][?(@.name=='baz')].inner.module.items[*]" $baz_import_id /// Inner re-export pub use crate::foo::Bar; } diff --git a/tests/rustdoc-json/reexport/macro.rs b/tests/rustdoc-json/reexport/macro.rs index 2cca238908e..f182208c341 100644 --- a/tests/rustdoc-json/reexport/macro.rs +++ b/tests/rustdoc-json/reexport/macro.rs @@ -1,13 +1,13 @@ //@ edition:2018 -// @set repro_id = "$.index[*][?(@.name=='repro')].id" +//@ set repro_id = "$.index[*][?(@.name=='repro')].id" #[macro_export] macro_rules! repro { () => {}; } -// @set repro2_id = "$.index[*][?(@.docs=='Re-export')].id" +//@ set repro2_id = "$.index[*][?(@.docs=='Re-export')].id" /// Re-export pub use crate::repro as repro2; -// @ismany "$.index[*][?(@.name=='macro')].inner.module.items[*]" $repro_id $repro2_id +//@ ismany "$.index[*][?(@.name=='macro')].inner.module.items[*]" $repro_id $repro2_id diff --git a/tests/rustdoc-json/reexport/mod_not_included.rs b/tests/rustdoc-json/reexport/mod_not_included.rs index bc072be81a3..7e0c0118e84 100644 --- a/tests/rustdoc-json/reexport/mod_not_included.rs +++ b/tests/rustdoc-json/reexport/mod_not_included.rs @@ -6,6 +6,6 @@ mod m1 { pub use m1::x; -// @has "$.index[*][?(@.name=='x' && @.inner.function)]" -// @has "$.index[*].inner[?(@.import.name=='x')].import.source" '"m1::x"' -// @!has "$.index[*][?(@.name=='m1')]" +//@ has "$.index[*][?(@.name=='x' && @.inner.function)]" +//@ has "$.index[*].inner[?(@.import.name=='x')].import.source" '"m1::x"' +//@ !has "$.index[*][?(@.name=='m1')]" diff --git a/tests/rustdoc-json/reexport/private_twice_one_inline.rs b/tests/rustdoc-json/reexport/private_twice_one_inline.rs index 5e6a10af529..be66ad522da 100644 --- a/tests/rustdoc-json/reexport/private_twice_one_inline.rs +++ b/tests/rustdoc-json/reexport/private_twice_one_inline.rs @@ -6,19 +6,19 @@ extern crate pub_struct as foo; #[doc(inline)] -// @set crate_use_id = "$.index[*][?(@.docs=='Hack A')].id" -// @set foo_id = "$.index[*][?(@.docs=='Hack A')].inner.import.id" +//@ set crate_use_id = "$.index[*][?(@.docs=='Hack A')].id" +//@ set foo_id = "$.index[*][?(@.docs=='Hack A')].inner.import.id" /// Hack A pub use foo::Foo; -// @set bar_id = "$.index[*][?(@.name=='bar')].id" +//@ set bar_id = "$.index[*][?(@.name=='bar')].id" pub mod bar { - // @is "$.index[*][?(@.docs=='Hack B')].inner.import.id" $foo_id - // @set bar_use_id = "$.index[*][?(@.docs=='Hack B')].id" - // @ismany "$.index[*][?(@.name=='bar')].inner.module.items[*]" $bar_use_id + //@ is "$.index[*][?(@.docs=='Hack B')].inner.import.id" $foo_id + //@ set bar_use_id = "$.index[*][?(@.docs=='Hack B')].id" + //@ ismany "$.index[*][?(@.name=='bar')].inner.module.items[*]" $bar_use_id /// Hack B pub use foo::Foo; } -// @ismany "$.index[*][?(@.inner.import)].id" $crate_use_id $bar_use_id -// @ismany "$.index[*][?(@.name=='private_twice_one_inline')].inner.module.items[*]" $bar_id $crate_use_id +//@ ismany "$.index[*][?(@.inner.import)].id" $crate_use_id $bar_use_id +//@ ismany "$.index[*][?(@.name=='private_twice_one_inline')].inner.module.items[*]" $bar_id $crate_use_id diff --git a/tests/rustdoc-json/reexport/private_two_names.rs b/tests/rustdoc-json/reexport/private_two_names.rs index e6f037eb4b3..1e5466dba5e 100644 --- a/tests/rustdoc-json/reexport/private_two_names.rs +++ b/tests/rustdoc-json/reexport/private_two_names.rs @@ -3,21 +3,21 @@ // Test for the ICE in https://github.com/rust-lang/rust/issues/83720 // A pub-in-private type re-exported under two different names shouldn't cause an error -// @!has "$.index[*][?(@.name=='style')]" +//@ !has "$.index[*][?(@.name=='style')]" mod style { - // @set color_struct_id = "$.index[*][?(@.inner.struct && @.name=='Color')].id" + //@ set color_struct_id = "$.index[*][?(@.inner.struct && @.name=='Color')].id" pub struct Color; } -// @is "$.index[*][?(@.docs=='First re-export')].inner.import.id" $color_struct_id -// @is "$.index[*][?(@.docs=='First re-export')].inner.import.name" \"Color\" -// @set color_export_id = "$.index[*][?(@.docs=='First re-export')].id" +//@ is "$.index[*][?(@.docs=='First re-export')].inner.import.id" $color_struct_id +//@ is "$.index[*][?(@.docs=='First re-export')].inner.import.name" \"Color\" +//@ set color_export_id = "$.index[*][?(@.docs=='First re-export')].id" /// First re-export pub use style::Color; -// @is "$.index[*][?(@.docs=='Second re-export')].inner.import.id" $color_struct_id -// @is "$.index[*][?(@.docs=='Second re-export')].inner.import.name" \"Colour\" -// @set colour_export_id = "$.index[*][?(@.docs=='Second re-export')].id" +//@ is "$.index[*][?(@.docs=='Second re-export')].inner.import.id" $color_struct_id +//@ is "$.index[*][?(@.docs=='Second re-export')].inner.import.name" \"Colour\" +//@ set colour_export_id = "$.index[*][?(@.docs=='Second re-export')].id" /// Second re-export pub use style::Color as Colour; -// @ismany "$.index[*][?(@.name=='private_two_names')].inner.module.items[*]" $color_export_id $colour_export_id +//@ ismany "$.index[*][?(@.name=='private_two_names')].inner.module.items[*]" $color_export_id $colour_export_id diff --git a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs index 15d194ef5d9..e021b51ab4b 100644 --- a/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs +++ b/tests/rustdoc-json/reexport/pub_use_doc_hidden.rs @@ -9,5 +9,5 @@ mod repeat_n { /// not here pub use repeat_n::RepeatN; -// @count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0 -// @!has "$.index[*][?(@.docs == 'not here')]" +//@ count "$.index[*][?(@.name=='pub_use_doc_hidden')].inner.items[*]" 0 +//@ !has "$.index[*][?(@.docs == 'not here')]" diff --git a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs index 61075088af9..25edd5dbb28 100644 --- a/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs +++ b/tests/rustdoc-json/reexport/reexport_method_from_private_module.rs @@ -1,11 +1,11 @@ // Regression test for <https://github.com/rust-lang/rust/issues/102583>. -// @set impl_S = "$.index[*][?(@.docs=='impl S')].id" -// @has "$.index[*][?(@.name=='S')].inner.struct.impls[*]" $impl_S -// @set is_present = "$.index[*][?(@.name=='is_present')].id" -// @is "$.index[*][?(@.docs=='impl S')].inner.impl.items[*]" $is_present -// @!has "$.index[*][?(@.name=='hidden_impl')]" -// @!has "$.index[*][?(@.name=='hidden_fn')]" +//@ set impl_S = "$.index[*][?(@.docs=='impl S')].id" +//@ has "$.index[*][?(@.name=='S')].inner.struct.impls[*]" $impl_S +//@ set is_present = "$.index[*][?(@.name=='is_present')].id" +//@ is "$.index[*][?(@.docs=='impl S')].inner.impl.items[*]" $is_present +//@ !has "$.index[*][?(@.name=='hidden_impl')]" +//@ !has "$.index[*][?(@.name=='hidden_fn')]" #![no_std] diff --git a/tests/rustdoc-json/reexport/reexport_of_hidden.rs b/tests/rustdoc-json/reexport/reexport_of_hidden.rs index 62c1dbff278..07ce1f5c20a 100644 --- a/tests/rustdoc-json/reexport/reexport_of_hidden.rs +++ b/tests/rustdoc-json/reexport/reexport_of_hidden.rs @@ -1,7 +1,7 @@ //@ compile-flags: --document-hidden-items -// @has "$.index[*].inner[?(@.import.name=='UsedHidden')]" -// @has "$.index[*][?(@.name=='Hidden')]" +//@ has "$.index[*].inner[?(@.import.name=='UsedHidden')]" +//@ has "$.index[*][?(@.name=='Hidden')]" pub mod submodule { #[doc(hidden)] pub struct Hidden {} diff --git a/tests/rustdoc-json/reexport/rename_private.rs b/tests/rustdoc-json/reexport/rename_private.rs index 433829bab30..3335d18e27b 100644 --- a/tests/rustdoc-json/reexport/rename_private.rs +++ b/tests/rustdoc-json/reexport/rename_private.rs @@ -1,10 +1,10 @@ //@ edition:2018 -// @!has "$.index[*][?(@.name=='inner')]" +//@ !has "$.index[*][?(@.name=='inner')]" mod inner { - // @has "$.index[*][?(@.name=='Public')]" + //@ has "$.index[*][?(@.name=='Public')]" pub struct Public; } -// @is "$.index[*][?(@.inner.import)].inner.import.name" \"NewName\" +//@ is "$.index[*][?(@.inner.import)].inner.import.name" \"NewName\" pub use inner::Public as NewName; diff --git a/tests/rustdoc-json/reexport/rename_public.rs b/tests/rustdoc-json/reexport/rename_public.rs index ebfa3d9f176..e534f458f93 100644 --- a/tests/rustdoc-json/reexport/rename_public.rs +++ b/tests/rustdoc-json/reexport/rename_public.rs @@ -1,15 +1,15 @@ //@ edition:2018 -// @set inner_id = "$.index[*][?(@.name=='inner')].id" +//@ set inner_id = "$.index[*][?(@.name=='inner')].id" pub mod inner { - // @set public_id = "$.index[*][?(@.name=='Public')].id" - // @ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id + //@ set public_id = "$.index[*][?(@.name=='Public')].id" + //@ ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -// @set import_id = "$.index[*][?(@.docs=='Re-export')].id" -// @!has "$.index[*].inner[?(@.import.name=='Public')]" -// @is "$.index[*].inner[?(@.import.name=='NewName')].import.source" \"inner::Public\" +//@ set import_id = "$.index[*][?(@.docs=='Re-export')].id" +//@ !has "$.index[*].inner[?(@.import.name=='Public')]" +//@ is "$.index[*].inner[?(@.import.name=='NewName')].import.source" \"inner::Public\" /// Re-export pub use inner::Public as NewName; -// @ismany "$.index[*][?(@.name=='rename_public')].inner.module.items[*]" $inner_id $import_id +//@ ismany "$.index[*][?(@.name=='rename_public')].inner.module.items[*]" $inner_id $import_id diff --git a/tests/rustdoc-json/reexport/same_name_different_types.rs b/tests/rustdoc-json/reexport/same_name_different_types.rs index 42ba6c40019..b0a06d4ecfa 100644 --- a/tests/rustdoc-json/reexport/same_name_different_types.rs +++ b/tests/rustdoc-json/reexport/same_name_different_types.rs @@ -1,22 +1,22 @@ // Regression test for <https://github.com/rust-lang/rust/issues/107677>. pub mod nested { - // @set foo_struct = "$.index[*][?(@.docs == 'Foo the struct')].id" + //@ set foo_struct = "$.index[*][?(@.docs == 'Foo the struct')].id" /// Foo the struct pub struct Foo {} - // @set foo_fn = "$.index[*][?(@.docs == 'Foo the function')].id" + //@ set foo_fn = "$.index[*][?(@.docs == 'Foo the function')].id" #[allow(non_snake_case)] /// Foo the function pub fn Foo() {} } -// @ismany "$.index[*].inner[?(@.import.name == 'Foo')].import.id" $foo_fn $foo_struct -// @ismany "$.index[*].inner[?(@.import.name == 'Bar')].import.id" $foo_fn $foo_struct +//@ ismany "$.index[*].inner[?(@.import.name == 'Foo')].import.id" $foo_fn $foo_struct +//@ ismany "$.index[*].inner[?(@.import.name == 'Bar')].import.id" $foo_fn $foo_struct -// @count "$.index[*].inner[?(@.import.name == 'Foo')]" 2 +//@ count "$.index[*].inner[?(@.import.name == 'Foo')]" 2 pub use nested::Foo; -// @count "$.index[*].inner[?(@.import.name == 'Bar')]" 2 +//@ count "$.index[*].inner[?(@.import.name == 'Bar')]" 2 pub use Foo as Bar; diff --git a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs index 1e1710e1c08..c533b9ba770 100644 --- a/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs +++ b/tests/rustdoc-json/reexport/same_type_reexported_more_than_once.rs @@ -5,17 +5,17 @@ #![no_std] mod inner { - // @set trait_id = "$.index[*][?(@.name=='Trait')].id" + //@ set trait_id = "$.index[*][?(@.name=='Trait')].id" pub trait Trait {} } -// @set export_id = "$.index[*][?(@.docs=='First re-export')].id" -// @is "$.index[*].inner[?(@.import.name=='Trait')].import.id" $trait_id +//@ set export_id = "$.index[*][?(@.docs=='First re-export')].id" +//@ is "$.index[*].inner[?(@.import.name=='Trait')].import.id" $trait_id /// First re-export pub use inner::Trait; -// @set reexport_id = "$.index[*][?(@.docs=='Second re-export')].id" -// @is "$.index[*].inner[?(@.import.name=='Reexport')].import.id" $trait_id +//@ set reexport_id = "$.index[*][?(@.docs=='Second re-export')].id" +//@ is "$.index[*].inner[?(@.import.name=='Reexport')].import.id" $trait_id /// Second re-export pub use inner::Trait as Reexport; -// @ismany "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.module.items[*]" $reexport_id $export_id +//@ ismany "$.index[*][?(@.name=='same_type_reexported_more_than_once')].inner.module.items[*]" $reexport_id $export_id diff --git a/tests/rustdoc-json/reexport/simple_private.rs b/tests/rustdoc-json/reexport/simple_private.rs index 7b6509abc8d..9af0157818b 100644 --- a/tests/rustdoc-json/reexport/simple_private.rs +++ b/tests/rustdoc-json/reexport/simple_private.rs @@ -1,14 +1,14 @@ //@ edition:2018 -// @!has "$.index[*][?(@.name=='inner')]" +//@ !has "$.index[*][?(@.name=='inner')]" mod inner { - // @set pub_id = "$.index[*][?(@.name=='Public')].id" + //@ set pub_id = "$.index[*][?(@.name=='Public')].id" pub struct Public; } -// @is "$.index[*][?(@.inner.import)].inner.import.name" \"Public\" -// @is "$.index[*][?(@.inner.import)].inner.import.id" $pub_id -// @set use_id = "$.index[*][?(@.inner.import)].id" +//@ is "$.index[*][?(@.inner.import)].inner.import.name" \"Public\" +//@ is "$.index[*][?(@.inner.import)].inner.import.id" $pub_id +//@ set use_id = "$.index[*][?(@.inner.import)].id" pub use inner::Public; -// @ismany "$.index[*][?(@.name=='simple_private')].inner.module.items[*]" $use_id +//@ ismany "$.index[*][?(@.name=='simple_private')].inner.module.items[*]" $use_id diff --git a/tests/rustdoc-json/reexport/simple_public.rs b/tests/rustdoc-json/reexport/simple_public.rs index 55d32b99951..d7b44b2f987 100644 --- a/tests/rustdoc-json/reexport/simple_public.rs +++ b/tests/rustdoc-json/reexport/simple_public.rs @@ -1,16 +1,16 @@ //@ edition:2018 -// @set inner_id = "$.index[*][?(@.name=='inner')].id" +//@ set inner_id = "$.index[*][?(@.name=='inner')].id" pub mod inner { - // @set public_id = "$.index[*][?(@.name=='Public')].id" - // @ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id + //@ set public_id = "$.index[*][?(@.name=='Public')].id" + //@ ismany "$.index[*][?(@.name=='inner')].inner.module.items[*]" $public_id pub struct Public; } -// @set import_id = "$.index[*][?(@.docs=='Outer')].id" -// @is "$.index[*][?(@.docs=='Outer')].inner.import.source" \"inner::Public\" +//@ set import_id = "$.index[*][?(@.docs=='Outer')].id" +//@ is "$.index[*][?(@.docs=='Outer')].inner.import.source" \"inner::Public\" /// Outer pub use inner::Public; -// @ismany "$.index[*][?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id +//@ ismany "$.index[*][?(@.name=='simple_public')].inner.module.items[*]" $import_id $inner_id diff --git a/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs b/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs index de67badffd5..59699e4861b 100644 --- a/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs +++ b/tests/rustdoc-json/reexport/synthesize_trait_with_docs.rs @@ -7,4 +7,4 @@ pub struct Local; impl trait_with_docs::HasDocs for Local {} -// @!has "$.index[*][?(@.name == 'HasDocs')]" +//@ !has "$.index[*][?(@.name == 'HasDocs')]" diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index a9301b3fe4f..4a1922e15e5 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -5,8 +5,8 @@ mod secret { pub struct Secret; } -// @has "$.index[*][?(@.name=='get_secret')].inner.function" -// @is "$.index[*][?(@.name=='get_secret')].inner.function.decl.output.resolved_path.name" \"secret::Secret\" +//@ has "$.index[*][?(@.name=='get_secret')].inner.function" +//@ is "$.index[*][?(@.name=='get_secret')].inner.function.decl.output.resolved_path.name" \"secret::Secret\" pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc-json/stripped_modules.rs b/tests/rustdoc-json/stripped_modules.rs index d5ab1173d92..d0db9c6588b 100644 --- a/tests/rustdoc-json/stripped_modules.rs +++ b/tests/rustdoc-json/stripped_modules.rs @@ -1,17 +1,17 @@ -// @!has "$.index[*][?(@.name=='no_pub_inner')]" +//@ !has "$.index[*][?(@.name=='no_pub_inner')]" mod no_pub_inner { fn priv_inner() {} } -// @!has "$.index[*][?(@.name=='pub_inner_unreachable')]" +//@ !has "$.index[*][?(@.name=='pub_inner_unreachable')]" mod pub_inner_unreachable { - // @!has "$.index[*][?(@.name=='pub_inner_1')]" + //@ !has "$.index[*][?(@.name=='pub_inner_1')]" pub fn pub_inner_1() {} } -// @!has "$.index[*][?(@.name=='pub_inner_reachable')]" +//@ !has "$.index[*][?(@.name=='pub_inner_reachable')]" mod pub_inner_reachable { - // @has "$.index[*][?(@.name=='pub_inner_2')]" + //@ has "$.index[*][?(@.name=='pub_inner_2')]" pub fn pub_inner_2() {} } diff --git a/tests/rustdoc-json/structs/field_order.rs b/tests/rustdoc-json/structs/field_order.rs index a8c18323d52..7e556df777f 100644 --- a/tests/rustdoc-json/structs/field_order.rs +++ b/tests/rustdoc-json/structs/field_order.rs @@ -15,24 +15,24 @@ pub struct Foo { pub vll_9: i32, } -// @set 0 = '$.index[*][?(@.name == "ews_0")].id' -// @set 1 = '$.index[*][?(@.name == "dik_1")].id' -// @set 2 = '$.index[*][?(@.name == "hsk_2")].id' -// @set 3 = '$.index[*][?(@.name == "djt_3")].id' -// @set 4 = '$.index[*][?(@.name == "jnr_4")].id' -// @set 5 = '$.index[*][?(@.name == "dfs_5")].id' -// @set 6 = '$.index[*][?(@.name == "bja_6")].id' -// @set 7 = '$.index[*][?(@.name == "lyc_7")].id' -// @set 8 = '$.index[*][?(@.name == "yqd_8")].id' -// @set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' +//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' +//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' +//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' +//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[0]' $0 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[1]' $1 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[2]' $2 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[3]' $3 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[4]' $4 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[5]' $5 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[6]' $6 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[7]' $7 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[8]' $8 -// @is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[9]' $9 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[0]' $0 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[1]' $1 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[2]' $2 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[3]' $3 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[4]' $4 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[5]' $5 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[6]' $6 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[7]' $7 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[8]' $8 +//@ is '$.index[*][?(@.name == "Foo")].inner.struct.kind.plain.fields[9]' $9 diff --git a/tests/rustdoc-json/structs/plain_all_pub.rs b/tests/rustdoc-json/structs/plain_all_pub.rs index 777260100d6..aa53b59726a 100644 --- a/tests/rustdoc-json/structs/plain_all_pub.rs +++ b/tests/rustdoc-json/structs/plain_all_pub.rs @@ -3,9 +3,9 @@ pub struct Demo { pub y: i32, } -// @set x = "$.index[*][?(@.name=='x')].id" -// @set y = "$.index[*][?(@.name=='y')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[1]" $y -// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 2 -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" false +//@ set x = "$.index[*][?(@.name=='x')].id" +//@ set y = "$.index[*][?(@.name=='y')].id" +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[1]" $y +//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 2 +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" false diff --git a/tests/rustdoc-json/structs/plain_doc_hidden.rs b/tests/rustdoc-json/structs/plain_doc_hidden.rs index 1ff4489ef6b..39f9367cb93 100644 --- a/tests/rustdoc-json/structs/plain_doc_hidden.rs +++ b/tests/rustdoc-json/structs/plain_doc_hidden.rs @@ -4,8 +4,8 @@ pub struct Demo { pub y: i32, } -// @set x = "$.index[*][?(@.name=='x')].id" -// @!has "$.index[*][?(@.name=='y')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true +//@ set x = "$.index[*][?(@.name=='x')].id" +//@ !has "$.index[*][?(@.name=='y')].id" +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true diff --git a/tests/rustdoc-json/structs/plain_empty.rs b/tests/rustdoc-json/structs/plain_empty.rs index c037c0251b9..00b4b05ebdd 100644 --- a/tests/rustdoc-json/structs/plain_empty.rs +++ b/tests/rustdoc-json/structs/plain_empty.rs @@ -1,5 +1,5 @@ -// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct" -// @is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields_stripped" false -// @is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields" [] +//@ is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='PlainEmpty')].inner.struct" +//@ is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields_stripped" false +//@ is "$.index[*][?(@.name=='PlainEmpty')].inner.struct.kind.plain.fields" [] pub struct PlainEmpty {} diff --git a/tests/rustdoc-json/structs/plain_pub_priv.rs b/tests/rustdoc-json/structs/plain_pub_priv.rs index ff061be62d1..f9ab8714f81 100644 --- a/tests/rustdoc-json/structs/plain_pub_priv.rs +++ b/tests/rustdoc-json/structs/plain_pub_priv.rs @@ -3,7 +3,7 @@ pub struct Demo { y: i32, } -// @set x = "$.index[*][?(@.name=='x')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x -// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true +//@ set x = "$.index[*][?(@.name=='x')].id" +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[0]" $x +//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields[*]" 1 +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.plain.fields_stripped" true diff --git a/tests/rustdoc-json/structs/tuple.rs b/tests/rustdoc-json/structs/tuple.rs index 16ab95ed271..6c8dc79dfe2 100644 --- a/tests/rustdoc-json/structs/tuple.rs +++ b/tests/rustdoc-json/structs/tuple.rs @@ -1,4 +1,4 @@ -// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Tuple')].inner.struct" -// @is "$.index[*][?(@.name=='Tuple')].inner.struct.kind.tuple" '[null, null]' +//@ is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='Tuple')].inner.struct" +//@ is "$.index[*][?(@.name=='Tuple')].inner.struct.kind.tuple" '[null, null]' pub struct Tuple(u32, String); diff --git a/tests/rustdoc-json/structs/tuple_empty.rs b/tests/rustdoc-json/structs/tuple_empty.rs index 4d4af8558bb..137915e6c05 100644 --- a/tests/rustdoc-json/structs/tuple_empty.rs +++ b/tests/rustdoc-json/structs/tuple_empty.rs @@ -1,2 +1,2 @@ -// @is "$.index[*][?(@.name=='TupleUnit')].inner.struct.kind.tuple" [] +//@ is "$.index[*][?(@.name=='TupleUnit')].inner.struct.kind.tuple" [] pub struct TupleUnit(); diff --git a/tests/rustdoc-json/structs/tuple_pub_priv.rs b/tests/rustdoc-json/structs/tuple_pub_priv.rs index a669ba1dfcc..11af26e6ea3 100644 --- a/tests/rustdoc-json/structs/tuple_pub_priv.rs +++ b/tests/rustdoc-json/structs/tuple_pub_priv.rs @@ -5,9 +5,9 @@ pub struct Demo( #[doc(hidden)] i32, ); -// @set field = "$.index[*][?(@.docs=='field')].id" +//@ set field = "$.index[*][?(@.docs=='field')].id" -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[0]" null -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[1]" $field -// @is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[2]" null -// @count "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[*]" 3 +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[0]" null +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[1]" $field +//@ is "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[2]" null +//@ count "$.index[*][?(@.name=='Demo')].inner.struct.kind.tuple[*]" 3 diff --git a/tests/rustdoc-json/structs/unit.rs b/tests/rustdoc-json/structs/unit.rs index 640d3fb7865..ad6af65c0e0 100644 --- a/tests/rustdoc-json/structs/unit.rs +++ b/tests/rustdoc-json/structs/unit.rs @@ -1,4 +1,4 @@ -// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Unit')].inner.struct" -// @is "$.index[*][?(@.name=='Unit')].inner.struct.kind" \"unit\" +//@ is "$.index[*][?(@.name=='Unit')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='Unit')].inner.struct" +//@ is "$.index[*][?(@.name=='Unit')].inner.struct.kind" \"unit\" pub struct Unit; diff --git a/tests/rustdoc-json/structs/with_generics.rs b/tests/rustdoc-json/structs/with_generics.rs index d721cbdbe25..6e13dae9ebf 100644 --- a/tests/rustdoc-json/structs/with_generics.rs +++ b/tests/rustdoc-json/structs/with_generics.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; -// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].name" \"T\" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].kind.type.bounds" [] -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].name" \"U\" -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].kind.type.bounds" [] -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields_stripped" true -// @is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields" [] +//@ is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='WithGenerics')].inner.struct" +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].name" \"T\" +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[0].kind.type.bounds" [] +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].name" \"U\" +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.generics.params[1].kind.type.bounds" [] +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields_stripped" true +//@ is "$.index[*][?(@.name=='WithGenerics')].inner.struct.kind.plain.fields" [] pub struct WithGenerics<T, U> { stuff: Vec<T>, things: HashMap<U, U>, diff --git a/tests/rustdoc-json/structs/with_primitives.rs b/tests/rustdoc-json/structs/with_primitives.rs index e0285a9e688..2ca11b50608 100644 --- a/tests/rustdoc-json/structs/with_primitives.rs +++ b/tests/rustdoc-json/structs/with_primitives.rs @@ -1,11 +1,11 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct" -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].name" \"\'a\" -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].kind.lifetime.outlives" [] -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields_stripped" true -// @is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields" [] +//@ is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='WithPrimitives')].inner.struct" +//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].name" \"\'a\" +//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.generics.params[0].kind.lifetime.outlives" [] +//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields_stripped" true +//@ is "$.index[*][?(@.name=='WithPrimitives')].inner.struct.kind.plain.fields" [] pub struct WithPrimitives<'a> { num: u32, s: &'a str, diff --git a/tests/rustdoc-json/trait_alias.rs b/tests/rustdoc-json/trait_alias.rs index dc930550ef1..ca9e5edfdf7 100644 --- a/tests/rustdoc-json/trait_alias.rs +++ b/tests/rustdoc-json/trait_alias.rs @@ -1,18 +1,18 @@ // ignore-tidy-linelength #![feature(trait_alias)] -// @set StrLike = "$.index[*][?(@.name=='StrLike')].id" -// @is "$.index[*][?(@.name=='StrLike')].visibility" \"public\" -// @has "$.index[*][?(@.name=='StrLike')].inner.trait_alias" -// @is "$.index[*][?(@.name=='StrLike')].span.filename" $FILE +//@ set StrLike = "$.index[*][?(@.name=='StrLike')].id" +//@ is "$.index[*][?(@.name=='StrLike')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='StrLike')].inner.trait_alias" +//@ is "$.index[*][?(@.name=='StrLike')].span.filename" $FILE pub trait StrLike = AsRef<str>; -// @is "$.index[*][?(@.name=='f')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike +//@ is "$.index[*][?(@.name=='f')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike pub fn f() -> impl StrLike { "heya" } -// @!is "$.index[*][?(@.name=='g')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike +//@ !is "$.index[*][?(@.name=='g')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $StrLike pub fn g() -> impl AsRef<str> { "heya" } diff --git a/tests/rustdoc-json/traits/has_body.rs b/tests/rustdoc-json/traits/has_body.rs index 219e2d9bc54..95e0f97b52c 100644 --- a/tests/rustdoc-json/traits/has_body.rs +++ b/tests/rustdoc-json/traits/has_body.rs @@ -1,21 +1,21 @@ -// @has "$.index[*][?(@.name=='Foo')]" +//@ has "$.index[*][?(@.name=='Foo')]" pub trait Foo { - // @is "$.index[*][?(@.name=='no_self')].inner.function.has_body" false + //@ is "$.index[*][?(@.name=='no_self')].inner.function.has_body" false fn no_self(); - // @is "$.index[*][?(@.name=='move_self')].inner.function.has_body" false + //@ is "$.index[*][?(@.name=='move_self')].inner.function.has_body" false fn move_self(self); - // @is "$.index[*][?(@.name=='ref_self')].inner.function.has_body" false + //@ is "$.index[*][?(@.name=='ref_self')].inner.function.has_body" false fn ref_self(&self); - // @is "$.index[*][?(@.name=='no_self_def')].inner.function.has_body" true + //@ is "$.index[*][?(@.name=='no_self_def')].inner.function.has_body" true fn no_self_def() {} - // @is "$.index[*][?(@.name=='move_self_def')].inner.function.has_body" true + //@ is "$.index[*][?(@.name=='move_self_def')].inner.function.has_body" true fn move_self_def(self) {} - // @is "$.index[*][?(@.name=='ref_self_def')].inner.function.has_body" true + //@ is "$.index[*][?(@.name=='ref_self_def')].inner.function.has_body" true fn ref_self_def(&self) {} } pub trait Bar: Clone { - // @is "$.index[*][?(@.name=='method')].inner.function.has_body" false + //@ is "$.index[*][?(@.name=='method')].inner.function.has_body" false fn method(&self, param: usize); } diff --git a/tests/rustdoc-json/traits/implementors.rs b/tests/rustdoc-json/traits/implementors.rs index c27553c7544..9fdb763b61e 100644 --- a/tests/rustdoc-json/traits/implementors.rs +++ b/tests/rustdoc-json/traits/implementors.rs @@ -5,14 +5,14 @@ pub struct GeorgeMichael {} impl Wham for GeorgeMichael {} // Find IDs. -// @set wham = "$.index[*][?(@.name=='Wham')].id" -// @set gmWham = "$.index[*][?(@.docs=='Wham for George Michael')].id" -// @set gm = "$.index[*][?(@.name=='GeorgeMichael')].id" +//@ set wham = "$.index[*][?(@.name=='Wham')].id" +//@ set gmWham = "$.index[*][?(@.docs=='Wham for George Michael')].id" +//@ set gm = "$.index[*][?(@.name=='GeorgeMichael')].id" // Both struct and trait point to impl. -// @has "$.index[*][?(@.name=='GeorgeMichael')].inner.struct.impls[*]" $gmWham -// @is "$.index[*][?(@.name=='Wham')].inner.trait.implementations[*]" $gmWham +//@ has "$.index[*][?(@.name=='GeorgeMichael')].inner.struct.impls[*]" $gmWham +//@ is "$.index[*][?(@.name=='Wham')].inner.trait.implementations[*]" $gmWham // Impl points to both struct and trait. -// @is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.trait.id" $wham -// @is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.for.resolved_path.id" $gm +//@ is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.trait.id" $wham +//@ is "$.index[*][?(@.docs == 'Wham for George Michael')].inner.impl.for.resolved_path.id" $gm diff --git a/tests/rustdoc-json/traits/is_object_safe.rs b/tests/rustdoc-json/traits/is_object_safe.rs index 131c5fc57a5..35c4e4eb847 100644 --- a/tests/rustdoc-json/traits/is_object_safe.rs +++ b/tests/rustdoc-json/traits/is_object_safe.rs @@ -1,19 +1,19 @@ #![no_std] -// @has "$.index[*][?(@.name=='FooUnsafe')]" -// @is "$.index[*][?(@.name=='FooUnsafe')].inner.trait.is_object_safe" false +//@ has "$.index[*][?(@.name=='FooUnsafe')]" +//@ is "$.index[*][?(@.name=='FooUnsafe')].inner.trait.is_object_safe" false pub trait FooUnsafe { fn foo() -> Self; } -// @has "$.index[*][?(@.name=='BarUnsafe')]" -// @is "$.index[*][?(@.name=='BarUnsafe')].inner.trait.is_object_safe" false +//@ has "$.index[*][?(@.name=='BarUnsafe')]" +//@ is "$.index[*][?(@.name=='BarUnsafe')].inner.trait.is_object_safe" false pub trait BarUnsafe<T> { fn foo(i: T); } -// @has "$.index[*][?(@.name=='FooSafe')]" -// @is "$.index[*][?(@.name=='FooSafe')].inner.trait.is_object_safe" true +//@ has "$.index[*][?(@.name=='FooSafe')]" +//@ is "$.index[*][?(@.name=='FooSafe')].inner.trait.is_object_safe" true pub trait FooSafe { fn foo(&self); } diff --git a/tests/rustdoc-json/traits/private_supertrait.rs b/tests/rustdoc-json/traits/private_supertrait.rs index 67b5a858ab7..d31b6ca4ad8 100644 --- a/tests/rustdoc-json/traits/private_supertrait.rs +++ b/tests/rustdoc-json/traits/private_supertrait.rs @@ -1,11 +1,11 @@ // ignore-tidy-linelength -// @!has "$.index[*][?(@.name == 'sealed')]" +//@ !has "$.index[*][?(@.name == 'sealed')]" mod sealed { - // @set sealed_id = "$.index[*][?(@.name=='Sealed')].id" + //@ set sealed_id = "$.index[*][?(@.name=='Sealed')].id" pub trait Sealed {} } -// @count "$.index[*][?(@.name=='Trait')].inner.trait.bounds[*]" 1 -// @is "$.index[*][?(@.name=='Trait')].inner.trait.bounds[0].trait_bound.trait.id" $sealed_id +//@ count "$.index[*][?(@.name=='Trait')].inner.trait.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='Trait')].inner.trait.bounds[0].trait_bound.trait.id" $sealed_id pub trait Trait: sealed::Sealed {} diff --git a/tests/rustdoc-json/traits/supertrait.rs b/tests/rustdoc-json/traits/supertrait.rs index bbae3557cf9..e8fe82ab9cd 100644 --- a/tests/rustdoc-json/traits/supertrait.rs +++ b/tests/rustdoc-json/traits/supertrait.rs @@ -1,22 +1,22 @@ // ignore-tidy-linelength -// @set loud_id = "$.index[*][?(@.name=='Loud')].id" +//@ set loud_id = "$.index[*][?(@.name=='Loud')].id" pub trait Loud {} -// @set very_loud_id = "$.index[*][?(@.name=='VeryLoud')].id" -// @count "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[*]" 1 -// @is "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[0].trait_bound.trait.id" $loud_id +//@ set very_loud_id = "$.index[*][?(@.name=='VeryLoud')].id" +//@ count "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[*]" 1 +//@ is "$.index[*][?(@.name=='VeryLoud')].inner.trait.bounds[0].trait_bound.trait.id" $loud_id pub trait VeryLoud: Loud {} -// @set sounds_good_id = "$.index[*][?(@.name=='SoundsGood')].id" +//@ set sounds_good_id = "$.index[*][?(@.name=='SoundsGood')].id" pub trait SoundsGood {} -// @count "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[*]" 2 -// @is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[0].trait_bound.trait.id" $very_loud_id -// @is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[1].trait_bound.trait.id" $sounds_good_id +//@ count "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[*]" 2 +//@ is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[0].trait_bound.trait.id" $very_loud_id +//@ is "$.index[*][?(@.name=='MetalBand')].inner.trait.bounds[1].trait_bound.trait.id" $sounds_good_id pub trait MetalBand: VeryLoud + SoundsGood {} -// @count "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[*]" 2 -// @is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[1].trait_bound.trait.id" $very_loud_id -// @is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[0].trait_bound.trait.id" $sounds_good_id +//@ count "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[*]" 2 +//@ is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[1].trait_bound.trait.id" $very_loud_id +//@ is "$.index[*][?(@.name=='DnabLatem')].inner.trait.bounds[0].trait_bound.trait.id" $sounds_good_id pub trait DnabLatem: SoundsGood + VeryLoud {} diff --git a/tests/rustdoc-json/traits/trait_alias.rs b/tests/rustdoc-json/traits/trait_alias.rs index 4fcc26f7de2..a1ab039692b 100644 --- a/tests/rustdoc-json/traits/trait_alias.rs +++ b/tests/rustdoc-json/traits/trait_alias.rs @@ -3,25 +3,25 @@ #![feature(trait_alias)] -// @set Orig = "$.index[*][?(@.name == 'Orig')].id" -// @has "$.index[*][?(@.name == 'Orig')].inner.trait" +//@ set Orig = "$.index[*][?(@.name == 'Orig')].id" +//@ has "$.index[*][?(@.name == 'Orig')].inner.trait" pub trait Orig<T> {} -// @set Alias = "$.index[*][?(@.name == 'Alias')].id" -// @has "$.index[*][?(@.name == 'Alias')].inner.trait_alias" -// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.generics" '{"params": [], "where_predicates": []}' -// @count "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[*]" 1 -// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.id" $Orig -// @is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.primitive" '"i32"' +//@ set Alias = "$.index[*][?(@.name == 'Alias')].id" +//@ has "$.index[*][?(@.name == 'Alias')].inner.trait_alias" +//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.generics" '{"params": [], "where_predicates": []}' +//@ count "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[*]" 1 +//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.id" $Orig +//@ is "$.index[*][?(@.name == 'Alias')].inner.trait_alias.params[0].trait_bound.trait.args.angle_bracketed.args[0].type.primitive" '"i32"' pub trait Alias = Orig<i32>; pub struct Struct; impl Orig<i32> for Struct {} -// @has "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait" -// @is "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $Alias -// @is "$.index[*][?(@.name=='takes_alias')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias +//@ has "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait" +//@ is "$.index[*][?(@.name=='takes_alias')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $Alias +//@ is "$.index[*][?(@.name=='takes_alias')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $Alias pub fn takes_alias(_: impl Alias) {} // FIXME: Should the trait be mentioned in both the decl and generics? diff --git a/tests/rustdoc-json/traits/uses_extern_trait.rs b/tests/rustdoc-json/traits/uses_extern_trait.rs index 55a51f739ab..3a93bcaefd4 100644 --- a/tests/rustdoc-json/traits/uses_extern_trait.rs +++ b/tests/rustdoc-json/traits/uses_extern_trait.rs @@ -1,5 +1,5 @@ #![no_std] pub fn drop_default<T: core::default::Default>(_x: T) {} -// @!has "$.index[*][?(@.name=='Debug')]" -// @!has "$.index[*][?(@.name=='Default')]" +//@ !has "$.index[*][?(@.name=='Debug')]" +//@ !has "$.index[*][?(@.name=='Default')]" diff --git a/tests/rustdoc-json/type/dyn.rs b/tests/rustdoc-json/type/dyn.rs index 4db65b61dc6..86ea1c2b5f2 100644 --- a/tests/rustdoc-json/type/dyn.rs +++ b/tests/rustdoc-json/type/dyn.rs @@ -1,46 +1,46 @@ // ignore-tidy-linelength use std::fmt::Debug; -// @count "$.index[*][?(@.name=='dyn')].inner.module.items[*]" 3 -// @set sync_int_gen = "$.index[*][?(@.name=='SyncIntGen')].id" -// @set ref_fn = "$.index[*][?(@.name=='RefFn')].id" -// @set weird_order = "$.index[*][?(@.name=='WeirdOrder')].id" -// @ismany "$.index[*][?(@.name=='dyn')].inner.module.items[*]" $sync_int_gen $ref_fn $weird_order +//@ count "$.index[*][?(@.name=='dyn')].inner.module.items[*]" 3 +//@ set sync_int_gen = "$.index[*][?(@.name=='SyncIntGen')].id" +//@ set ref_fn = "$.index[*][?(@.name=='RefFn')].id" +//@ set weird_order = "$.index[*][?(@.name=='WeirdOrder')].id" +//@ ismany "$.index[*][?(@.name=='dyn')].inner.module.items[*]" $sync_int_gen $ref_fn $weird_order -// @has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}' -// @has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.name" \"Box\" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.bindings" [] -// @count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1 -// @has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.lifetime" \"\'static\" -// @count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[*]" 3 -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Fn"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Send"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.name" '"Sync"' -// @is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' +//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias" +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}' +//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path" +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.name" \"Box\" +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.bindings" [] +//@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1 +//@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.lifetime" \"\'static\" +//@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[*]" 3 +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Fn"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Send"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.name" '"Sync"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>; -// @has "$.index[*][?(@.name=='RefFn')].inner.type_alias" -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' -// @has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref" -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.mutable" 'false' -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.lifetime" "\"'a\"" -// @has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait" -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null -// @count "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1 -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' -// @has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" -// @has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" -// @is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" +//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias" +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' +//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref" +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.mutable" 'false' +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.lifetime" "\"'a\"" +//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait" +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null +//@ count "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1 +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' +//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" +//@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; -// @is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Send"' -// @is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Debug"' +//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Send"' +//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Debug"' pub type WeirdOrder = Box<dyn Send + Debug>; diff --git a/tests/rustdoc-json/type/extern.rs b/tests/rustdoc-json/type/extern.rs index 59e099ec9fc..fda5d5ab970 100644 --- a/tests/rustdoc-json/type/extern.rs +++ b/tests/rustdoc-json/type/extern.rs @@ -5,5 +5,5 @@ extern "C" { pub type Foo; } -// @is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"' -// @is "$.index[*][?(@.docs=='No inner information')].inner" \"foreign_type\" +//@ is "$.index[*][?(@.docs=='No inner information')].name" '"Foo"' +//@ is "$.index[*][?(@.docs=='No inner information')].inner" \"foreign_type\" diff --git a/tests/rustdoc-json/type/fn_lifetime.rs b/tests/rustdoc-json/type/fn_lifetime.rs index 4aca303e6dc..2893b37319f 100644 --- a/tests/rustdoc-json/type/fn_lifetime.rs +++ b/tests/rustdoc-json/type/fn_lifetime.rs @@ -1,26 +1,26 @@ // ignore-tidy-linelength -// @has "$.index[*][?(@.name=='GenericFn')].inner.type_alias" +//@ has "$.index[*][?(@.name=='GenericFn')].inner.type_alias" -// @ismany "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].name" \"\'a\" -// @has "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime" -// @count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime.outlives[*]" 0 -// @count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.where_predicates[*]" 0 -// @count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.generic_params[*]" 0 -// @count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" +//@ ismany "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].name" \"\'a\" +//@ has "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime" +//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.params[*].kind.lifetime.outlives[*]" 0 +//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.generic_params[*]" 0 +//@ count "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='GenericFn')].inner.type_alias.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" pub type GenericFn<'a> = fn(&'a i32) -> &'a i32; -// @has "$.index[*][?(@.name=='ForAll')].inner.type_alias" -// @count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.params[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.where_predicates[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*]" 1 -// @is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].name" \"\'a\" -// @has "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime" -// @count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime.outlives[*]" 0 -// @count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" -// @is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" +//@ has "$.index[*][?(@.name=='ForAll')].inner.type_alias" +//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.params[*]" 0 +//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*]" 1 +//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].name" \"\'a\" +//@ has "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime" +//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.generic_params[*].kind.lifetime.outlives[*]" 0 +//@ count "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.inputs[*][1].borrowed_ref.lifetime" \"\'a\" +//@ is "$.index[*][?(@.name=='ForAll')].inner.type_alias.type.function_pointer.decl.output.borrowed_ref.lifetime" \"\'a\" pub type ForAll = for<'a> fn(&'a i32) -> &'a i32; diff --git a/tests/rustdoc-json/type/generic_default.rs b/tests/rustdoc-json/type/generic_default.rs index 30817a42e8a..306376354ce 100644 --- a/tests/rustdoc-json/type/generic_default.rs +++ b/tests/rustdoc-json/type/generic_default.rs @@ -1,33 +1,33 @@ // ignore-tidy-linelength -// @set result = "$.index[*][?(@.name=='Result')].id" +//@ set result = "$.index[*][?(@.name=='Result')].id" pub enum Result<T, E> { Ok(T), Err(E), } -// @set my_error = "$.index[*][?(@.name=='MyError')].id" +//@ set my_error = "$.index[*][?(@.name=='MyError')].id" pub struct MyError {} -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias" -// @count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.where_predicates[*]" 0 -// @count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[*]" 2 -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].name" \"T\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].name" \"E\" -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type" -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type" -// @count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.bounds[*]" 0 -// @count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.bounds[*]" 0 -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.name" \"MyError\" -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.name" \"Result\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.bindings" [] -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" -// @has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" \"T\" -// @is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" \"E\" +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias" +//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.where_predicates[*]" 0 +//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[*]" 2 +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].name" \"T\" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].name" \"E\" +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type" +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type" +//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.bounds[*]" 0 +//@ count "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.bounds[*]" 0 +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.name" \"MyError\" +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.name" \"Result\" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.bindings" [] +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" +//@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" \"T\" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" \"E\" pub type MyResult<T, E = MyError> = Result<T, E>; diff --git a/tests/rustdoc-json/type/hrtb.rs b/tests/rustdoc-json/type/hrtb.rs index f7ac878ceaa..a28b2fddf46 100644 --- a/tests/rustdoc-json/type/hrtb.rs +++ b/tests/rustdoc-json/type/hrtb.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength -// @is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.type" '{"generic": "F"}' -// @is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.type" '{"generic": "F"}' +//@ is "$.index[*][?(@.name=='genfn')].inner.function.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' pub fn genfn<F>(f: F) where for<'a, 'b> F: Fn(&'a i32, &'b i32), @@ -10,12 +10,12 @@ where f(&zero, &zero); } -// @is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' -// @is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' -// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null -// @count "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 -// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -// @is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.generics" '{"params": [], "where_predicates": []}' +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null +//@ count "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.decl.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); diff --git a/tests/rustdoc-json/type/inherent_associated_type.rs b/tests/rustdoc-json/type/inherent_associated_type.rs index f8603147951..386c7c80d7f 100644 --- a/tests/rustdoc-json/type/inherent_associated_type.rs +++ b/tests/rustdoc-json/type/inherent_associated_type.rs @@ -2,23 +2,23 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -// @set OwnerMetadata = '$.index[*][?(@.name=="OwnerMetadata")].id' +//@ set OwnerMetadata = '$.index[*][?(@.name=="OwnerMetadata")].id' pub struct OwnerMetadata; -// @set Owner = '$.index[*][?(@.name=="Owner")].id' +//@ set Owner = '$.index[*][?(@.name=="Owner")].id' pub struct Owner; pub fn create() -> Owner::Metadata { OwnerMetadata } -// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.name' '"Metadata"' -// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.trait' null -// @is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.self_type.resolved_path.id' $Owner +//@ is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.name' '"Metadata"' +//@ is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.trait' null +//@ is '$.index[*][?(@.name=="create")].inner.function.decl.output.qualified_path.self_type.resolved_path.id' $Owner /// impl impl Owner { /// iat pub type Metadata = OwnerMetadata; } -// @set iat = '$.index[*][?(@.docs=="iat")].id' -// @is '$.index[*][?(@.docs=="impl")].inner.impl.items[*]' $iat -// @is '$.index[*][?(@.docs=="iat")].inner.assoc_type.default.resolved_path.id' $OwnerMetadata +//@ set iat = '$.index[*][?(@.docs=="iat")].id' +//@ is '$.index[*][?(@.docs=="impl")].inner.impl.items[*]' $iat +//@ is '$.index[*][?(@.docs=="iat")].inner.assoc_type.default.resolved_path.id' $OwnerMetadata diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs index 6da23c8fb4e..45fe19bf467 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_bound.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs @@ -2,17 +2,17 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -// @set Carrier = '$.index[*][?(@.name=="Carrier")].id' +//@ set Carrier = '$.index[*][?(@.name=="Carrier")].id' pub struct Carrier<'a>(&'a ()); -// @count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"' -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\" -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"' -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null -// @is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' +//@ count "$.index[*][?(@.name=='user')].inner.function.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='user')].inner.function.decl.inputs[0][0]" '"_"' +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.generic_params[*].name' \""'b"\" +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Carrier +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].lifetime' \""'b"\" +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.name' '"Focus"' +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.trait' null +//@ is '$.index[*][?(@.name=="user")].inner.function.decl.inputs[0][1].function_pointer.decl.inputs[0][1].qualified_path.args.angle_bracketed.args[0].type.primitive' '"i32"' pub fn user(_: for<'b> fn(Carrier<'b>::Focus<i32>)) {} impl<'a> Carrier<'a> { diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs index d12e5f4a784..9b827a98419 100644 --- a/tests/rustdoc-json/type/inherent_associated_type_projections.rs +++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs @@ -2,15 +2,15 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] -// @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' +//@ set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' pub struct Parametrized<T>(T); -// @count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1 -// @is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"' -// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized -// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" -// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"' -// @is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null +//@ count "$.index[*][?(@.name=='test')].inner.function.decl.inputs[*]" 1 +//@ is "$.index[*][?(@.name=='test')].inner.function.decl.inputs[0][0]" '"_"' +//@ is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.id' $Parametrized +//@ is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.self_type.resolved_path.args.angle_bracketed.args[0].type.primitive' \"i32\" +//@ is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.name' '"Proj"' +//@ is '$.index[*][?(@.name=="test")].inner.function.decl.inputs[0][1].qualified_path.trait' null pub fn test(_: Parametrized<i32>::Proj) {} /// param_bool @@ -25,10 +25,10 @@ impl Parametrized<i32> { pub type Proj = String; } -// @set param_bool = '$.index[*][?(@.docs=="param_bool")].id' -// @set param_i32 = '$.index[*][?(@.docs=="param_i32")].id' -// @set param_bool_proj = '$.index[*][?(@.docs=="param_bool_proj")].id' -// @set param_i32_proj = '$.index[*][?(@.docs=="param_i32_proj")].id' +//@ set param_bool = '$.index[*][?(@.docs=="param_bool")].id' +//@ set param_i32 = '$.index[*][?(@.docs=="param_i32")].id' +//@ set param_bool_proj = '$.index[*][?(@.docs=="param_bool_proj")].id' +//@ set param_i32_proj = '$.index[*][?(@.docs=="param_i32_proj")].id' -// @is '$.index[*][?(@.docs=="param_bool")].inner.impl.items[*]' $param_bool_proj -// @is '$.index[*][?(@.docs=="param_i32")].inner.impl.items[*]' $param_i32_proj +//@ is '$.index[*][?(@.docs=="param_bool")].inner.impl.items[*]' $param_bool_proj +//@ is '$.index[*][?(@.docs=="param_i32")].inner.impl.items[*]' $param_i32_proj diff --git a/tests/rustdoc-json/type_alias.rs b/tests/rustdoc-json/type_alias.rs index 7a938c50ba0..ecf35c5987a 100644 --- a/tests/rustdoc-json/type_alias.rs +++ b/tests/rustdoc-json/type_alias.rs @@ -1,15 +1,15 @@ -// @set IntVec = "$.index[*][?(@.name=='IntVec')].id" -// @is "$.index[*][?(@.name=='IntVec')].visibility" \"public\" -// @has "$.index[*][?(@.name=='IntVec')].inner.type_alias" -// @is "$.index[*][?(@.name=='IntVec')].span.filename" $FILE +//@ set IntVec = "$.index[*][?(@.name=='IntVec')].id" +//@ is "$.index[*][?(@.name=='IntVec')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='IntVec')].inner.type_alias" +//@ is "$.index[*][?(@.name=='IntVec')].span.filename" $FILE pub type IntVec = Vec<u32>; -// @is "$.index[*][?(@.name=='f')].inner.function.decl.output.resolved_path.id" $IntVec +//@ is "$.index[*][?(@.name=='f')].inner.function.decl.output.resolved_path.id" $IntVec pub fn f() -> IntVec { vec![0; 32] } -// @!is "$.index[*][?(@.name=='g')].inner.function.decl.output.resolved_path.id" $IntVec +//@ !is "$.index[*][?(@.name=='g')].inner.function.decl.output.resolved_path.id" $IntVec pub fn g() -> Vec<u32> { vec![0; 32] } diff --git a/tests/rustdoc-json/unions/field_order.rs b/tests/rustdoc-json/unions/field_order.rs index 8a40bda0399..a1616f62751 100644 --- a/tests/rustdoc-json/unions/field_order.rs +++ b/tests/rustdoc-json/unions/field_order.rs @@ -15,24 +15,24 @@ pub union Foo { pub vll_9: i32, } -// @set 0 = '$.index[*][?(@.name == "ews_0")].id' -// @set 1 = '$.index[*][?(@.name == "dik_1")].id' -// @set 2 = '$.index[*][?(@.name == "hsk_2")].id' -// @set 3 = '$.index[*][?(@.name == "djt_3")].id' -// @set 4 = '$.index[*][?(@.name == "jnr_4")].id' -// @set 5 = '$.index[*][?(@.name == "dfs_5")].id' -// @set 6 = '$.index[*][?(@.name == "bja_6")].id' -// @set 7 = '$.index[*][?(@.name == "lyc_7")].id' -// @set 8 = '$.index[*][?(@.name == "yqd_8")].id' -// @set 9 = '$.index[*][?(@.name == "vll_9")].id' +//@ set 0 = '$.index[*][?(@.name == "ews_0")].id' +//@ set 1 = '$.index[*][?(@.name == "dik_1")].id' +//@ set 2 = '$.index[*][?(@.name == "hsk_2")].id' +//@ set 3 = '$.index[*][?(@.name == "djt_3")].id' +//@ set 4 = '$.index[*][?(@.name == "jnr_4")].id' +//@ set 5 = '$.index[*][?(@.name == "dfs_5")].id' +//@ set 6 = '$.index[*][?(@.name == "bja_6")].id' +//@ set 7 = '$.index[*][?(@.name == "lyc_7")].id' +//@ set 8 = '$.index[*][?(@.name == "yqd_8")].id' +//@ set 9 = '$.index[*][?(@.name == "vll_9")].id' -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[0]' $0 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[1]' $1 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[2]' $2 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[3]' $3 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[4]' $4 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[5]' $5 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[6]' $6 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[7]' $7 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[8]' $8 -// @is '$.index[*][?(@.name == "Foo")].inner.union.fields[9]' $9 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[0]' $0 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[1]' $1 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[2]' $2 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[3]' $3 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[4]' $4 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[5]' $5 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[6]' $6 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[7]' $7 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[8]' $8 +//@ is '$.index[*][?(@.name == "Foo")].inner.union.fields[9]' $9 diff --git a/tests/rustdoc-json/unions/impl.rs b/tests/rustdoc-json/unions/impl.rs index 1515f7d9397..989a025f669 100644 --- a/tests/rustdoc-json/unions/impl.rs +++ b/tests/rustdoc-json/unions/impl.rs @@ -1,15 +1,15 @@ #![no_std] -// @is "$.index[*][?(@.name=='Ux')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Ux')].inner.union" +//@ is "$.index[*][?(@.name=='Ux')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='Ux')].inner.union" pub union Ux { a: u32, b: u64, } -// @is "$.index[*][?(@.name=='Num')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Num')].inner.trait" +//@ is "$.index[*][?(@.name=='Num')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='Num')].inner.trait" pub trait Num {} -// @count "$.index[*][?(@.name=='Ux')].inner.union.impls" 1 +//@ count "$.index[*][?(@.name=='Ux')].inner.union.impls" 1 impl Num for Ux {} diff --git a/tests/rustdoc-json/unions/union.rs b/tests/rustdoc-json/unions/union.rs index 1089d9c4558..4a97b5d4fb8 100644 --- a/tests/rustdoc-json/unions/union.rs +++ b/tests/rustdoc-json/unions/union.rs @@ -1,14 +1,14 @@ -// @has "$.index[*][?(@.name=='Union')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Union')].inner.union" -// @!has "$.index[*][?(@.name=='Union')].inner.union.struct_type" -// @set Union = "$.index[*][?(@.name=='Union')].id" +//@ has "$.index[*][?(@.name=='Union')].visibility" \"public\" +//@ has "$.index[*][?(@.name=='Union')].inner.union" +//@ !has "$.index[*][?(@.name=='Union')].inner.union.struct_type" +//@ set Union = "$.index[*][?(@.name=='Union')].id" pub union Union { int: i32, float: f32, } -// @has "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path" -// @is "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path.id" $Union +//@ has "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path" +//@ is "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path.id" $Union pub fn make_int_union(int: i32) -> Union { Union { int } } diff --git a/tests/rustdoc-ui/ice-unresolved-import-100241.stderr b/tests/rustdoc-ui/ice-unresolved-import-100241.stderr new file mode 100644 index 00000000000..57fbbb59c8d --- /dev/null +++ b/tests/rustdoc-ui/ice-unresolved-import-100241.stderr @@ -0,0 +1,11 @@ +error[E0432]: unresolved import `inner` + --> $DIR/ice-unresolved-import-100241.rs:9:13 + | +LL | pub use inner::S; + | ^^^^^ maybe a missing crate `inner`? + | + = help: consider adding `extern crate inner` to use the `inner` crate + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/rustdoc-ui/invalid_associated_const.stderr b/tests/rustdoc-ui/invalid_associated_const.stderr index 6e5ddc44982..66f8ffe6d72 100644 --- a/tests/rustdoc-ui/invalid_associated_const.stderr +++ b/tests/rustdoc-ui/invalid_associated_const.stderr @@ -6,8 +6,9 @@ LL | type A: S<C<X = 0i32> = 34>; | help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error[E0229]: associated item constraints are not allowed here --> $DIR/invalid_associated_const.rs:4:17 @@ -18,8 +19,9 @@ LL | type A: S<C<X = 0i32> = 34>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error: aborting due to 2 previous errors diff --git a/tests/rustdoc-ui/issue-102467.stderr b/tests/rustdoc-ui/issue-102467.stderr index 99f91102319..5fcdba782e7 100644 --- a/tests/rustdoc-ui/issue-102467.stderr +++ b/tests/rustdoc-ui/issue-102467.stderr @@ -6,8 +6,9 @@ LL | type A: S<C<X = 0i32> = 34>; | help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102467.rs:7:17 @@ -18,8 +19,9 @@ LL | type A: S<C<X = 0i32> = 34>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error: aborting due to 2 previous errors diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr index 131adfd588c..f7f3e368a3c 100644 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ b/tests/rustdoc-ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.rs b/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.rs new file mode 100644 index 00000000000..33e10a00713 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.rs @@ -0,0 +1,38 @@ +//@ compile-flags: -Z unstable-options +//@ ignore-stage1 (can be removed after beta bump, #[cfg(bootstrap)]) +#![feature(rustc_private)] +#![deny(rustc::non_glob_import_of_type_ir_inherent)] + +extern crate rustc_type_ir; + +mod ok { + use rustc_type_ir::inherent::*; // OK + use rustc_type_ir::inherent::{}; // OK + use rustc_type_ir::inherent::{*}; // OK + + fn usage<T: rustc_type_ir::inherent::SliceLike>() {} // OK +} + +mod direct { + use rustc_type_ir::inherent::Predicate; //~ ERROR non-glob import of `rustc_type_ir::inherent` + use rustc_type_ir::inherent::{AdtDef, Ty}; + //~^ ERROR non-glob import of `rustc_type_ir::inherent` + //~| ERROR non-glob import of `rustc_type_ir::inherent` + use rustc_type_ir::inherent::ParamEnv as _; //~ ERROR non-glob import of `rustc_type_ir::inherent` +} + +mod indirect0 { + use rustc_type_ir::inherent; //~ ERROR non-glob import of `rustc_type_ir::inherent` + use rustc_type_ir::inherent as inh; //~ ERROR non-glob import of `rustc_type_ir::inherent` + use rustc_type_ir::{inherent as _}; //~ ERROR non-glob import of `rustc_type_ir::inherent` + + fn usage0<T: inherent::SliceLike>() {} + fn usage1<T: inh::SliceLike>() {} +} + +mod indirect1 { + use rustc_type_ir::inherent::{self}; //~ ERROR non-glob import of `rustc_type_ir::inherent` + use rustc_type_ir::inherent::{self as innate}; //~ ERROR non-glob import of `rustc_type_ir::inherent` +} + +fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.stderr b/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.stderr new file mode 100644 index 00000000000..84e3867c95b --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/non_glob_import_of_type_ir_inherent.stderr @@ -0,0 +1,68 @@ +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:17:9 + | +LL | use rustc_type_ir::inherent::Predicate; + | ^^^^^^^^^^^^^^^^^^^^^^^^^--------- + | | + | help: try using a glob import instead: `*` + | +note: the lint level is defined here + --> $DIR/non_glob_import_of_type_ir_inherent.rs:4:9 + | +LL | #![deny(rustc::non_glob_import_of_type_ir_inherent)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:18:35 + | +LL | use rustc_type_ir::inherent::{AdtDef, Ty}; + | ^^^^^^ help: try using a glob import instead: `*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:18:43 + | +LL | use rustc_type_ir::inherent::{AdtDef, Ty}; + | ^^ help: try using a glob import instead: `*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:21:9 + | +LL | use rustc_type_ir::inherent::ParamEnv as _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^------------- + | | + | help: try using a glob import instead: `*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:25:9 + | +LL | use rustc_type_ir::inherent; + | ^^^^^^^^^^^^^^^^^^^^^^^- help: try using a glob import instead: `::*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:26:9 + | +LL | use rustc_type_ir::inherent as inh; + | ^^^^^^^^^^^^^^^^^^^^^^^------- help: try using a glob import instead: `::*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:27:25 + | +LL | use rustc_type_ir::{inherent as _}; + | ^^^^^^^^----- help: try using a glob import instead: `::*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:34:35 + | +LL | use rustc_type_ir::inherent::{self}; + | ^^^^ help: try using a glob import instead: `*` + +error: non-glob import of `rustc_type_ir::inherent` + --> $DIR/non_glob_import_of_type_ir_inherent.rs:35:35 + | +LL | use rustc_type_ir::inherent::{self as innate}; + | ^^^^---------- + | | + | help: try using a glob import instead: `*` + +error: aborting due to 9 previous errors + diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index f971426723f..5e3f2557566 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -33,7 +33,7 @@ fn test_stable_mir() -> ControlFlow<()> { // Get all items and split generic vs monomorphic items. let (generic, mono): (Vec<_>, Vec<_>) = items.into_iter().partition(|item| item.requires_monomorphization()); - assert_eq!(mono.len(), 4, "Expected 2 mono functions and one constant"); + assert_eq!(mono.len(), 3, "Expected 3 mono functions"); assert_eq!(generic.len(), 2, "Expected 2 generic functions"); // For all monomorphic items, get the correspondent instances. diff --git a/tests/ui/abi/statics/static-mut-foreign.stderr b/tests/ui/abi/statics/static-mut-foreign.stderr index 983325c1abd..0c4bd5382a1 100644 --- a/tests/ui/abi/statics/static-mut-foreign.stderr +++ b/tests/ui/abi/statics/static-mut-foreign.stderr @@ -11,7 +11,7 @@ LL | static_bound(&rust_dbg_static_mut); help: use `addr_of!` instead to create a raw pointer | LL | static_bound(addr_of!(rust_dbg_static_mut)); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + warning: creating a mutable reference to mutable static is discouraged --> $DIR/static-mut-foreign.rs:33:22 @@ -25,7 +25,7 @@ LL | static_bound_set(&mut rust_dbg_static_mut); help: use `addr_of_mut!` instead to create a raw pointer | LL | static_bound_set(addr_of_mut!(rust_dbg_static_mut)); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: 2 warnings emitted diff --git a/tests/ui/anon-params/anon-params-denied-2018.stderr b/tests/ui/anon-params/anon-params-denied-2018.stderr index bb60c898e81..2d6356ffcb1 100644 --- a/tests/ui/anon-params/anon-params-denied-2018.stderr +++ b/tests/ui/anon-params/anon-params-denied-2018.stderr @@ -48,7 +48,7 @@ LL | fn foo_with_qualified_path(<Bar as T>::Baz); help: explicitly ignore the parameter name | LL | fn foo_with_qualified_path(_: <Bar as T>::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:15:56 @@ -60,7 +60,7 @@ LL | fn foo_with_qualified_path_and_ref(&<Bar as T>::Baz); help: explicitly ignore the parameter name | LL | fn foo_with_qualified_path_and_ref(_: &<Bar as T>::Baz); - | ~~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:18:57 @@ -72,7 +72,7 @@ LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, <Bar as T>::Baz); help: explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(_: <Bar as T>::Baz, <Bar as T>::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `(`, `...`, `..=`, `..`, `::`, `:`, `{`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:18:74 @@ -84,7 +84,7 @@ LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, <Bar as T>::Baz); help: explicitly ignore the parameter name | LL | fn foo_with_multiple_qualified_paths(<Bar as T>::Baz, _: <Bar as T>::Baz); - | ~~~~~~~~~~~~~~~~~~ + | ++ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:22:36 diff --git a/tests/ui/argument-suggestions/basic.stderr b/tests/ui/argument-suggestions/basic.stderr index ea58ca97cfa..2d52df21233 100644 --- a/tests/ui/argument-suggestions/basic.stderr +++ b/tests/ui/argument-suggestions/basic.stderr @@ -33,7 +33,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:22:5 | LL | missing(); - | ^^^^^^^-- an argument of type `u32` is missing + | ^^^^^^^-- argument #1 of type `u32` is missing | note: function defined here --> $DIR/basic.rs:15:4 @@ -86,7 +86,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:27:5 | LL | closure(); - | ^^^^^^^-- an argument is missing + | ^^^^^^^-- argument #1 is missing | note: closure defined here --> $DIR/basic.rs:26:19 diff --git a/tests/ui/argument-suggestions/display-is-suggestable.stderr b/tests/ui/argument-suggestions/display-is-suggestable.stderr index bde87475e0a..eea88c3e78d 100644 --- a/tests/ui/argument-suggestions/display-is-suggestable.stderr +++ b/tests/ui/argument-suggestions/display-is-suggestable.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/display-is-suggestable.rs:6:5 | LL | foo(); - | ^^^-- an argument of type `&dyn std::fmt::Display + Send` is missing + | ^^^-- argument #1 of type `&dyn std::fmt::Display + Send` is missing | note: function defined here --> $DIR/display-is-suggestable.rs:3:4 diff --git a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr index f6bc84c1203..47fbfc98c67 100644 --- a/tests/ui/argument-suggestions/extern-fn-arg-names.stderr +++ b/tests/ui/argument-suggestions/extern-fn-arg-names.stderr @@ -8,7 +8,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/extern-fn-arg-names.rs:7:5 | LL | dstfn(1); - | ^^^^^--- an argument is missing + | ^^^^^--- argument #2 is missing | note: function defined here --> $DIR/extern-fn-arg-names.rs:2:8 diff --git a/tests/ui/argument-suggestions/extra_arguments.stderr b/tests/ui/argument-suggestions/extra_arguments.stderr index dec3da75186..8c95cc86a27 100644 --- a/tests/ui/argument-suggestions/extra_arguments.stderr +++ b/tests/ui/argument-suggestions/extra_arguments.stderr @@ -19,9 +19,9 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:20:3 | LL | empty(1, 1); - | ^^^^^ - - unexpected argument of type `{integer}` + | ^^^^^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:1:4 @@ -38,7 +38,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:22:3 | LL | one_arg(1, 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -55,7 +55,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:23:3 | LL | one_arg(1, ""); - | ^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^ -- unexpected argument #2 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -72,9 +72,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 | LL | one_arg(1, "", 1.0); - | ^^^^^^^ -- --- unexpected argument of type `{float}` + | ^^^^^^^ -- --- unexpected argument #3 of type `{float}` | | - | unexpected argument of type `&'static str` + | unexpected argument #2 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -91,7 +91,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:26:3 | LL | two_arg_same(1, 1, 1); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -108,7 +108,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:27:3 | LL | two_arg_same(1, 1, 1.0); - | ^^^^^^^^^^^^ --- unexpected argument of type `{float}` + | ^^^^^^^^^^^^ --- unexpected argument #3 of type `{float}` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -125,7 +125,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:29:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -142,7 +142,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:30:3 | LL | two_arg_diff(1, "", ""); - | ^^^^^^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -159,9 +159,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:31:3 | LL | two_arg_diff(1, 1, "", ""); - | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ - -- unexpected argument #4 of type `&'static str` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -178,9 +178,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:32:3 | LL | two_arg_diff(1, "", 1, ""); - | ^^^^^^^^^^^^ - -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ - -- unexpected argument #4 of type `&'static str` | | - | unexpected argument of type `{integer}` + | unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -197,7 +197,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:35:3 | LL | two_arg_same(1, 1, ""); - | ^^^^^^^^^^^^ -- unexpected argument of type `&'static str` + | ^^^^^^^^^^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -214,7 +214,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:36:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -234,7 +234,7 @@ LL | two_arg_same( | ^^^^^^^^^^^^ ... LL | "" - | -- unexpected argument of type `&'static str` + | -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -255,7 +255,7 @@ LL | two_arg_diff( | ^^^^^^^^^^^^ LL | 1, LL | 1, - | - unexpected argument of type `{integer}` + | - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -271,12 +271,12 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:8:9 | LL | empty($x, 1); - | ^^^^^ - unexpected argument of type `{integer}` + | ^^^^^ - unexpected argument #2 of type `{integer}` ... LL | foo!(1, ~); | ---------- | | | - | | unexpected argument of type `{integer}` + | | unexpected argument #1 of type `{integer}` | in this macro invocation | note: function defined here @@ -290,12 +290,12 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/extra_arguments.rs:14:9 | LL | empty(1, $y); - | ^^^^^ - unexpected argument of type `{integer}` + | ^^^^^ - unexpected argument #1 of type `{integer}` ... LL | foo!(~, 1); | ---------- | | | - | | unexpected argument of type `{integer}` + | | unexpected argument #2 of type `{integer}` | in this macro invocation | note: function defined here @@ -314,8 +314,8 @@ LL | empty($x, $y); LL | foo!(1, 1); | ---------- | | | | - | | | unexpected argument of type `{integer}` - | | unexpected argument of type `{integer}` + | | | unexpected argument #2 of type `{integer}` + | | unexpected argument #1 of type `{integer}` | in this macro invocation | note: function defined here @@ -329,7 +329,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:53:3 | LL | one_arg(1, panic!()); - | ^^^^^^^ -------- unexpected argument + | ^^^^^^^ -------- unexpected argument #2 | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -346,7 +346,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:54:3 | LL | one_arg(panic!(), 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -363,7 +363,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:55:3 | LL | one_arg(stringify!($e), 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -380,7 +380,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:60:3 | LL | one_arg(for _ in 1.. {}, 1); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/extra_arguments.rs:2:4 diff --git a/tests/ui/argument-suggestions/issue-100478.stderr b/tests/ui/argument-suggestions/issue-100478.stderr index e4304988f9b..94709f0ebc6 100644 --- a/tests/ui/argument-suggestions/issue-100478.stderr +++ b/tests/ui/argument-suggestions/issue-100478.stderr @@ -4,8 +4,8 @@ error[E0061]: this function takes 3 arguments but 1 argument was supplied LL | three_diff(T2::new(0)); | ^^^^^^^^^^------------ | || - | |an argument of type `T1` is missing - | an argument of type `T3` is missing + | |argument #1 of type `T1` is missing + | argument #3 of type `T3` is missing | note: function defined here --> $DIR/issue-100478.rs:30:4 @@ -63,7 +63,7 @@ LL | foo( | ^^^ ... LL | p3, p4, p5, p6, p7, p8, - | -- an argument of type `Arc<T2>` is missing + | -- argument #2 of type `Arc<T2>` is missing | note: function defined here --> $DIR/issue-100478.rs:29:4 diff --git a/tests/ui/argument-suggestions/issue-101097.stderr b/tests/ui/argument-suggestions/issue-101097.stderr index 061f510144b..6e21f19ab4f 100644 --- a/tests/ui/argument-suggestions/issue-101097.stderr +++ b/tests/ui/argument-suggestions/issue-101097.stderr @@ -4,7 +4,7 @@ error[E0061]: this function takes 6 arguments but 7 arguments were supplied LL | f(C, A, A, A, B, B, C); | ^ - - - - expected `C`, found `B` | | | | - | | | unexpected argument of type `A` + | | | unexpected argument #4 of type `A` | | expected `B`, found `A` | expected `A`, found `C` | @@ -64,8 +64,8 @@ error[E0308]: arguments to this function are incorrect LL | f(A, A, D, D, B, B); | ^ - - ---- two arguments of type `C` and `C` are missing | | | - | | unexpected argument of type `D` - | unexpected argument of type `D` + | | unexpected argument #4 of type `D` + | unexpected argument #3 of type `D` | note: function defined here --> $DIR/issue-101097.rs:6:4 diff --git a/tests/ui/argument-suggestions/issue-109425.stderr b/tests/ui/argument-suggestions/issue-109425.stderr index 1514f1cb487..bfe007793d4 100644 --- a/tests/ui/argument-suggestions/issue-109425.stderr +++ b/tests/ui/argument-suggestions/issue-109425.stderr @@ -2,9 +2,9 @@ error[E0061]: this function takes 0 arguments but 2 arguments were supplied --> $DIR/issue-109425.rs:10:5 | LL | f(0, 1,); // f() - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:3:4 @@ -21,9 +21,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:12:5 | LL | i(0, 1, 2,); // i(0,) - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:4:4 @@ -40,9 +40,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:14:5 | LL | i(0, 1, 2); // i(0) - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:4:4 @@ -59,9 +59,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/issue-109425.rs:16:5 | LL | is(0, 1, 2, ""); // is(0, "") - | ^^ - - unexpected argument of type `{integer}` + | ^^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:5:4 @@ -78,9 +78,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/issue-109425.rs:18:5 | LL | s(0, 1, ""); // s("") - | ^ - - unexpected argument of type `{integer}` + | ^ - - unexpected argument #2 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #1 of type `{integer}` | note: function defined here --> $DIR/issue-109425.rs:6:4 diff --git a/tests/ui/argument-suggestions/issue-109831.stderr b/tests/ui/argument-suggestions/issue-109831.stderr index 7b9a3c9ef2c..12be0887121 100644 --- a/tests/ui/argument-suggestions/issue-109831.stderr +++ b/tests/ui/argument-suggestions/issue-109831.stderr @@ -29,7 +29,7 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/issue-109831.rs:7:5 | LL | f(A, A, B, C); - | ^ - - - unexpected argument + | ^ - - - unexpected argument #4 | | | | | expected `B`, found `A` | expected `B`, found `A` diff --git a/tests/ui/argument-suggestions/issue-112507.stderr b/tests/ui/argument-suggestions/issue-112507.stderr index 17bde4d9743..908ed35c669 100644 --- a/tests/ui/argument-suggestions/issue-112507.stderr +++ b/tests/ui/argument-suggestions/issue-112507.stderr @@ -4,12 +4,12 @@ error[E0061]: this enum variant takes 1 argument but 4 arguments were supplied LL | let _a = Value::Float( | ^^^^^^^^^^^^ LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #1 of type `{integer}` LL | None, LL | None, - | ---- unexpected argument of type `Option<_>` + | ---- unexpected argument #3 of type `Option<_>` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #4 of type `{integer}` | note: tuple variant defined here --> $DIR/issue-112507.rs:2:5 diff --git a/tests/ui/argument-suggestions/issue-96638.stderr b/tests/ui/argument-suggestions/issue-96638.stderr index 887bf82a2f6..6492acbad94 100644 --- a/tests/ui/argument-suggestions/issue-96638.stderr +++ b/tests/ui/argument-suggestions/issue-96638.stderr @@ -4,7 +4,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied LL | f(&x, ""); | ^ -- -- expected `usize`, found `&str` | | - | an argument of type `usize` is missing + | argument #1 of type `usize` is missing | note: function defined here --> $DIR/issue-96638.rs:1:4 diff --git a/tests/ui/argument-suggestions/issue-97484.stderr b/tests/ui/argument-suggestions/issue-97484.stderr index 6bdb734fddf..a7708f6e0d7 100644 --- a/tests/ui/argument-suggestions/issue-97484.stderr +++ b/tests/ui/argument-suggestions/issue-97484.stderr @@ -2,11 +2,11 @@ error[E0061]: this function takes 4 arguments but 7 arguments were supplied --> $DIR/issue-97484.rs:12:5 | LL | foo(&&A, B, C, D, E, F, G); - | ^^^ - - - - unexpected argument of type `F` + | ^^^ - - - - unexpected argument #6 of type `F` | | | | | | | expected `&E`, found `E` - | | unexpected argument of type `C` - | unexpected argument of type `B` + | | unexpected argument #3 of type `C` + | unexpected argument #2 of type `B` | note: function defined here --> $DIR/issue-97484.rs:9:4 diff --git a/tests/ui/argument-suggestions/issue-98894.stderr b/tests/ui/argument-suggestions/issue-98894.stderr index 72e6fec27e6..93e604c3101 100644 --- a/tests/ui/argument-suggestions/issue-98894.stderr +++ b/tests/ui/argument-suggestions/issue-98894.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-98894.rs:2:5 | LL | (|_, ()| ())(if true {} else {return;}); - | ^^^^^^^^^^^^--------------------------- an argument of type `()` is missing + | ^^^^^^^^^^^^--------------------------- argument #2 of type `()` is missing | note: closure defined here --> $DIR/issue-98894.rs:2:6 diff --git a/tests/ui/argument-suggestions/issue-98897.stderr b/tests/ui/argument-suggestions/issue-98897.stderr index eed3964559a..671e3d99d85 100644 --- a/tests/ui/argument-suggestions/issue-98897.stderr +++ b/tests/ui/argument-suggestions/issue-98897.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-98897.rs:2:5 | LL | (|_, ()| ())([return, ()]); - | ^^^^^^^^^^^^-------------- an argument of type `()` is missing + | ^^^^^^^^^^^^-------------- argument #2 of type `()` is missing | note: closure defined here --> $DIR/issue-98897.rs:2:6 diff --git a/tests/ui/argument-suggestions/issue-99482.stderr b/tests/ui/argument-suggestions/issue-99482.stderr index 9c83b47f8b6..be407874615 100644 --- a/tests/ui/argument-suggestions/issue-99482.stderr +++ b/tests/ui/argument-suggestions/issue-99482.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-99482.rs:3:14 | LL | let _f = f(main); - | ^ ---- an argument of type `()` is missing + | ^ ---- argument #1 of type `()` is missing | note: closure defined here --> $DIR/issue-99482.rs:2:13 diff --git a/tests/ui/argument-suggestions/missing_arguments.stderr b/tests/ui/argument-suggestions/missing_arguments.stderr index ba9ece040be..3a27a51d032 100644 --- a/tests/ui/argument-suggestions/missing_arguments.stderr +++ b/tests/ui/argument-suggestions/missing_arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing_arguments.rs:10:3 | LL | one_arg(); - | ^^^^^^^-- an argument of type `i32` is missing + | ^^^^^^^-- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:1:4 @@ -34,7 +34,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:15:3 | LL | two_same( 1 ); - | ^^^^^^^^----------------- an argument of type `i32` is missing + | ^^^^^^^^----------------- argument #2 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:2:4 @@ -66,7 +66,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:17:3 | LL | two_diff( 1 ); - | ^^^^^^^^----------------- an argument of type `f32` is missing + | ^^^^^^^^----------------- argument #2 of type `f32` is missing | note: function defined here --> $DIR/missing_arguments.rs:3:4 @@ -82,7 +82,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:18:3 | LL | two_diff( 1.0 ); - | ^^^^^^^^ --- an argument of type `i32` is missing + | ^^^^^^^^ --- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:3:4 @@ -130,7 +130,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:23:3 | LL | three_same( 1, 1 ); - | ^^^^^^^^^^------------------------- an argument of type `i32` is missing + | ^^^^^^^^^^------------------------- argument #3 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:4:4 @@ -146,7 +146,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:26:3 | LL | three_diff( 1.0, "" ); - | ^^^^^^^^^^ --- an argument of type `i32` is missing + | ^^^^^^^^^^ --- argument #1 of type `i32` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -162,7 +162,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:27:3 | LL | three_diff( 1, "" ); - | ^^^^^^^^^^ -- an argument of type `f32` is missing + | ^^^^^^^^^^ -- argument #2 of type `f32` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -178,7 +178,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:28:3 | LL | three_diff( 1, 1.0 ); - | ^^^^^^^^^^------------------------- an argument of type `&str` is missing + | ^^^^^^^^^^------------------------- argument #3 of type `&str` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 @@ -212,8 +212,8 @@ error[E0061]: this function takes 3 arguments but 1 argument was supplied LL | three_diff( 1.0 ); | ^^^^^^^^^^------------------------- | | | - | | an argument of type `i32` is missing - | an argument of type `&str` is missing + | | argument #1 of type `i32` is missing + | argument #3 of type `&str` is missing | note: function defined here --> $DIR/missing_arguments.rs:5:4 diff --git a/tests/ui/argument-suggestions/mixed_cases.stderr b/tests/ui/argument-suggestions/mixed_cases.stderr index c645dd38179..bec5d4dc16b 100644 --- a/tests/ui/argument-suggestions/mixed_cases.stderr +++ b/tests/ui/argument-suggestions/mixed_cases.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/mixed_cases.rs:10:3 | LL | two_args(1, "", X {}); - | ^^^^^^^^ -- ---- unexpected argument of type `X` + | ^^^^^^^^ -- ---- unexpected argument #3 of type `X` | | | expected `f32`, found `&str` | @@ -21,10 +21,10 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/mixed_cases.rs:11:3 | LL | three_args(1, "", X {}, ""); - | ^^^^^^^^^^ -- ---- -- unexpected argument of type `&'static str` + | ^^^^^^^^^^ -- ---- -- unexpected argument #4 of type `&'static str` | | | - | | unexpected argument of type `X` - | an argument of type `f32` is missing + | | unexpected argument #3 of type `X` + | argument #2 of type `f32` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -43,7 +43,7 @@ LL | three_args(1, X {}); | ^^^^^^^^^^--------- | | | | | expected `f32`, found `X` - | an argument of type `&str` is missing + | argument #3 of type `&str` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -59,9 +59,9 @@ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:17:3 | LL | three_args(1, "", X {}); - | ^^^^^^^^^^ -- ---- unexpected argument of type `X` + | ^^^^^^^^^^ -- ---- unexpected argument #3 of type `X` | | - | an argument of type `f32` is missing + | argument #2 of type `f32` is missing | note: function defined here --> $DIR/mixed_cases.rs:6:4 @@ -98,7 +98,7 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied LL | three_args("", 1); | ^^^^^^^^^^ -- - | | | - | | an argument of type `f32` is missing + | | argument #2 of type `f32` is missing | | expected `&str`, found `{integer}` | expected `i32`, found `&'static str` | diff --git a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr index dc293945eb6..730f20cfb88 100644 --- a/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr +++ b/tests/ui/argument-suggestions/suggest-better-removing-issue-126246.stderr @@ -32,7 +32,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:10:5 | LL | add_one(2, 2); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -49,7 +49,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:11:5 | LL | add_one(no_such_local, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #1 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -66,7 +66,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:13:5 | LL | add_one(10, no_such_local); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #2 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:1:4 @@ -83,7 +83,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:15:5 | LL | add_two(10, no_such_local, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #2 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 @@ -100,7 +100,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:17:5 | LL | add_two(no_such_local, 10, 10); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #1 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 @@ -117,7 +117,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/suggest-better-removing-issue-126246.rs:19:5 | LL | add_two(10, 10, no_such_local); - | ^^^^^^^ ------------- unexpected argument + | ^^^^^^^ ------------- unexpected argument #3 | note: function defined here --> $DIR/suggest-better-removing-issue-126246.rs:5:4 diff --git a/tests/ui/asm/binary_asm_labels.stderr b/tests/ui/asm/binary_asm_labels.stderr index 1f2943084f1..206d2da1779 100644 --- a/tests/ui/asm/binary_asm_labels.stderr +++ b/tests/ui/asm/binary_asm_labels.stderr @@ -4,7 +4,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("0: jmp 0b"); | ^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information = note: `#[deny(binary_asm_labels)]` on by default error: avoid using labels containing only the digits `0` and `1` in inline assembly @@ -13,7 +15,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("1: jmp 1b"); | ^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:13:15 @@ -21,7 +25,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("10: jmp 10b"); | ^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:14:15 @@ -29,7 +35,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("01: jmp 01b"); | ^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:15:15 @@ -37,7 +45,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("1001101: jmp 1001101b"); | ^^^^^^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see <https://github.com/llvm/llvm-project/issues/99547> for more information error: aborting due to 5 previous errors diff --git a/tests/ui/asm/binary_asm_labels_allowed.rs b/tests/ui/asm/binary_asm_labels_allowed.rs new file mode 100644 index 00000000000..a21ab8d70f5 --- /dev/null +++ b/tests/ui/asm/binary_asm_labels_allowed.rs @@ -0,0 +1,17 @@ +//@ build-pass +//@ only-aarch64 + +// The `binary_asm_labels` lint should only be raised on `x86`. Make sure it +// doesn't get raised on other platforms. + +use std::arch::asm; + +fn main() { + unsafe { + asm!("0: bl 0b"); + asm!("1: bl 1b"); + asm!("10: bl 10b"); + asm!("01: bl 01b"); + asm!("1001101: bl 1001101b"); + } +} diff --git a/tests/ui/associated-consts/associated-const-type-parameter-arms.stderr b/tests/ui/associated-consts/associated-const-type-parameter-arms.stderr deleted file mode 100644 index 1ccf9febd4b..00000000000 --- a/tests/ui/associated-consts/associated-const-type-parameter-arms.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0158]: associated consts cannot be referenced in patterns - --> $DIR/associated-const-type-parameter-arms.rs:20:9 - | -LL | A::X => println!("A::X"), - | ^^^^ - -error[E0158]: associated consts cannot be referenced in patterns - --> $DIR/associated-const-type-parameter-arms.rs:22:9 - | -LL | B::X => println!("B::X"), - | ^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/associated-consts/associated-const-type-parameter-arms.rs b/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs index 3f260d84e4c..b5798adc71c 100644 --- a/tests/ui/associated-consts/associated-const-type-parameter-arms.rs +++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs @@ -18,12 +18,18 @@ impl Foo for Def { pub fn test<A: Foo, B: Foo>(arg: EFoo) { match arg { A::X => println!("A::X"), - //~^ error: associated consts cannot be referenced in patterns [E0158] + //~^ error: constant pattern depends on a generic parameter B::X => println!("B::X"), - //~^ error: associated consts cannot be referenced in patterns [E0158] + //~^ error: constant pattern depends on a generic parameter _ => (), } } +pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { + //~^ ERROR constant pattern depends on a generic parameter + let A::X = arg; + //~^ ERROR constant pattern depends on a generic parameter +} + fn main() { } diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr new file mode 100644 index 00000000000..adc8f399207 --- /dev/null +++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr @@ -0,0 +1,27 @@ +error[E0158]: constant pattern depends on a generic parameter + --> $DIR/associated-const-type-parameter-pattern.rs:20:9 + | +LL | A::X => println!("A::X"), + | ^^^^ + +error[E0158]: constant pattern depends on a generic parameter + --> $DIR/associated-const-type-parameter-pattern.rs:22:9 + | +LL | B::X => println!("B::X"), + | ^^^^ + +error[E0158]: constant pattern depends on a generic parameter + --> $DIR/associated-const-type-parameter-pattern.rs:30:9 + | +LL | let A::X = arg; + | ^^^^ + +error[E0158]: constant pattern depends on a generic parameter + --> $DIR/associated-const-type-parameter-pattern.rs:28:48 + | +LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { + | ^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/associated-consts/issue-102335-const.stderr b/tests/ui/associated-consts/issue-102335-const.stderr index dc1631220e2..cf96c8cf8eb 100644 --- a/tests/ui/associated-consts/issue-102335-const.stderr +++ b/tests/ui/associated-consts/issue-102335-const.stderr @@ -6,8 +6,9 @@ LL | type A: S<C<X = 0i32> = 34>; | help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102335-const.rs:4:17 @@ -18,8 +19,9 @@ LL | type A: S<C<X = 0i32> = 34>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<X = 0i32> = 34>; - | ~~~~~~~~~~ +LL - type A: S<C<X = 0i32> = 34>; +LL + type A: S<C = 34>; + | error: aborting due to 2 previous errors diff --git a/tests/ui/associated-inherent-types/issue-109768.stderr b/tests/ui/associated-inherent-types/issue-109768.stderr index e960f4fb5d1..e71551f9e73 100644 --- a/tests/ui/associated-inherent-types/issue-109768.stderr +++ b/tests/ui/associated-inherent-types/issue-109768.stderr @@ -34,7 +34,7 @@ error[E0061]: this struct takes 1 argument but 0 arguments were supplied --> $DIR/issue-109768.rs:10:56 | LL | const WRAPPED_ASSOC_3: Wrapper<Self::AssocType3> = Wrapper(); - | ^^^^^^^-- an argument is missing + | ^^^^^^^-- argument #1 is missing | note: tuple struct defined here --> $DIR/issue-109768.rs:3:8 diff --git a/tests/ui/associated-type-bounds/issue-102335-ty.stderr b/tests/ui/associated-type-bounds/issue-102335-ty.stderr index cd585f7f7d8..259b0ca00e1 100644 --- a/tests/ui/associated-type-bounds/issue-102335-ty.stderr +++ b/tests/ui/associated-type-bounds/issue-102335-ty.stderr @@ -6,8 +6,9 @@ LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint | help: consider removing this associated item binding | -LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint - | ~~~~~~~~~~~ +LL - type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint +LL + type A: S<C = ()>; // Just one erroneous equality constraint + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102335-ty.rs:2:17 @@ -18,8 +19,9 @@ LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint - | ~~~~~~~~~~~ +LL - type A: S<C<i32 = u32> = ()>; // Just one erroneous equality constraint +LL + type A: S<C = ()>; // Just one erroneous equality constraint + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102335-ty.rs:8:17 @@ -29,8 +31,9 @@ LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equal | help: consider removing this associated item binding | -LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints - | ~~~~~~~~~~ +LL - type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints +LL + type A: S<C<X = i32> = ()>; // More than one erroneous equality constraints + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102335-ty.rs:8:17 @@ -41,8 +44,9 @@ LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equal = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints - | ~~~~~~~~~~ +LL - type A: S<C<i32 = u32, X = i32> = ()>; // More than one erroneous equality constraints +LL + type A: S<C<X = i32> = ()>; // More than one erroneous equality constraints + | error: aborting due to 4 previous errors diff --git a/tests/ui/associated-type-bounds/no-gat-position.stderr b/tests/ui/associated-type-bounds/no-gat-position.stderr index 39a2f89f9ac..03dc752c533 100644 --- a/tests/ui/associated-type-bounds/no-gat-position.stderr +++ b/tests/ui/associated-type-bounds/no-gat-position.stderr @@ -6,8 +6,9 @@ LL | fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>; | help: consider removing this associated item constraint | -LL | fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>; - | ~~~~~~~~~~~ +LL - fn next<'a>(&'a mut self) -> Option<Self::Item<'a, As1: Copy>>; +LL + fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index dde7036231e..e9fd8503296 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -13,12 +13,12 @@ error: future cannot be sent between threads safely LL | is_send(foo::<T>()); | ^^^^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }`, which is required by `impl Future<Output = Result<(), ()>>: Send` + = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }`, which is required by `impl Future<Output = Result<(), ()>>: Send` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/basic.rs:13:5 | LL | T::method().await?; - | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>> { <T as Foo>::method() }`, which is not `Send` + | ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }`, which is not `Send` note: required by a bound in `is_send` --> $DIR/basic.rs:17:20 | diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.rs b/tests/ui/associated-type-bounds/return-type-notation/display.rs new file mode 100644 index 00000000000..c5be2ca00ea --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/display.rs @@ -0,0 +1,25 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait {} +fn needs_trait(_: impl Trait) {} + +trait Assoc { + fn method() -> impl Sized; + fn method_with_lt() -> impl Sized; + fn method_with_ty<T>() -> impl Sized; + fn method_with_ct<const N: usize>() -> impl Sized; +} + +fn foo<T: Assoc>(t: T) { + needs_trait(T::method()); + //~^ ERROR the trait bound + needs_trait(T::method_with_lt()); + //~^ ERROR the trait bound + needs_trait(T::method_with_ty()); + //~^ ERROR the trait bound + needs_trait(T::method_with_ct()); + //~^ ERROR the trait bound +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/display.stderr b/tests/ui/associated-type-bounds/return-type-notation/display.stderr new file mode 100644 index 00000000000..4915ec1aa83 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/display.stderr @@ -0,0 +1,78 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/display.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `impl Sized { <T as Assoc>::method(..) }: Trait` is not satisfied + --> $DIR/display.rs:15:17 + | +LL | needs_trait(T::method()); + | ----------- ^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { <T as Assoc>::method(..) }` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized { <T as Assoc>::method_with_lt(..) }: Trait` is not satisfied + --> $DIR/display.rs:17:17 + | +LL | needs_trait(T::method_with_lt()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized { <T as Assoc>::method_with_lt(..) }` + | | + | required by a bound introduced by this call + | +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized: Trait` is not satisfied + --> $DIR/display.rs:19:17 + | +LL | needs_trait(T::method_with_ty()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/display.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error[E0277]: the trait bound `impl Sized: Trait` is not satisfied + --> $DIR/display.rs:21:17 + | +LL | needs_trait(T::method_with_ct()); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Sized` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/display.rs:4:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `needs_trait` + --> $DIR/display.rs:5:24 + | +LL | fn needs_trait(_: impl Trait) {} + | ^^^^^ required by this bound in `needs_trait` + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-types/associated-types-eq-2.stderr b/tests/ui/associated-types/associated-types-eq-2.stderr index 69b1b533450..e5013a35d45 100644 --- a/tests/ui/associated-types/associated-types-eq-2.stderr +++ b/tests/ui/associated-types/associated-types-eq-2.stderr @@ -50,8 +50,9 @@ LL | impl Tr1<A = usize> for usize { | help: consider removing this associated item binding | -LL | impl Tr1<A = usize> for usize { - | ~~~~~~~~~~~ +LL - impl Tr1<A = usize> for usize { +LL + impl Tr1 for usize { + | error[E0046]: not all trait items implemented, missing: `A` --> $DIR/associated-types-eq-2.rs:20:1 @@ -70,8 +71,9 @@ LL | fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {} | help: consider removing this associated item binding | -LL | fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {} - | ~~~~~~~ +LL - fn baz<I: Tr1>(_x: &<I as Tr1<A=Bar>>::A) {} +LL + fn baz<I: Tr1>(_x: &<I as Tr1>::A) {} + | error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied --> $DIR/associated-types-eq-2.rs:40:6 @@ -128,8 +130,9 @@ LL | impl Tr2<i32, t2 = Qux, T3 = usize> for Qux { | help: consider removing this associated item binding | -LL | impl Tr2<i32, t2 = Qux, T3 = usize> for Qux { - | ~~~~~~~~~~ +LL - impl Tr2<i32, t2 = Qux, T3 = usize> for Qux { +LL + impl Tr2<i32, T3 = usize> for Qux { + | error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied --> $DIR/associated-types-eq-2.rs:54:6 @@ -157,8 +160,9 @@ LL | impl Tr2<i32, X = Qux, Y = usize> for Bar { | help: consider removing this associated item binding | -LL | impl Tr2<i32, X = Qux, Y = usize> for Bar { - | ~~~~~~~~~ +LL - impl Tr2<i32, X = Qux, Y = usize> for Bar { +LL + impl Tr2<i32, Y = usize> for Bar { + | error[E0107]: trait takes 3 generic arguments but 2 generic arguments were supplied --> $DIR/associated-types-eq-2.rs:61:6 @@ -228,8 +232,9 @@ LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux { | help: consider removing this associated item binding | -LL | impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux { - | ~~~~~~~ +LL - impl Tr3<n = 42, T2 = Qux, T3 = usize> for Qux { +LL + impl Tr3<T2 = Qux, T3 = usize> for Qux { + | error[E0229]: associated item constraints are not allowed here --> $DIR/associated-types-eq-2.rs:92:10 @@ -239,8 +244,9 @@ LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar { | help: consider removing this associated item binding | -LL | impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar { - | ~~~~~~~~ +LL - impl Tr3<N = u32, T2 = Qux, T3 = usize> for Bar { +LL + impl Tr3<T2 = Qux, T3 = usize> for Bar { + | error[E0107]: trait takes 3 generic arguments but 1 generic argument was supplied --> $DIR/associated-types-eq-2.rs:98:6 @@ -268,8 +274,9 @@ LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { | help: consider removing this associated item binding | -LL | impl Tr3<42, T2 = 42, T3 = usize> for Bar { - | ~~~~~~~~~ +LL - impl Tr3<42, T2 = 42, T3 = usize> for Bar { +LL + impl Tr3<42, T3 = usize> for Bar { + | error[E0107]: trait takes 3 generic arguments but 0 generic arguments were supplied --> $DIR/associated-types-eq-2.rs:106:6 @@ -295,8 +302,9 @@ LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar { | help: consider removing this associated item binding | -LL | impl Tr3<X = 42, Y = Qux, Z = usize> for Bar { - | ~~~~~~~ +LL - impl Tr3<X = 42, Y = Qux, Z = usize> for Bar { +LL + impl Tr3<Y = Qux, Z = usize> for Bar { + | error[E0107]: struct takes 1 generic argument but 0 generic arguments were supplied --> $DIR/associated-types-eq-2.rs:117:13 diff --git a/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr index adde31b4a32..b4012d2a5b9 100644 --- a/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr +++ b/tests/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr @@ -3,11 +3,6 @@ error[E0277]: the trait bound `T: Foo<usize>` is not satisfied | LL | let u: <T as Foo<usize>>::Bar = t.get_bar(); | ^ the trait `Foo<usize>` is not implemented for `T` - | -help: consider further restricting this bound - | -LL | fn f<T:Foo<isize> + Foo<usize>>(t: &T) { - | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs new file mode 100644 index 00000000000..6083cc7d96d --- /dev/null +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.rs @@ -0,0 +1,23 @@ +//@ edition:2021 +// issue: rust-lang/rust#127555 + +pub trait Foo { + fn bar<F>(&mut self, func: F) -> impl std::future::Future<Output = ()> + Send + where + F: FnMut(); +} + +struct Baz {} + +impl Foo for Baz { + async fn bar<F>(&mut self, _func: F) -> () + //~^ ERROR `F` cannot be sent between threads safely + where + F: FnMut() + Send, + //~^ ERROR impl has stricter requirements than trait + { + () + } +} + +fn main() {} diff --git a/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr new file mode 100644 index 00000000000..7f3cd2a5900 --- /dev/null +++ b/tests/ui/associated-types/remove-invalid-type-bound-suggest-issue-127555.stderr @@ -0,0 +1,33 @@ +error[E0277]: `F` cannot be sent between threads safely + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:13:5 + | +LL | / async fn bar<F>(&mut self, _func: F) -> () +LL | | +LL | | where +LL | | F: FnMut() + Send, + | |__________________________^ `F` cannot be sent between threads safely + | +note: required by a bound in `<Baz as Foo>::bar` + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 + | +LL | async fn bar<F>(&mut self, _func: F) -> () + | --- required by a bound in this associated function +... +LL | F: FnMut() + Send, + | ^^^^ required by this bound in `<Baz as Foo>::bar` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/remove-invalid-type-bound-suggest-issue-127555.rs:16:22 + | +LL | / fn bar<F>(&mut self, func: F) -> impl std::future::Future<Output = ()> + Send +LL | | where +LL | | F: FnMut(); + | |___________________- definition of `bar` from trait +... +LL | F: FnMut() + Send, + | ^^^^ impl has extra requirement `F: Send` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr index 66819d1fcf7..80dc5fdc747 100644 --- a/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr +++ b/tests/ui/async-await/in-trait/unconstrained-impl-region.stderr @@ -9,10 +9,6 @@ note: required by a bound in `<() as Actor>::on_mount` | LL | async fn on_mount(self, _: impl Inbox<&'a ()>) {} | ^^^^^^^^^^^^^ required by this bound in `<() as Actor>::on_mount` -help: consider further restricting this bound - | -LL | async fn on_mount(self, _: impl Inbox<&'a ()> + Inbox<&'a ()>) {} - | +++++++++++++++ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained-impl-region.rs:13:6 diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr index 23ede089b5a..acad8bd3791 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr @@ -18,8 +18,8 @@ LL | | } LL | | }); | |______^ implementation of `Send` is not general enough | - = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2` + = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>(..) }`, for some specific lifetime `'2` error: implementation of `Send` is not general enough --> $DIR/issue-110963-early.rs:14:5 @@ -32,8 +32,8 @@ LL | | } LL | | }); | |______^ implementation of `Send` is not general enough | - = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>() }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>() }`, for some specific lifetime `'2` + = note: `Send` would have to be implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... + = note: ...but `Send` is actually implemented for the type `impl Future<Output = bool> { <HC as HealthCheck>::check<'2>(..) }`, for some specific lifetime `'2` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr index b23dbc37a55..e061587f491 100644 --- a/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-in-impl-signature.stderr @@ -15,8 +15,9 @@ LL | impl Super1<'_, bar(..): Send> for () {} | help: consider removing this associated item constraint | -LL | impl Super1<'_, bar(..): Send> for () {} - | ~~~~~~~~~~~~~~~ +LL - impl Super1<'_, bar(..): Send> for () {} +LL + impl Super1<'_> for () {} + | error[E0046]: not all trait items implemented, missing: `bar` --> $DIR/rtn-in-impl-signature.rs:10:1 diff --git a/tests/ui/blind/blind-item-block-item-shadow.stderr b/tests/ui/blind/blind-item-block-item-shadow.stderr index 2e24ef453c2..38e3087ca34 100644 --- a/tests/ui/blind/blind-item-block-item-shadow.stderr +++ b/tests/ui/blind/blind-item-block-item-shadow.stderr @@ -10,7 +10,7 @@ LL | use foo::Bar; help: you can use `as` to change the binding name of the import | LL | use foo::Bar as OtherBar; - | ~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/blind/blind-item-item-shadow.stderr b/tests/ui/blind/blind-item-item-shadow.stderr index 84b273c7338..08f5f5b47ed 100644 --- a/tests/ui/blind/blind-item-item-shadow.stderr +++ b/tests/ui/blind/blind-item-item-shadow.stderr @@ -11,7 +11,7 @@ LL | use foo::foo; help: you can use `as` to change the binding name of the import | LL | use foo::foo as other_foo; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index 11e2b63bd6c..36e259fa6e8 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -11,7 +11,7 @@ LL | let _y2 = &mut static_x_mut; help: use `addr_of_mut!` instead to create a raw pointer | LL | let _y2 = addr_of_mut!(static_x_mut); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-access-permissions.rs:10:19 diff --git a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr index 354d70eb1ad..a727c9414c5 100644 --- a/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr +++ b/tests/ui/borrowck/borrowck-unsafe-static-mutable-borrows.stderr @@ -11,7 +11,7 @@ LL | let sfoo: *mut Foo = &mut SFOO; help: use `addr_of_mut!` instead to create a raw pointer | LL | let sfoo: *mut Foo = addr_of_mut!(SFOO); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs new file mode 100644 index 00000000000..2de43f63487 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.rs @@ -0,0 +1,68 @@ +fn s() -> String { + let a = String::new(); + dbg!(a); + return a; //~ ERROR use of moved value: +} + +fn m() -> String { + let a = String::new(); + dbg!(1, 2, a, 1, 2); + return a; //~ ERROR use of moved value: +} + +fn t(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return b; //~ ERROR use of moved value: +} + +fn x(a: String) -> String { + let b: String = "".to_string(); + dbg!(a, b); + return a; //~ ERROR use of moved value: +} + +macro_rules! my_dbg { + () => { + eprintln!("[{}:{}:{}]", file!(), line!(), column!()) + }; + ($val:expr $(,)?) => { + match $val { + tmp => { + eprintln!("[{}:{}:{}] {} = {:#?}", + file!(), line!(), column!(), stringify!($val), &tmp); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($(my_dbg!($val)),+,) + }; +} + +fn test_my_dbg() -> String { + let b: String = "".to_string(); + my_dbg!(b, 1); + return b; //~ ERROR use of moved value: +} + +fn test_not_macro() -> String { + let a = String::new(); + let _b = match a { + tmp => { + eprintln!("dbg: {}", tmp); + tmp + } + }; + return a; //~ ERROR use of moved value: +} + +fn get_expr(_s: String) {} + +fn test() { + let a: String = "".to_string(); + let _res = get_expr(dbg!(a)); + let _l = a.len(); //~ ERROR borrow of moved value +} + +fn main() {} diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr new file mode 100644 index 00000000000..efacc0c3f13 --- /dev/null +++ b/tests/ui/borrowck/dbg-issue-120327.stderr @@ -0,0 +1,117 @@ +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:4:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a); + | ------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:10:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | dbg!(1, 2, a, 1, 2); + | ------------------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(1, 2, &a, 1, 2); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:16:12 + | +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | dbg!(a, b); + | ---------- value moved here +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(a, &b); + | + + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:22:12 + | +LL | fn x(a: String) -> String { + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let b: String = "".to_string(); +LL | dbg!(a, b); + | ---------- value moved here +LL | return a; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | dbg!(&a, b); + | + + +error[E0382]: use of moved value: `b` + --> $DIR/dbg-issue-120327.rs:46:12 + | +LL | tmp => { + | --- value moved here +... +LL | let b: String = "".to_string(); + | - move occurs because `b` has type `String`, which does not implement the `Copy` trait +LL | my_dbg!(b, 1); +LL | return b; + | ^ value used here after move + | +help: consider borrowing instead of transferring ownership + | +LL | my_dbg!(&b, 1); + | + +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: use of moved value: `a` + --> $DIR/dbg-issue-120327.rs:57:12 + | +LL | let a = String::new(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _b = match a { +LL | tmp => { + | --- value moved here +... +LL | return a; + | ^ value used here after move + | +help: borrow this binding in the pattern to avoid moving the value + | +LL | ref tmp => { + | +++ + +error[E0382]: borrow of moved value: `a` + --> $DIR/dbg-issue-120327.rs:65:14 + | +LL | let a: String = "".to_string(); + | - move occurs because `a` has type `String`, which does not implement the `Copy` trait +LL | let _res = get_expr(dbg!(a)); + | ------- value moved here +LL | let _l = a.len(); + | ^ value borrowed here after move + | +help: consider borrowing instead of transferring ownership + | +LL | let _res = get_expr(dbg!(&a)); + | + + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/issue-20801.stderr b/tests/ui/borrowck/issue-20801.stderr index c1d06ac3e21..769b34831c1 100644 --- a/tests/ui/borrowck/issue-20801.stderr +++ b/tests/ui/borrowck/issue-20801.stderr @@ -11,7 +11,7 @@ LL | unsafe { &mut GLOBAL_MUT_T } help: use `addr_of_mut!` instead to create a raw pointer | LL | unsafe { addr_of_mut!(GLOBAL_MUT_T) } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error[E0507]: cannot move out of a mutable reference --> $DIR/issue-20801.rs:27:22 diff --git a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr index ff5ec1db346..72fd0d8ce16 100644 --- a/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr +++ b/tests/ui/borrowck/issue-55492-borrowck-migrate-scans-parents.stderr @@ -11,7 +11,7 @@ LL | c1(&mut Y); help: use `addr_of_mut!` instead to create a raw pointer | LL | c1(addr_of_mut!(Y)); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: creating a mutable reference to mutable static is discouraged --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:27:16 @@ -25,7 +25,7 @@ LL | c1(&mut Z); help: use `addr_of_mut!` instead to create a raw pointer | LL | c1(addr_of_mut!(Z)); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: creating a mutable reference to mutable static is discouraged --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:64:37 @@ -39,7 +39,7 @@ LL | borrowck_closures_unique::e(&mut X); help: use `addr_of_mut!` instead to create a raw pointer | LL | borrowck_closures_unique::e(addr_of_mut!(X)); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error[E0594]: cannot assign to `x`, as it is not declared as mutable --> $DIR/issue-55492-borrowck-migrate-scans-parents.rs:9:46 diff --git a/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.fixed b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.fixed new file mode 100644 index 00000000000..cec52272fee --- /dev/null +++ b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.fixed @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![allow(dead_code)] + +struct X(u32); + +impl X { + fn f(&mut self) { + generic(&mut *self); + self.0 += 1; + //~^ ERROR: use of moved value: `self` [E0382] + } +} + +fn generic<T>(_x: T) {} + +fn main() {} diff --git a/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.rs b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.rs new file mode 100644 index 00000000000..dd015697fdc --- /dev/null +++ b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.rs @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![allow(dead_code)] + +struct X(u32); + +impl X { + fn f(&mut self) { + generic(self); + self.0 += 1; + //~^ ERROR: use of moved value: `self` [E0382] + } +} + +fn generic<T>(_x: T) {} + +fn main() {} diff --git a/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.stderr b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.stderr new file mode 100644 index 00000000000..3da8b6e9dff --- /dev/null +++ b/tests/ui/borrowck/moved-value-suggest-reborrow-issue-127285.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of moved value: `self` + --> $DIR/moved-value-suggest-reborrow-issue-127285.rs:10:9 + | +LL | fn f(&mut self) { + | --------- move occurs because `self` has type `&mut X`, which does not implement the `Copy` trait +LL | generic(self); + | ---- value moved here +LL | self.0 += 1; + | ^^^^^^^^^^^ value used here after move + | +help: consider creating a fresh reborrow of `self` here + | +LL | generic(&mut *self); + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/mut-borrow-in-loop-2.stderr b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr index 7a569d1da41..4f32df1eb24 100644 --- a/tests/ui/borrowck/mut-borrow-in-loop-2.stderr +++ b/tests/ui/borrowck/mut-borrow-in-loop-2.stderr @@ -8,19 +8,10 @@ LL | for _ in 0..3 { LL | Other::handle(value); | ^^^^^ value moved here, in previous iteration of loop | -note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary - --> $DIR/mut-borrow-in-loop-2.rs:8:22 - | -LL | fn handle(value: T) -> Self; - | ------ ^ this parameter takes ownership of the value - | | - | in this function -help: consider moving the expression out of the loop so it is only moved once - | -LL ~ let mut value = Other::handle(value); -LL ~ for _ in 0..3 { -LL ~ value; +help: consider creating a fresh reborrow of `value` here | +LL | Other::handle(&mut *value); + | ++++++ help: consider creating a fresh reborrow of `value` here | LL | Other::handle(&mut *value); diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index 4beea83d8a5..72d60a1439a 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr @@ -24,7 +24,7 @@ error[E0060]: this function takes at least 2 arguments but 1 argument was suppli --> $DIR/variadic-ffi-1.rs:23:9 | LL | foo(1); - | ^^^--- an argument of type `u8` is missing + | ^^^--- argument #2 of type `u8` is missing | note: function defined here --> $DIR/variadic-ffi-1.rs:15:8 diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.stderr b/tests/ui/cast/ice-cast-type-with-error-124848.stderr index 2d86bf76d11..1e2adcc7d9e 100644 --- a/tests/ui/cast/ice-cast-type-with-error-124848.stderr +++ b/tests/ui/cast/ice-cast-type-with-error-124848.stderr @@ -39,7 +39,7 @@ error[E0061]: this struct takes 2 arguments but 1 argument was supplied --> $DIR/ice-cast-type-with-error-124848.rs:12:24 | LL | let mut unpinned = MyType(Cell::new(None)); - | ^^^^^^----------------- an argument is missing + | ^^^^^^----------------- argument #2 is missing | note: tuple struct defined here --> $DIR/ice-cast-type-with-error-124848.rs:7:8 diff --git a/tests/ui/cfg/diagnostics-cross-crate.rs b/tests/ui/cfg/diagnostics-cross-crate.rs index 77dd91d6c28..00ac7e2fd08 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.rs +++ b/tests/ui/cfg/diagnostics-cross-crate.rs @@ -11,12 +11,14 @@ fn main() { cfged_out::inner::uwu(); //~ ERROR cannot find function //~^ NOTE found an item that was configured out //~| NOTE not found in `cfged_out::inner` + //~| NOTE the item is gated here // The module isn't found - we would like to get a diagnostic, but currently don't due to // the awkward way the resolver diagnostics are currently implemented. cfged_out::inner::doesnt_exist::hello(); //~ ERROR failed to resolve //~^ NOTE could not find `doesnt_exist` in `inner` //~| NOTE found an item that was configured out + //~| NOTE the item is gated here // It should find the one in the right module, not the wrong one. cfged_out::inner::right::meow(); //~ ERROR cannot find function @@ -28,4 +30,5 @@ fn main() { cfged_out::vanished(); //~ ERROR cannot find function //~^ NOTE found an item that was configured out //~| NOTE not found in `cfged_out` + //~| NOTE the item is gated here } diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr index 8a238f36404..07ad4e3272d 100644 --- a/tests/ui/cfg/diagnostics-cross-crate.stderr +++ b/tests/ui/cfg/diagnostics-cross-crate.stderr @@ -1,5 +1,5 @@ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` - --> $DIR/diagnostics-cross-crate.rs:17:23 + --> $DIR/diagnostics-cross-crate.rs:18:23 | LL | cfged_out::inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` @@ -9,6 +9,11 @@ note: found an item that was configured out | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:5:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in crate `cfged_out` --> $DIR/diagnostics-cross-crate.rs:7:16 @@ -27,9 +32,14 @@ note: found an item that was configured out | LL | pub fn uwu() {} | ^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:2:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `cfged_out::inner::right` - --> $DIR/diagnostics-cross-crate.rs:22:30 + --> $DIR/diagnostics-cross-crate.rs:24:30 | LL | cfged_out::inner::right::meow(); | ^^^^ not found in `cfged_out::inner::right` @@ -39,10 +49,14 @@ note: found an item that was configured out | LL | pub fn meow() {} | ^^^^ - = note: the item is gated behind the `what-a-cool-feature` feature +note: the item is gated behind the `what-a-cool-feature` feature + --> $DIR/auxiliary/cfged_out.rs:16:15 + | +LL | #[cfg(feature = "what-a-cool-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `vanished` in crate `cfged_out` - --> $DIR/diagnostics-cross-crate.rs:28:16 + --> $DIR/diagnostics-cross-crate.rs:30:16 | LL | cfged_out::vanished(); | ^^^^^^^^ not found in `cfged_out` @@ -52,6 +66,11 @@ note: found an item that was configured out | LL | pub fn vanished() {} | ^^^^^^^^ +note: the item is gated here + --> $DIR/auxiliary/cfged_out.rs:21:1 + | +LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index 9b3208cb87c..9ae7d931fcb 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -4,7 +4,7 @@ pub mod inner { pub fn uwu() {} } - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub use super::uwu; //~^ NOTE found an item that was configured out } @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr index e25b7cf86e2..737202fdf9a 100644 --- a/tests/ui/cfg/diagnostics-reexport.stderr +++ b/tests/ui/cfg/diagnostics-reexport.stderr @@ -9,6 +9,11 @@ note: found an item that was configured out | LL | pub fn x() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:17:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0432]: unresolved imports `b::x`, `b::y` --> $DIR/diagnostics-reexport.rs:22:13 @@ -23,11 +28,21 @@ note: found an item that was configured out | LL | pub fn x() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:28:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ note: found an item that was configured out --> $DIR/diagnostics-reexport.rs:32:12 | LL | pub fn y() {} | ^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:31:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` --> $DIR/diagnostics-reexport.rs:38:12 @@ -40,6 +55,11 @@ note: found an item that was configured out | LL | pub use super::uwu; | ^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport.rs:7:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs index b2a0fb58dd6..d6f8dd21a92 100644 --- a/tests/ui/cfg/diagnostics-same-crate.rs +++ b/tests/ui/cfg/diagnostics-same-crate.rs @@ -1,11 +1,13 @@ #![allow(unexpected_cfgs)] // since we want to recognize them as unexpected pub mod inner { - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here pub fn uwu() {} //~^ NOTE found an item that was configured out - #[cfg(FALSE)] + #[cfg(FALSE)] //~ NOTE the item is gated here + //~^ NOTE the item is gated here + //~| NOTE the item is gated here pub mod doesnt_exist { //~^ NOTE found an item that was configured out //~| NOTE found an item that was configured out @@ -20,7 +22,7 @@ pub mod inner { } pub mod right { - #[cfg(feature = "what-a-cool-feature")] + #[cfg(feature = "what-a-cool-feature")] //~ NOTE the item is gated behind the `what-a-cool-feature` feature pub fn meow() {} //~^ NOTE found an item that was configured out } @@ -55,7 +57,6 @@ fn main() { // It should find the one in the right module, not the wrong one. inner::right::meow(); //~ ERROR cannot find function //~| NOTE not found in `inner::right - //~| NOTE the item is gated behind the `what-a-cool-feature` feature // Exists in the crate root - we would generally want a diagnostic, // but currently don't have one. diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 86421736b8c..dd0d10c6567 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -1,41 +1,56 @@ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:30:9 + --> $DIR/diagnostics-same-crate.rs:32:9 | LL | use super::inner::doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0432]: unresolved import `super::inner::doesnt_exist` - --> $DIR/diagnostics-same-crate.rs:33:23 + --> $DIR/diagnostics-same-crate.rs:35:23 | LL | use super::inner::doesnt_exist::hi; | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner` - --> $DIR/diagnostics-same-crate.rs:52:12 + --> $DIR/diagnostics-same-crate.rs:54:12 | LL | inner::doesnt_exist::hello(); | ^^^^^^^^^^^^ could not find `doesnt_exist` in `inner` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:9:13 + --> $DIR/diagnostics-same-crate.rs:11:13 | LL | pub mod doesnt_exist { | ^^^^^^^^^^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:8:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in module `inner` - --> $DIR/diagnostics-same-crate.rs:47:12 + --> $DIR/diagnostics-same-crate.rs:49:12 | LL | inner::uwu(); | ^^^ not found in `inner` @@ -45,28 +60,37 @@ note: found an item that was configured out | LL | pub fn uwu() {} | ^^^ +note: the item is gated here + --> $DIR/diagnostics-same-crate.rs:4:5 + | +LL | #[cfg(FALSE)] + | ^^^^^^^^^^^^^ error[E0425]: cannot find function `meow` in module `inner::right` - --> $DIR/diagnostics-same-crate.rs:56:19 + --> $DIR/diagnostics-same-crate.rs:58:19 | LL | inner::right::meow(); | ^^^^ not found in `inner::right` | note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:24:16 + --> $DIR/diagnostics-same-crate.rs:26:16 | LL | pub fn meow() {} | ^^^^ - = note: the item is gated behind the `what-a-cool-feature` feature +note: the item is gated behind the `what-a-cool-feature` feature + --> $DIR/diagnostics-same-crate.rs:25:15 + | +LL | #[cfg(feature = "what-a-cool-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `uwu` in this scope - --> $DIR/diagnostics-same-crate.rs:43:5 + --> $DIR/diagnostics-same-crate.rs:45:5 | LL | uwu(); | ^^^ not found in this scope error[E0425]: cannot find function `vanished` in this scope - --> $DIR/diagnostics-same-crate.rs:63:5 + --> $DIR/diagnostics-same-crate.rs:64:5 | LL | vanished(); | ^^^^^^^^ not found in this scope diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs new file mode 100644 index 00000000000..e6b0bf3e686 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs @@ -0,0 +1,21 @@ +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(C)] +struct Wrapper<T>(T); + +struct Test<T: Copy> { + f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, //~ ERROR cannot find type `U` in this scope + //~^ ERROR function pointer types may not have generic parameters + f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, + //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters + f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] + f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798] +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr new file mode 100644 index 00000000000..fa68d95218c --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -0,0 +1,47 @@ +error: function pointer types may not have generic parameters + --> $DIR/generics.rs:15:42 + | +LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, + | ^^^^^^^^^ + +error[E0412]: cannot find type `U` in this scope + --> $DIR/generics.rs:15:52 + | +LL | struct Test<T: Copy> { + | - similarly named type parameter `T` defined here +LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, + | ^ + | +help: a type parameter with a similar name exists + | +LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(T, u32, u32, u32) -> u64, + | ~ +help: you might be missing a type parameter + | +LL | struct Test<T: Copy, U> { + | +++ + +error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters + --> $DIR/generics.rs:17:43 + | +LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64, + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type + --> $DIR/generics.rs:19:9 + | +LL | f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type + --> $DIR/generics.rs:20:9 + | +LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0412, E0562, E0798. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs deleted file mode 100644 index 364d0858afb..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ build-pass -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] -#![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute<T, U>(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32) -> u32 { - let non_secure_function = unsafe { - transmute::<usize, extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32>( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d) -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs deleted file mode 100644 index c225a26c065..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ build-fail -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] -#![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute<T, U>(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { - let non_secure_function = unsafe { - transmute::< - usize, - extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32> - ( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d, e) -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr deleted file mode 100644 index a8aced2483e..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: <unknown>:0:0: in function test i32 (i32, i32, i32, i32, i32): call to non-secure function would require passing arguments on stack - -error: aborting due to 1 previous error - diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs new file mode 100644 index 00000000000..083a563bd7b --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs @@ -0,0 +1,23 @@ +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(C, align(16))] +#[allow(unused)] +pub struct AlignRelevant(u32); + +#[no_mangle] +pub fn test( + f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), //~ ERROR [E0798] + f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798] + f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), //~ ERROR [E0798] + f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), //~ ERROR [E0798] + f5: extern "C-cmse-nonsecure-call" fn([u32; 5]), //~ ERROR [E0798] +) { +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr new file mode 100644 index 00000000000..a5f5e1c3151 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -0,0 +1,43 @@ +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:17:63 + | +LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), + | ^^^^^^^^^^^^^^ these arguments don't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:18:63 + | +LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), + | ^^^ this argument doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:19:53 + | +LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), + | ^^^ this argument doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:20:58 + | +LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), + | ^^^ this argument doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:21:43 + | +LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]), + | ^^^^^^^^ this argument doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0798`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs new file mode 100644 index 00000000000..e6af1d60e77 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -0,0 +1,54 @@ +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(C)] +pub struct ReprCU64(u64); + +#[repr(C)] +pub struct ReprCBytes(u8, u8, u8, u8, u8); + +#[repr(C)] +pub struct U64Compound(u32, u32); + +#[repr(C, align(16))] +pub struct ReprCAlign16(u16); + +#[no_mangle] +pub fn test( + f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798] + f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798] + f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798] + f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798] + f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798] +) { +} + +#[allow(improper_ctypes_definitions)] +struct Test { + u128: extern "C-cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798] + i128: extern "C-cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798] +} + +#[repr(C)] +pub union ReprCUnionU64 { + _unused: u64, +} + +#[repr(Rust)] +pub union ReprRustUnionU64 { + _unused: u64, +} + +#[no_mangle] +pub fn test_union( + f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798] + f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798] +) { +} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr new file mode 100644 index 00000000000..89f7f159d6e --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -0,0 +1,84 @@ +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:35:50 + | +LL | u128: extern "C-cmse-nonsecure-call" fn() -> u128, + | ^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:36:50 + | +LL | i128: extern "C-cmse-nonsecure-call" fn() -> i128, + | ^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:25:48 + | +LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, + | ^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:26:48 + | +LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, + | ^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:27:48 + | +LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, + | ^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:28:48 + | +LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, + | ^^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:29:48 + | +LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], + | ^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:51:48 + | +LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, + | ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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 `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:52:48 + | +LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, + | ^^^^^^^^^^^^^ this type doesn't fit in the available registers + | + = note: functions with the `"C-cmse-nonsecure-call"` 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: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0798`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs new file mode 100644 index 00000000000..9fda55c2a48 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -0,0 +1,53 @@ +//@ build-pass +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(transparent)] +pub struct ReprTransparentStruct<T> { + _marker1: (), + _marker2: (), + field: T, + _marker3: (), +} + +#[repr(transparent)] +pub enum ReprTransparentEnumU64 { + A(u64), +} + +#[repr(C)] +pub struct U32Compound(u16, u16); + +#[no_mangle] +#[allow(improper_ctypes_definitions)] +pub fn params( + f1: extern "C-cmse-nonsecure-call" fn(), + f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32), + f3: extern "C-cmse-nonsecure-call" fn(u64, u64), + f4: extern "C-cmse-nonsecure-call" fn(u128), + f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32), + f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStruct<u64>, U32Compound), + f7: extern "C-cmse-nonsecure-call" fn([u32; 4]), +) { +} + +#[no_mangle] +pub fn returns( + f1: extern "C-cmse-nonsecure-call" fn() -> u32, + f2: extern "C-cmse-nonsecure-call" fn() -> u64, + f3: extern "C-cmse-nonsecure-call" fn() -> i64, + f4: extern "C-cmse-nonsecure-call" fn() -> f64, + f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4], + f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<u64>, + f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<ReprTransparentStruct<u64>>, + f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, + f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound, +) { +} diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs index fa0b0fdc136..e07fa78463c 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.rs @@ -5,9 +5,7 @@ #![feature(with_negative_coherence)] trait Trait {} impl<const N: u8> Trait for [(); N] {} -//~^ ERROR: mismatched types impl<const N: i8> Trait for [(); N] {} -//~^ ERROR: mismatched types -//~| ERROR: conflicting implementations of trait `Trait` +//~^ ERROR: conflicting implementations of trait `Trait` fn main() {} diff --git a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr index d65450845bc..2087be8e711 100644 --- a/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr +++ b/tests/ui/coherence/negative-coherence/generic_const_type_mismatch.stderr @@ -1,25 +1,11 @@ error[E0119]: conflicting implementations of trait `Trait` for type `[(); _]` - --> $DIR/generic_const_type_mismatch.rs:9:1 + --> $DIR/generic_const_type_mismatch.rs:8:1 | LL | impl<const N: u8> Trait for [(); N] {} | ----------------------------------- first implementation here -LL | LL | impl<const N: i8> Trait for [(); N] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); _]` -error[E0308]: mismatched types - --> $DIR/generic_const_type_mismatch.rs:7:34 - | -LL | impl<const N: u8> Trait for [(); N] {} - | ^ expected `usize`, found `u8` - -error[E0308]: mismatched types - --> $DIR/generic_const_type_mismatch.rs:9:34 - | -LL | impl<const N: i8> Trait for [(); N] {} - | ^ expected `usize`, found `i8` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/const-generics/bad-subst-const-kind.rs b/tests/ui/const-generics/bad-subst-const-kind.rs index d5913879191..cc2ff9b8dea 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.rs +++ b/tests/ui/const-generics/bad-subst-const-kind.rs @@ -6,7 +6,7 @@ trait Q { } impl<const N: u64> Q for [u8; N] { - //~^ ERROR mismatched types + //~^ ERROR: the constant `N` is not of type `usize` const ASSOC: usize = 1; } diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr index 6725f6762e4..5c8d9c90363 100644 --- a/tests/ui/const-generics/bad-subst-const-kind.stderr +++ b/tests/ui/const-generics/bad-subst-const-kind.stderr @@ -1,3 +1,9 @@ +error: the constant `N` is not of type `usize` + --> $DIR/bad-subst-const-kind.rs:8:26 + | +LL | impl<const N: u64> Q for [u8; N] { + | ^^^^^^^ expected `usize`, found `u64` + error: the constant `13` is not of type `u64` --> $DIR/bad-subst-const-kind.rs:13:24 | @@ -12,12 +18,5 @@ LL | impl<const N: u64> Q for [u8; N] { | | | unsatisfied trait bound introduced here -error[E0308]: mismatched types - --> $DIR/bad-subst-const-kind.rs:8:31 - | -LL | impl<const N: u64> Q for [u8; N] { - | ^ expected `usize`, found `u64` - error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs index 6b0d9e047db..8e5e23b2337 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.rs @@ -7,7 +7,7 @@ trait Q { impl<const N: u64> Q for [u8; N] {} //~^ ERROR not all trait items implemented -//~| ERROR mismatched types +//~| ERROR the constant `N` is not of type `usize` pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} //~^ ERROR the constant `13` is not of type `u64` diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr index bb6d650b7ab..e03580ec007 100644 --- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr +++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr @@ -1,3 +1,9 @@ +error: the constant `N` is not of type `usize` + --> $DIR/type_mismatch.rs:8:26 + | +LL | impl<const N: u64> Q for [u8; N] {} + | ^^^^^^^ expected `usize`, found `u64` + error[E0046]: not all trait items implemented, missing: `ASSOC` --> $DIR/type_mismatch.rs:8:1 | @@ -29,12 +35,6 @@ LL | pub fn q_user() -> [u8; <[u8; 13] as Q>::ASSOC] {} | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:8:31 - | -LL | impl<const N: u64> Q for [u8; N] {} - | ^ expected `usize`, found `u64` - error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0308. diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs index 51cae20df84..8b7ee577569 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.rs @@ -25,8 +25,8 @@ mod v20 { } impl<const v10: usize> v17<v10, v2> { - //~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} - //~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} + //~^ ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} + //~| ERROR maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} pub const fn v21() -> v18 { //~^ ERROR cannot find type `v18` in this scope v18 { _p: () } diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index 39f022fbee9..15d3c472585 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -72,13 +72,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} +error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl<const v10: usize> v17<v10, v2> { | ^^ -error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#1} +error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} --> $DIR/unevaluated-const-ice-119731.rs:27:37 | LL | impl<const v10: usize> v17<v10, v2> { diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index c17a7d5d9fa..b5eec3046fd 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -1,26 +1,32 @@ -error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated` - --> $DIR/issue-88119.rs:21:5 +error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}` + --> $DIR/issue-88119.rs:19:49 | -LL | [(); name_len::<T>()]:, - | ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated` +LL | impl<T: ?Sized + ConstName> const ConstName for &T + | ^^ cannot normalize `<&T as ConstName>::{constant#0}` | -note: required by a bound in `<&T as ConstName>` - --> $DIR/issue-88119.rs:21:10 +note: required for `&T` to implement `ConstName` + --> $DIR/issue-88119.rs:19:35 | +LL | impl<T: ?Sized + ConstName> const ConstName for &T + | ^^^^^^^^^ ^^ +LL | where LL | [(); name_len::<T>()]:, - | ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` + | --------------------- unsatisfied trait bound introduced here -error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated` - --> $DIR/issue-88119.rs:28:5 +error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}` + --> $DIR/issue-88119.rs:26:49 | -LL | [(); name_len::<T>()]:, - | ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated` +LL | impl<T: ?Sized + ConstName> const ConstName for &mut T + | ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}` | -note: required by a bound in `<&mut T as ConstName>` - --> $DIR/issue-88119.rs:28:10 +note: required for `&mut T` to implement `ConstName` + --> $DIR/issue-88119.rs:26:35 | +LL | impl<T: ?Sized + ConstName> const ConstName for &mut T + | ^^^^^^^^^ ^^^^^^ +LL | where LL | [(); name_len::<T>()]:, - | ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` + | --------------------- unsatisfied trait bound introduced here error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs index e7ae2ea1d5a..def4611f94b 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs @@ -19,6 +19,8 @@ fn bar<const N: usize>() {} fn foo<const N: usize>() { bar::<{ [1; N] }>(); //~^ ERROR: generic parameters may not be used in const operations + bar::<{ [1; { N + 1 }] }>(); + //~^ ERROR: generic parameters may not be used in const operations } fn main() {} diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr index 72a6e6977f5..ead6c621d60 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr @@ -7,5 +7,14 @@ LL | bar::<{ [1; N] }>(); = help: const parameters may only be used as standalone arguments, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error: aborting due to 1 previous error +error: generic parameters may not be used in const operations + --> $DIR/repeat_expr_hack_gives_right_generics.rs:22:19 + | +LL | bar::<{ [1; { N + 1 }] }>(); + | ^ cannot perform const operation using `N` + | + = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/transmute-fail.rs b/tests/ui/const-generics/transmute-fail.rs index 90afd232534..59b77c678e8 100644 --- a/tests/ui/const-generics/transmute-fail.rs +++ b/tests/ui/const-generics/transmute-fail.rs @@ -10,11 +10,10 @@ fn foo<const W: usize, const H: usize>(v: [[u32;H+1]; W]) -> [[u32; W+1]; H] { } fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { - //~^ ERROR mismatched types - //~| ERROR mismatched types + //~^ ERROR the constant `W` is not of type `usize` unsafe { std::mem::transmute(v) - //~^ ERROR cannot transmute between types + //~^ ERROR the constant `W` is not of type `usize` } } diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index b76ec10bd3f..b40fb23c331 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -1,3 +1,9 @@ +error: the constant `W` is not of type `usize` + --> $DIR/transmute-fail.rs:12:42 + | +LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { + | ^^^^^^^^^^^^^ expected `usize`, found `bool` + error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:7:5 | @@ -7,17 +13,14 @@ LL | std::mem::transmute(v) = note: source type: `[[u32; H+1]; W]` (size can vary because of [u32; H+1]) = note: target type: `[[u32; W+1]; H]` (size can vary because of [u32; W+1]) -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:16:5 +error: the constant `W` is not of type `usize` + --> $DIR/transmute-fail.rs:15:5 | LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H]) - = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) + | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:23:5 + --> $DIR/transmute-fail.rs:22:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -26,7 +29,7 @@ LL | std::mem::transmute(v) = note: target type: `[u32; W * H * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:30:5 + --> $DIR/transmute-fail.rs:29:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -35,7 +38,7 @@ LL | std::mem::transmute(v) = note: target type: `[[[u32; 9999999]; 777777777]; 8888888]` (values of the type `[[u32; 9999999]; 777777777]` are too big for the current architecture) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:37:5 + --> $DIR/transmute-fail.rs:36:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -44,7 +47,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:50:5 + --> $DIR/transmute-fail.rs:49:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -53,7 +56,7 @@ LL | std::mem::transmute(v) = note: target type: `[u32; W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:57:5 + --> $DIR/transmute-fail.rs:56:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -62,7 +65,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:66:5 + --> $DIR/transmute-fail.rs:65:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -71,7 +74,7 @@ LL | std::mem::transmute(v) = note: target type: `[u32; D * W * H]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:75:5 + --> $DIR/transmute-fail.rs:74:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -80,7 +83,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u32; D * W]; H]` (size can vary because of [u32; D * W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:82:5 + --> $DIR/transmute-fail.rs:81:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -89,7 +92,7 @@ LL | std::mem::transmute(v) = note: target type: `[u8; L * 2]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:89:5 + --> $DIR/transmute-fail.rs:88:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -98,7 +101,7 @@ LL | std::mem::transmute(v) = note: target type: `[u16; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:96:5 + --> $DIR/transmute-fail.rs:95:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -107,7 +110,7 @@ LL | std::mem::transmute(v) = note: target type: `[[u8; 1]; L]` (this type does not have a fixed size) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-fail.rs:105:5 + --> $DIR/transmute-fail.rs:104:5 | LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ @@ -115,19 +118,6 @@ LL | std::mem::transmute(v) = note: source type: `[[u32; 2 * H]; W + W]` (size can vary because of [u32; 2 * H]) = note: target type: `[[u32; W + W]; 2 * H]` (size can vary because of [u32; W + W]) -error[E0308]: mismatched types - --> $DIR/transmute-fail.rs:12:53 - | -LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { - | ^ expected `usize`, found `bool` - -error[E0308]: mismatched types - --> $DIR/transmute-fail.rs:12:67 - | -LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { - | ^ expected `usize`, found `bool` - -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0308, E0512. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/const-generics/type_mismatch.rs b/tests/ui/const-generics/type_mismatch.rs index daa13277be0..8187c785cd1 100644 --- a/tests/ui/const-generics/type_mismatch.rs +++ b/tests/ui/const-generics/type_mismatch.rs @@ -1,10 +1,10 @@ fn foo<const N: usize>() -> [u8; N] { - bar::<N>() //~ ERROR mismatched types + bar::<N>() //~^ ERROR the constant `N` is not of type `u8` } fn bar<const N: u8>() -> [u8; N] {} -//~^ ERROR mismatched types +//~^ ERROR the constant `N` is not of type `usize` //~| ERROR mismatched types fn main() {} diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr index 026999827c0..d1bb5c1242f 100644 --- a/tests/ui/const-generics/type_mismatch.stderr +++ b/tests/ui/const-generics/type_mismatch.stderr @@ -1,3 +1,9 @@ +error: the constant `N` is not of type `usize` + --> $DIR/type_mismatch.rs:6:26 + | +LL | fn bar<const N: u8>() -> [u8; N] {} + | ^^^^^^^ expected `usize`, found `u8` + error: the constant `N` is not of type `u8` --> $DIR/type_mismatch.rs:2:11 | @@ -18,18 +24,6 @@ LL | fn bar<const N: u8>() -> [u8; N] {} | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:2:11 - | -LL | bar::<N>() - | ^ expected `u8`, found `usize` - -error[E0308]: mismatched types - --> $DIR/type_mismatch.rs:6:31 - | -LL | fn bar<const N: u8>() -> [u8; N] {} - | ^ expected `usize`, found `u8` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index c1748c2e237..d7d24f373eb 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -436,30 +436,20 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:196:1 +error[E0080]: evaluation of constant value failed + --> $DIR/raw-bytes.rs:196:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC_ID╼ 00 00 00 00 │ ╾──╼.... - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:198:1 +error[E0080]: evaluation of constant value failed + --> $DIR/raw-bytes.rs:199:65 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──╼╾──╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC32 as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:202:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -470,7 +460,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:203:1 + --> $DIR/raw-bytes.rs:205:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -481,7 +471,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:204:1 + --> $DIR/raw-bytes.rs:206:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -492,7 +482,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:208:1 + --> $DIR/raw-bytes.rs:210:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -503,7 +493,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:213:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -516,7 +506,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:214:1 + --> $DIR/raw-bytes.rs:216:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -527,7 +517,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 + --> $DIR/raw-bytes.rs:220:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -538,7 +528,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:225:1 + --> $DIR/raw-bytes.rs:227:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -549,7 +539,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:230:1 + --> $DIR/raw-bytes.rs:232:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -562,7 +552,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:235:1 + --> $DIR/raw-bytes.rs:237:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index eb97eab9db7..22679acda98 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -436,30 +436,20 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ } -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:196:1 +error[E0080]: evaluation of constant value failed + --> $DIR/raw-bytes.rs:196:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC_ID╼ 00 00 00 00 00 00 00 00 │ ╾──────╼........ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:198:1 +error[E0080]: evaluation of constant value failed + --> $DIR/raw-bytes.rs:199:65 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC_ID╼ ╾ALLOC_ID╼ │ ╾──────╼╾──────╼ - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC32 as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:202:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -470,7 +460,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:203:1 + --> $DIR/raw-bytes.rs:205:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -481,7 +471,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:204:1 + --> $DIR/raw-bytes.rs:206:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -492,7 +482,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:208:1 + --> $DIR/raw-bytes.rs:210:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -503,7 +493,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:213:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -516,7 +506,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:214:1 + --> $DIR/raw-bytes.rs:216:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -527,7 +517,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 + --> $DIR/raw-bytes.rs:220:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -538,7 +528,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:225:1 + --> $DIR/raw-bytes.rs:227:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -549,7 +539,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:230:1 + --> $DIR/raw-bytes.rs:232:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -562,7 +552,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:235:1 + --> $DIR/raw-bytes.rs:237:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 1c7ef6f2b0f..de1a81b0024 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -194,9 +194,11 @@ const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool //~| expected a boolean const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| null pointer const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| vtable // Uninhabited types const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 5c47cbfdf3b..439ccb24e61 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -1,56 +1,46 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:18:1 - | -LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:19:14 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──╼╾──╼ - } +LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC8 as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:23:1 - | -LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:24:14 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──╼╾──╼ - } +LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC9 as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC1<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼ + ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC3<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──╼╾──╼ + ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──╼╾──╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -61,7 +51,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──╼╾──╼ + ╾ALLOC6<imm>╼ ╾ALLOC7╼ │ ╾──╼╾──╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index f400073aca2..89bf959703a 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -1,56 +1,46 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:18:1 - | -LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:19:14 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼ - } +LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC8 as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-incorrect-vtable.rs:23:1 - | -LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer +error[E0080]: evaluation of constant value failed + --> $DIR/ub-incorrect-vtable.rs:24:14 | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼ - } +LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC9 as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC1<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼ + ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC3<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼ + ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -61,7 +51,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ + ╾ALLOC6<imm>╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs index 11c3b2fe560..4325495a380 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -17,13 +17,13 @@ trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; -//~^^ ERROR it is undefined behavior to use this value -//~| expected a vtable pointer +//~^ ERROR evaluation of constant value failed +//~| vtable const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; -//~^^ ERROR it is undefined behavior to use this value -//~| expected a vtable pointer +//~^ ERROR evaluation of constant value failed +//~| vtable #[repr(transparent)] struct W<T>(T); diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index d0d93081738..3956146f6ae 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -113,27 +113,27 @@ const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { // bad trait object const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~| vtable // bad trait object const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~| vtable // bad trait object const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~| vtable const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; -//~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~^ ERROR evaluation of constant value failed +//~| vtable const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~^ ERROR evaluation of constant value failed +//~| vtable const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; -//~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~^ ERROR evaluation of constant value failed +//~| vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; //~^ ERROR it is undefined behavior to use this value -//~| expected a vtable +//~| vtable // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; @@ -142,21 +142,25 @@ const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool // # raw trait object const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| null pointer const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; -//~^ ERROR it is undefined behavior to use this value +//~^ ERROR evaluation of constant value failed +//~| vtable const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) } as *const dyn Trait; // ok because raw // Officially blessed way to get the vtable const DYN_METADATA: ptr::DynMetadata<dyn Send> = ptr::metadata::<dyn Send>(ptr::null::<i32>()); -// Const eval fails for these, so they need to be statics to error. + static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { -//~^ ERROR it is undefined behavior to use this value mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + //~^ ERROR could not evaluate static initializer + //~| null pointer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { -//~^ ERROR it is undefined behavior to use this value mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + //~^ ERROR could not evaluate static initializer + //~| vtable }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 2fa462a6a64..4fe744265df 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -218,44 +218,29 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:125:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:125:57 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC20 as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:128:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:128:57 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC21 as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:131:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:131:56 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC22 as vtable pointer but it does not point to a vtable error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:134:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23<imm>, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -273,49 +258,29 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, HEX_DUMP } -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:144:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:144:62 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:146:1 +error[E0080]: evaluation of constant value failed + --> $DIR/ub-wide-ptr.rs:147:65 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC23 as vtable pointer but it does not point to a vtable -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:153:1 +error[E0080]: could not evaluate static initializer + --> $DIR/ub-wide-ptr.rs:156:5 | -LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } +LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) -error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:157:1 +error[E0080]: could not evaluate static initializer + --> $DIR/ub-wide-ptr.rs:161:5 | -LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31<imm>, but expected a vtable pointer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } +LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using ALLOC24 as vtable pointer but it does not point to a vtable error: aborting due to 29 previous errors diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs index 2e7061e7c4b..ab8eec876bc 100644 --- a/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs +++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-pass.rs @@ -23,9 +23,20 @@ const BAR_BAZ: Foo = if 42 == 42 { Foo::Qux(CustomEq) // dead arm }; +const EMPTY: &[CustomEq] = &[]; + fn main() { + // BAR_BAZ itself is fine but the enum has other variants + // that are non-structural. Still, this should be accepted. match Foo::Qux(CustomEq) { BAR_BAZ => panic!(), _ => {} } + + // Similarly, an empty slice of a type that is non-structural + // is accepted. + match &[CustomEq] as &[CustomEq] { + EMPTY => panic!(), + _ => {}, + } } diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs index 86d971044fe..645e1418912 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs @@ -26,7 +26,7 @@ fn main() { match None { NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), - //~^ ERROR must be annotated with `#[derive(PartialEq)]` + //~^ ERROR must implement `PartialEq` _ => panic!("whoops"), } } diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr index 88b82d5004b..ed531a1fead 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr @@ -1,11 +1,8 @@ -error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq)]` +error: to use a constant of type `Option<NoPartialEq>` in a pattern, the type must implement `PartialEq` --> $DIR/reject_non_partial_eq.rs:28:9 | LL | NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"), | ^^^^^^^^^^^^^^^^^^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/consts/const_let_assign2.stderr b/tests/ui/consts/const_let_assign2.stderr index 5ae8fd353dd..87b94a7be67 100644 --- a/tests/ui/consts/const_let_assign2.stderr +++ b/tests/ui/consts/const_let_assign2.stderr @@ -11,7 +11,7 @@ LL | let ptr = unsafe { &mut BB }; help: use `addr_of_mut!` instead to create a raw pointer | LL | let ptr = unsafe { addr_of_mut!(BB) }; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.rs b/tests/ui/consts/invalid-inline-const-in-match-arm.rs index 0654fd82fbc..4fe4b0d33c8 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.rs +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.rs @@ -4,5 +4,6 @@ fn main() { match () { const { (|| {})() } => {} //~^ ERROR cannot call non-const closure in constants + //~| ERROR could not evaluate constant pattern } } diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr index 7579f7f9692..0e41053a29d 100644 --- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr +++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr @@ -11,6 +11,12 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable LL + #![feature(const_trait_impl)] | -error: aborting due to 1 previous error +error: could not evaluate constant pattern + --> $DIR/invalid-inline-const-in-match-arm.rs:5:9 + | +LL | const { (|| {})() } => {} + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/issue-36163.stderr b/tests/ui/consts/issue-36163.stderr index 8a7a0981f41..52d3e003f0a 100644 --- a/tests/ui/consts/issue-36163.stderr +++ b/tests/ui/consts/issue-36163.stderr @@ -1,10 +1,10 @@ -error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... +note: ...which requires const-evaluating + checking `Foo::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, @@ -19,7 +19,7 @@ note: ...which requires const-evaluating + checking `A`... | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ - = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/issue-36163.rs:3:1 | diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr index 97a5fbc5747..8a44eb9854f 100644 --- a/tests/ui/consts/issue-73976-polymorphic.stderr +++ b/tests/ui/consts/issue-73976-polymorphic.stderr @@ -1,10 +1,10 @@ -error: constant pattern depends on a generic parameter +error[E0158]: constant pattern depends on a generic parameter --> $DIR/issue-73976-polymorphic.rs:20:37 | LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE) | ^^^^^^^^^^^^^^^^^^^^^ -error: constant pattern depends on a generic parameter +error[E0158]: constant pattern depends on a generic parameter --> $DIR/issue-73976-polymorphic.rs:31:42 | LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) @@ -12,3 +12,4 @@ LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE) error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr index 18bdde45e2c..de81512ec6d 100644 --- a/tests/ui/consts/issue-79137-toogeneric.stderr +++ b/tests/ui/consts/issue-79137-toogeneric.stderr @@ -1,4 +1,4 @@ -error: constant pattern depends on a generic parameter +error[E0158]: constant pattern depends on a generic parameter --> $DIR/issue-79137-toogeneric.rs:12:43 | LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE) @@ -6,3 +6,4 @@ LL | matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE) error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/coroutine/issue-102645.stderr b/tests/ui/coroutine/issue-102645.stderr index ab5e4a8459f..1ef37d3f7d1 100644 --- a/tests/ui/coroutine/issue-102645.stderr +++ b/tests/ui/coroutine/issue-102645.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/issue-102645.rs:15:22 | LL | Pin::new(&mut b).resume(); - | ^^^^^^-- an argument of type `()` is missing + | ^^^^^^-- argument #1 of type `()` is missing | note: method defined here --> $SRC_DIR/core/src/ops/coroutine.rs:LL:COL diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index f378e05304b..f15e6aa81af 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -34,6 +34,9 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope + reuse Trait::foo2 { self.0 } + //~^ ERROR cannot find function `foo2` in trait `Trait` + //~| ERROR method `foo2` is not a member of trait `Trait` } mod prefix {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 883ff523bcf..32d2f3b26cb 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -25,6 +25,15 @@ LL | reuse <F as Trait>::baz; | | help: there is an associated function with a similar name: `bar` | not a member of trait `Trait` +error[E0407]: method `foo2` is not a member of trait `Trait` + --> $DIR/bad-resolve.rs:37:5 + | +LL | reuse Trait::foo2 { self.0 } + | ^^^^^^^^^^^^^----^^^^^^^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo` + | not a member of trait `Trait` + error[E0423]: expected function, found associated constant `Trait::C` --> $DIR/bad-resolve.rs:24:11 | @@ -54,6 +63,15 @@ error[E0425]: cannot find function `foo` in this scope LL | reuse foo { &self.0 } | ^^^ not found in this scope +error[E0425]: cannot find function `foo2` in trait `Trait` + --> $DIR/bad-resolve.rs:37:18 + | +LL | fn foo(&self, x: i32) -> i32 { x } + | ---------------------------- similarly named associated function `foo` defined here +... +LL | reuse Trait::foo2 { self.0 } + | ^^^^ help: an associated function with a similar name exists: `foo` + error[E0046]: not all trait items implemented, missing: `Type` --> $DIR/bad-resolve.rs:22:1 | @@ -64,18 +82,18 @@ LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix` - --> $DIR/bad-resolve.rs:40:7 + --> $DIR/bad-resolve.rs:43:7 | LL | reuse unresolved_prefix::{a, b, c}; | ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix` error[E0433]: failed to resolve: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:41:29 + --> $DIR/bad-resolve.rs:44:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ `crate` in paths can only be used in start position -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/explicit-paths-pass.rs b/tests/ui/delegation/explicit-paths-pass.rs index fada793bd11..dd0ee2c732f 100644 --- a/tests/ui/delegation/explicit-paths-pass.rs +++ b/tests/ui/delegation/explicit-paths-pass.rs @@ -24,8 +24,8 @@ reuse to_reuse::zero_args { self } struct S(F); impl Trait for S { - reuse Trait::bar { &self.0 } - reuse Trait::description { &self.0 } + reuse Trait::bar { self.0 } + reuse Trait::description { self.0 } reuse <F as Trait>::static_method; reuse <F as Trait>::static_method2 { S::static_method(self) } } diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index a91ca4cb931..d42e305b252 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -34,7 +34,7 @@ mod inherent_impl_assoc_fn_to_other { use crate::*; impl S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse <S as Trait>::foo2; reuse to_reuse::foo3; reuse F::foo4 { &self.0 } @@ -46,7 +46,7 @@ mod trait_impl_assoc_fn_to_other { use crate::*; impl Trait for S { - reuse Trait::foo1 { &self.0 } + reuse Trait::foo1 { self.0 } reuse <F as Trait>::foo2; reuse to_reuse::foo3; //~^ ERROR method `foo3` is not a member of trait `Trait` diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index d33c5da4377..b5afe19f878 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -91,10 +91,17 @@ error[E0308]: mismatched types LL | trait Trait2 : Trait { | -------------------- found this type parameter LL | reuse <F as Trait>::foo1 { self } - | ^^^^ expected `&F`, found `&Self` + | ---- ^^^^ expected `&F`, found `&Self` + | | + | arguments to this function are incorrect | = note: expected reference `&F` found reference `&Self` +note: method defined here + --> $DIR/explicit-paths.rs:5:8 + | +LL | fn foo1(&self, x: i32) -> i32 { x } + | ^^^^ ----- error[E0277]: the trait bound `S2: Trait` is not satisfied --> $DIR/explicit-paths.rs:78:16 diff --git a/tests/ui/delegation/ice-issue-122550.stderr b/tests/ui/delegation/ice-issue-122550.stderr index c92170644e7..1a01bee3e1e 100644 --- a/tests/ui/delegation/ice-issue-122550.stderr +++ b/tests/ui/delegation/ice-issue-122550.stderr @@ -4,15 +4,6 @@ error[E0308]: mismatched types LL | fn description(&self) -> &str {} | ^^ expected `&str`, found `()` -error[E0308]: mismatched types - --> $DIR/ice-issue-122550.rs:13:39 - | -LL | reuse <S as Trait>::description { &self.0 } - | ^^^^^^^ expected `&S`, found `&F` - | - = note: expected reference `&S` - found reference `&F` - error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/ice-issue-122550.rs:13:12 | @@ -25,6 +16,22 @@ help: this trait has no implementations, consider adding one LL | trait Trait { | ^^^^^^^^^^^ +error[E0308]: mismatched types + --> $DIR/ice-issue-122550.rs:13:39 + | +LL | reuse <S as Trait>::description { &self.0 } + | ----------- ^^^^^^^ expected `&S`, found `&F` + | | + | arguments to this function are incorrect + | + = note: expected reference `&S` + found reference `&F` +note: method defined here + --> $DIR/ice-issue-122550.rs:5:8 + | +LL | fn description(&self) -> &str {} + | ^^^^^^^^^^^ ----- + error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0308. diff --git a/tests/ui/delegation/method-call-choice.rs b/tests/ui/delegation/method-call-choice.rs new file mode 100644 index 00000000000..8d53d8bfdb7 --- /dev/null +++ b/tests/ui/delegation/method-call-choice.rs @@ -0,0 +1,25 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + fn foo(&self) {} +} + +struct F; +impl Trait for F {} +struct S(F); + +pub mod to_reuse { + use crate::F; + + pub fn foo(_: &F) {} +} + +impl Trait for S { + // Make sure that the method call is not generated if the path resolution + // does not have a `self` parameter. + reuse to_reuse::foo { self.0 } + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/delegation/method-call-choice.stderr b/tests/ui/delegation/method-call-choice.stderr new file mode 100644 index 00000000000..6757af20a6b --- /dev/null +++ b/tests/ui/delegation/method-call-choice.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/method-call-choice.rs:21:27 + | +LL | reuse to_reuse::foo { self.0 } + | --- ^^^^^^ expected `&F`, found `F` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/method-call-choice.rs:15:12 + | +LL | pub fn foo(_: &F) {} + | ^^^ ----- +help: consider borrowing here + | +LL | reuse to_reuse::foo { &self.0 } + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/method-call-priority.rs b/tests/ui/delegation/method-call-priority.rs new file mode 100644 index 00000000000..8d68740d181 --- /dev/null +++ b/tests/ui/delegation/method-call-priority.rs @@ -0,0 +1,34 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![allow(dead_code)] + +trait Trait1 { + fn foo(&self) -> i32 { 1 } +} + +trait Trait2 { + fn foo(&self) -> i32 { 2 } +} + +struct F; +impl Trait1 for F {} +impl Trait2 for F {} + +impl F { + fn foo(&self) -> i32 { 3 } +} + +struct S(F); + +impl Trait1 for S { + // Make sure that the generated `self.0.foo()` does not turn into the inherent method `F::foo` + // that has a higher priority than methods from traits. + reuse Trait1::foo { self.0 } +} + +fn main() { + let s = S(F); + assert_eq!(s.foo(), 1); +} diff --git a/tests/ui/delegation/self-coercion.rs b/tests/ui/delegation/self-coercion.rs new file mode 100644 index 00000000000..96c1f1b140b --- /dev/null +++ b/tests/ui/delegation/self-coercion.rs @@ -0,0 +1,26 @@ +//@ run-pass + +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait : Sized { + fn by_value(self) -> i32 { 1 } + fn by_mut_ref(&mut self) -> i32 { 2 } + fn by_ref(&self) -> i32 { 3 } +} + +struct F; +impl Trait for F {} + +struct S(F); + +impl Trait for S { + reuse Trait::{by_value, by_mut_ref, by_ref} { self.0 } +} + +fn main() { + let mut s = S(F); + assert_eq!(s.by_ref(), 3); + assert_eq!(s.by_mut_ref(), 2); + assert_eq!(s.by_value(), 1); +} diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr index de1194e74b4..9126e602391 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.stderr @@ -11,7 +11,7 @@ LL | (mem::size_of_val(&trails) * 8) as u32 help: use `addr_of!` instead to create a raw pointer | LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr b/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr index bdf46abea8a..6da87416802 100644 --- a/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr +++ b/tests/ui/drop/issue-23611-enum-swap-in-drop.stderr @@ -11,7 +11,7 @@ LL | (mem::size_of_val(&trails) * 8) as u32 help: use `addr_of!` instead to create a raw pointer | LL | (mem::size_of_val(addr_of!(trails)) * 8) as u32 - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/duplicate/duplicate-check-macro-exports.stderr b/tests/ui/duplicate/duplicate-check-macro-exports.stderr index eff19c09062..470a516ecbc 100644 --- a/tests/ui/duplicate/duplicate-check-macro-exports.stderr +++ b/tests/ui/duplicate/duplicate-check-macro-exports.stderr @@ -11,7 +11,7 @@ LL | macro_rules! panic { () => {} } help: you can use `as` to change the binding name of the import | LL | pub use std::panic as other_panic; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/empty/empty-struct-braces-expr.stderr b/tests/ui/empty/empty-struct-braces-expr.stderr index 4604ebeaa8b..28c701443de 100644 --- a/tests/ui/empty/empty-struct-braces-expr.stderr +++ b/tests/ui/empty/empty-struct-braces-expr.stderr @@ -71,12 +71,22 @@ error[E0533]: expected value, found struct variant `E::Empty3` | LL | let e3 = E::Empty3; | ^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let e3 = E::Empty3 {}; + | ++ error[E0533]: expected value, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-expr.rs:19:14 | LL | let e3 = E::Empty3(); | ^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let e3 = E::Empty3 {}; + | ~~ error[E0423]: expected function, tuple struct or tuple variant, found struct `XEmpty1` --> $DIR/empty-struct-braces-expr.rs:23:15 @@ -104,25 +114,34 @@ error[E0599]: no variant or associated item named `Empty3` found for enum `empty --> $DIR/empty-struct-braces-expr.rs:25:19 | LL | let xe3 = XE::Empty3; - | ^^^^^^ - | | - | variant or associated item not found in `XE` - | help: there is a variant with a similar name: `XEmpty3` + | ^^^^^^ variant or associated item not found in `XE` + | +help: there is a variant with a similar name + | +LL | let xe3 = XE::XEmpty3; + | ~~~~~~~ error[E0599]: no variant or associated item named `Empty3` found for enum `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:26:19 | LL | let xe3 = XE::Empty3(); - | ^^^^^^ - | | - | variant or associated item not found in `XE` - | help: there is a variant with a similar name: `XEmpty3` + | ^^^^^^ variant or associated item not found in `XE` + | +help: there is a variant with a similar name + | +LL | let xe3 = XE::XEmpty3 {}; + | ~~~~~~~~~~ error[E0599]: no variant named `Empty1` found for enum `empty_struct::XE` --> $DIR/empty-struct-braces-expr.rs:28:9 | LL | XE::Empty1 {}; - | ^^^^^^ help: there is a variant with a similar name: `XEmpty3` + | ^^^^^^ + | +help: there is a variant with a similar name + | +LL | XE::XEmpty3 {}; + | ~~~~~~~~~~ error: aborting due to 9 previous errors diff --git a/tests/ui/enum/error-variant-with-turbofishes.stderr b/tests/ui/enum/error-variant-with-turbofishes.stderr index 66bed1c0d85..ffc2862bfe0 100644 --- a/tests/ui/enum/error-variant-with-turbofishes.stderr +++ b/tests/ui/enum/error-variant-with-turbofishes.stderr @@ -3,6 +3,11 @@ error[E0533]: expected value, found struct variant `Struct<0>::Variant` | LL | let x = Struct::<0>::Variant; | ^^^^^^^^^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let x = Struct::<0>::Variant { x: /* value */ }; + | ++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0057.stderr b/tests/ui/error-codes/E0057.stderr index efd2af6d609..ef6e2908b93 100644 --- a/tests/ui/error-codes/E0057.stderr +++ b/tests/ui/error-codes/E0057.stderr @@ -2,7 +2,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0057.rs:3:13 | LL | let a = f(); - | ^-- an argument is missing + | ^-- argument #1 is missing | note: closure defined here --> $DIR/E0057.rs:2:13 @@ -18,7 +18,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^ - unexpected argument of type `{integer}` + | ^ - unexpected argument #2 of type `{integer}` | note: closure defined here --> $DIR/E0057.rs:2:13 diff --git a/tests/ui/error-codes/E0060.stderr b/tests/ui/error-codes/E0060.stderr index 88c1f1bbb2a..8387b15b970 100644 --- a/tests/ui/error-codes/E0060.stderr +++ b/tests/ui/error-codes/E0060.stderr @@ -2,7 +2,7 @@ error[E0060]: this function takes at least 1 argument but 0 arguments were suppl --> $DIR/E0060.rs:6:14 | LL | unsafe { printf(); } - | ^^^^^^-- an argument of type `*const u8` is missing + | ^^^^^^-- argument #1 of type `*const u8` is missing | note: function defined here --> $DIR/E0060.rs:2:8 diff --git a/tests/ui/error-codes/E0061.stderr b/tests/ui/error-codes/E0061.stderr index fa4ccbe6677..7b180c07120 100644 --- a/tests/ui/error-codes/E0061.stderr +++ b/tests/ui/error-codes/E0061.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | LL | f(0); - | ^--- an argument of type `&str` is missing + | ^--- argument #2 of type `&str` is missing | note: function defined here --> $DIR/E0061.rs:1:4 @@ -18,7 +18,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:9:5 | LL | f2(); - | ^^-- an argument of type `u16` is missing + | ^^-- argument #1 of type `u16` is missing | note: function defined here --> $DIR/E0061.rs:3:4 diff --git a/tests/ui/error-codes/E0229.stderr b/tests/ui/error-codes/E0229.stderr index 7d9cedc3bdc..038f44e8b14 100644 --- a/tests/ui/error-codes/E0229.stderr +++ b/tests/ui/error-codes/E0229.stderr @@ -6,8 +6,9 @@ LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} | help: consider removing this associated item binding | -LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} - | ~~~~~~~~~ +LL - fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} +LL + fn baz<I>(x: &<I as Foo>::A) {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/E0229.rs:13:25 @@ -18,8 +19,9 @@ LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} - | ~~~~~~~~~ +LL - fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} +LL + fn baz<I>(x: &<I as Foo>::A) {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/E0229.rs:13:25 @@ -30,8 +32,9 @@ LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} - | ~~~~~~~~~ +LL - fn baz<I>(x: &<I as Foo<A = Bar>>::A) {} +LL + fn baz<I>(x: &<I as Foo>::A) {} + | error[E0277]: the trait bound `I: Foo` is not satisfied --> $DIR/E0229.rs:13:15 diff --git a/tests/ui/error-codes/E0252.stderr b/tests/ui/error-codes/E0252.stderr index efbb9ec96de..16574964eb3 100644 --- a/tests/ui/error-codes/E0252.stderr +++ b/tests/ui/error-codes/E0252.stderr @@ -10,7 +10,7 @@ LL | use bar::baz; help: you can use `as` to change the binding name of the import | LL | use bar::baz as other_baz; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0254.stderr b/tests/ui/error-codes/E0254.stderr index d89497b2804..592b8766d6b 100644 --- a/tests/ui/error-codes/E0254.stderr +++ b/tests/ui/error-codes/E0254.stderr @@ -11,7 +11,7 @@ LL | use foo::alloc; help: you can use `as` to change the binding name of the import | LL | use foo::alloc as other_alloc; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0255.stderr b/tests/ui/error-codes/E0255.stderr index e5f908217e1..b67a334f02c 100644 --- a/tests/ui/error-codes/E0255.stderr +++ b/tests/ui/error-codes/E0255.stderr @@ -11,7 +11,7 @@ LL | fn foo() {} help: you can use `as` to change the binding name of the import | LL | use bar::foo as other_foo; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/expr/issue-22933-2.stderr b/tests/ui/expr/issue-22933-2.stderr index 8cda8598f3c..dadc3121362 100644 --- a/tests/ui/expr/issue-22933-2.stderr +++ b/tests/ui/expr/issue-22933-2.stderr @@ -5,10 +5,12 @@ LL | enum Delicious { | -------------- variant or associated item `PIE` not found for this enum ... LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - | ^^^ - | | - | variant or associated item not found in `Delicious` - | help: there is a variant with a similar name: `Pie` + | ^^^ variant or associated item not found in `Delicious` + | +help: there is a variant with a similar name + | +LL | ApplePie = Delicious::Apple as isize | Delicious::Pie as isize, + | ~~~ error: aborting due to 1 previous error diff --git a/tests/ui/extern/issue-18819.stderr b/tests/ui/extern/issue-18819.stderr index b2cf0bad1df..6de0ebfe9ae 100644 --- a/tests/ui/extern/issue-18819.stderr +++ b/tests/ui/extern/issue-18819.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | LL | print_x(X); - | ^^^^^^^--- an argument of type `&str` is missing + | ^^^^^^^--- argument #2 of type `&str` is missing | note: expected `&dyn Foo<Item = bool>`, found `X` --> $DIR/issue-18819.rs:16:13 diff --git a/tests/ui/fn/issue-3044.stderr b/tests/ui/fn/issue-3044.stderr index 06254775b74..8351818dc89 100644 --- a/tests/ui/fn/issue-3044.stderr +++ b/tests/ui/fn/issue-3044.stderr @@ -5,7 +5,7 @@ LL | needlesArr.iter().fold(|x, y| { | _______________________^^^^- LL | | LL | | }); - | |______- an argument is missing + | |______- argument #2 is missing | note: method defined here --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL diff --git a/tests/ui/generic-associated-types/issue-102335-gat.stderr b/tests/ui/generic-associated-types/issue-102335-gat.stderr index b4772486e6e..bcef76290fc 100644 --- a/tests/ui/generic-associated-types/issue-102335-gat.stderr +++ b/tests/ui/generic-associated-types/issue-102335-gat.stderr @@ -6,8 +6,9 @@ LL | type A: S<C<(), i32 = ()> = ()>; | help: consider removing this associated item binding | -LL | type A: S<C<(), i32 = ()> = ()>; - | ~~~~~~~~~~ +LL - type A: S<C<(), i32 = ()> = ()>; +LL + type A: S<C<()> = ()>; + | error[E0229]: associated item constraints are not allowed here --> $DIR/issue-102335-gat.rs:2:21 @@ -18,8 +19,9 @@ LL | type A: S<C<(), i32 = ()> = ()>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type A: S<C<(), i32 = ()> = ()>; - | ~~~~~~~~~~ +LL - type A: S<C<(), i32 = ()> = ()>; +LL + type A: S<C<()> = ()>; + | error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-91139.migrate.stderr b/tests/ui/generic-associated-types/issue-91139.migrate.stderr index 23b7bf45afb..e3b658558e3 100644 --- a/tests/ui/generic-associated-types/issue-91139.migrate.stderr +++ b/tests/ui/generic-associated-types/issue-91139.migrate.stderr @@ -1,7 +1,6 @@ error: expected identifier, found `<<` --> $DIR/issue-91139.rs:1:1 | -LL | <<<<<<< HEAD | ^^ expected identifier error: aborting due to 1 previous error diff --git a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr index dfc6761e17e..c60c4c72a21 100644 --- a/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr +++ b/tests/ui/generics/impl-block-params-declared-in-wrong-spot-issue-113073.stderr @@ -14,8 +14,9 @@ LL | impl Foo<T: Default> for String {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<T: Default> Foo<T> for String {} - | ++++++++++++ ~ +LL - impl Foo<T: Default> for String {} +LL + impl<T: Default> Foo<T> for String {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:7:10 @@ -25,8 +26,9 @@ LL | impl Foo<T: 'a + Default> for u8 {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<'a, T: 'a + Default> Foo<T> for u8 {} - | +++++++++++++++++++++ ~ +LL - impl Foo<T: 'a + Default> for u8 {} +LL + impl<'a, T: 'a + Default> Foo<T> for u8 {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:13:13 @@ -36,8 +38,9 @@ LL | impl<T> Foo<T: Default> for u16 {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<T, T: Default> Foo<T> for u16 {} - | ++++++++++++ ~ +LL - impl<T> Foo<T: Default> for u16 {} +LL + impl<T, T: Default> Foo<T> for u16 {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:17:14 @@ -47,8 +50,9 @@ LL | impl<'a> Foo<T: 'a + Default> for u32 {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<'a, 'a, T: 'a + Default> Foo<T> for u32 {} - | +++++++++++++++++++++ ~ +LL - impl<'a> Foo<T: 'a + Default> for u32 {} +LL + impl<'a, 'a, T: 'a + Default> Foo<T> for u32 {} + | error[E0229]: associated item constraints are not allowed here --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:23:10 @@ -58,8 +62,9 @@ LL | impl Bar<T: Default, K: Default> for String {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<T: Default> Bar<T, K: Default> for String {} - | ++++++++++++ ~ +LL - impl Bar<T: Default, K: Default> for String {} +LL + impl<T: Default> Bar<T, K: Default> for String {} + | error[E0107]: trait takes 2 generic arguments but 1 generic argument was supplied --> $DIR/impl-block-params-declared-in-wrong-spot-issue-113073.rs:27:9 @@ -87,8 +92,9 @@ LL | impl<T> Bar<T, K: Default> for u8 {} | help: declare the type parameter right after the `impl` keyword | -LL | impl<T, K: Default> Bar<T, K> for u8 {} - | ++++++++++++ ~ +LL - impl<T> Bar<T, K: Default> for u8 {} +LL + impl<T, K: Default> Bar<T, K> for u8 {} + | error: aborting due to 8 previous errors diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr index 8771de85c19..3697bd9cf02 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-2.next.stderr @@ -9,10 +9,6 @@ note: required by a bound in `impl_hr` | LL | fn impl_hr<'b, T: for<'a> Trait<'a, 'b>>() {} | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `impl_hr` -help: consider further restricting this bound - | -LL | fn not_hr<'a, T: for<'b> Trait<'a, 'b> + OtherTrait<'static> + for<'a> Trait<'a, '_>>() { - | +++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index 90df487c07e..6e0ec5620da 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -9,10 +9,6 @@ note: required by a bound in `trait_bound` | LL | fn trait_bound<T: for<'a> Trait<'a>>() {} | ^^^^^^^^^^^^^^^^^ required by this bound in `trait_bound` -help: consider further restricting this bound - | -LL | fn function1<T: Trait<'static> + for<'a> Trait<'a>>() { - | +++++++++++++++++++ error[E0277]: the trait bound `for<'a> T: Trait<'a>` is not satisfied --> $DIR/candidate-from-env-universe-err-project.rs:38:24 @@ -25,10 +21,6 @@ note: required by a bound in `projection_bound` | LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound` -help: consider further restricting this bound - | -LL | fn function2<T: Trait<'static, Assoc = usize> + for<'a> Trait<'a>>() { - | +++++++++++++++++++ error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize` --> $DIR/candidate-from-env-universe-err-project.rs:38:24 diff --git a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr index af76377de85..dc1a4c9b983 100644 --- a/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hrtb-higher-ranker-supertraits.stderr @@ -11,10 +11,6 @@ note: required by a bound in `want_foo_for_any_tcx` | LL | fn want_foo_for_any_tcx<F: for<'tcx> Foo<'tcx>>(f: &F) { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_foo_for_any_tcx` -help: consider further restricting this bound - | -LL | fn want_foo_for_some_tcx<'x, F: Foo<'x> + for<'tcx> Foo<'tcx>>(f: &'x F) { - | +++++++++++++++++++++ error[E0277]: the trait bound `for<'ccx> B: Bar<'ccx>` is not satisfied --> $DIR/hrtb-higher-ranker-supertraits.rs:28:26 @@ -29,10 +25,6 @@ note: required by a bound in `want_bar_for_any_ccx` | LL | fn want_bar_for_any_ccx<B: for<'ccx> Bar<'ccx>>(b: &B) { | ^^^^^^^^^^^^^^^^^^^ required by this bound in `want_bar_for_any_ccx` -help: consider further restricting this bound - | -LL | fn want_bar_for_some_ccx<'x, B: Bar<'x> + for<'ccx> Bar<'ccx>>(b: &B) { - | +++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr index 99d088799fb..34d7db9b3cf 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-58451.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | LL | f(&[f()]); - | ^-- an argument is missing + | ^-- argument #1 is missing | note: function defined here --> $DIR/issue-58451.rs:5:4 diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index fbf82a24b50..ae449099987 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -22,10 +22,6 @@ note: required by a bound in `<Bar as Foo<char>>::foo` | LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { | ^^^^^^^ required by this bound in `<Bar as Foo<char>>::foo` -help: consider further restricting this bound - | -LL | fn foo<F2: Foo<u8> + Foo<u8>>(self) -> impl Foo<u8> { - | +++++++++ error[E0276]: impl has stricter requirements than trait --> $DIR/return-dont-satisfy-bounds.rs:8:16 diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs index e0b115b0ce4..b50780643f1 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.rs @@ -27,4 +27,16 @@ fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<' //~^ ERROR hidden type for } +fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { +//~^ HELP add a `use<...>` bound + y +//~^ ERROR hidden type for +} + +fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { +//~^ HELP add a `use<...>` bound + y +//~^ ERROR hidden type for +} + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr index 391f16d012e..1007a835894 100644 --- a/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr +++ b/tests/ui/impl-trait/precise-capturing/hidden-type-suggestion.stderr @@ -62,6 +62,48 @@ help: add a `use<...>` bound to explicitly capture `'a` LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> { | ++++++++++++++++++++++++++++++ -error: aborting due to 4 previous errors +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:32:5 + | +LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { + | --- ---------- opaque type defined here + | | + | hidden type `&()` captures the anonymous lifetime defined here +LL | +LL | y + | ^ + | +note: you could use a `use<...>` bound to explicitly capture `'_`, but argument-position `impl Trait`s are not nameable + --> $DIR/hidden-type-suggestion.rs:30:21 + | +LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized { + | ^^^^^^^^^^ +help: add a `use<...>` bound to explicitly capture `'_` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + | +LL | fn no_params_yet<T: Sized>(_: T, y: &()) -> impl Sized + use<'_, T> { + | ++++++++++ ~ ++++++++++++ + +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> $DIR/hidden-type-suggestion.rs:38:5 + | +LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { + | -- ---------- opaque type defined here + | | + | hidden type `&'a ()` captures the lifetime `'a` as defined here +LL | +LL | y + | ^ + | +note: you could use a `use<...>` bound to explicitly capture `'a`, but argument-position `impl Trait`s are not nameable + --> $DIR/hidden-type-suggestion.rs:36:29 + | +LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized { + | ^^^^^^^^^^ +help: add a `use<...>` bound to explicitly capture `'a` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + | +LL | fn yes_params_yet<'a, T, U: Sized>(_: U, y: &'a ()) -> impl Sized + use<'a, T, U> { + | ++++++++++ ~ +++++++++++++++ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/imports/double-import.stderr b/tests/ui/imports/double-import.stderr index 73bb73e3490..15b8620909f 100644 --- a/tests/ui/imports/double-import.stderr +++ b/tests/ui/imports/double-import.stderr @@ -10,7 +10,7 @@ LL | use sub2::foo; help: you can use `as` to change the binding name of the import | LL | use sub2::foo as other_foo; - | ~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-19498.stderr b/tests/ui/imports/issue-19498.stderr index 9d26022098f..69bdb67d389 100644 --- a/tests/ui/imports/issue-19498.stderr +++ b/tests/ui/imports/issue-19498.stderr @@ -11,7 +11,7 @@ LL | mod A {} help: you can use `as` to change the binding name of the import | LL | use self::A as OtherA; - | ~~~~~~~~~~~~~~~~~ + | +++++++++ error[E0255]: the name `B` is defined multiple times --> $DIR/issue-19498.rs:5:1 @@ -26,7 +26,7 @@ LL | pub mod B {} help: you can use `as` to change the binding name of the import | LL | use self::B as OtherB; - | ~~~~~~~~~~~~~~~~~ + | +++++++++ error[E0255]: the name `D` is defined multiple times --> $DIR/issue-19498.rs:9:5 @@ -40,7 +40,7 @@ LL | mod D {} help: you can use `as` to change the binding name of the import | LL | use C::D as OtherD; - | ~~~~~~~~~~~~~~ + | +++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/imports/issue-24081.stderr b/tests/ui/imports/issue-24081.stderr index e5ed6b10a54..6ceba6c7013 100644 --- a/tests/ui/imports/issue-24081.stderr +++ b/tests/ui/imports/issue-24081.stderr @@ -11,7 +11,7 @@ LL | type Add = bool; help: you can use `as` to change the binding name of the import | LL | use std::ops::Add as OtherAdd; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error[E0255]: the name `Sub` is defined multiple times --> $DIR/issue-24081.rs:9:1 @@ -26,7 +26,7 @@ LL | struct Sub { x: f32 } help: you can use `as` to change the binding name of the import | LL | use std::ops::Sub as OtherSub; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error[E0255]: the name `Mul` is defined multiple times --> $DIR/issue-24081.rs:11:1 @@ -41,7 +41,7 @@ LL | enum Mul { A, B } help: you can use `as` to change the binding name of the import | LL | use std::ops::Mul as OtherMul; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error[E0255]: the name `Div` is defined multiple times --> $DIR/issue-24081.rs:13:1 @@ -56,7 +56,7 @@ LL | mod Div { } help: you can use `as` to change the binding name of the import | LL | use std::ops::Div as OtherDiv; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error[E0255]: the name `Rem` is defined multiple times --> $DIR/issue-24081.rs:15:1 @@ -71,7 +71,7 @@ LL | trait Rem { } help: you can use `as` to change the binding name of the import | LL | use std::ops::Rem as OtherRem; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++ error: aborting due to 5 previous errors diff --git a/tests/ui/imports/issue-25396.stderr b/tests/ui/imports/issue-25396.stderr index 518d2be7841..6f9b080f3c5 100644 --- a/tests/ui/imports/issue-25396.stderr +++ b/tests/ui/imports/issue-25396.stderr @@ -10,7 +10,7 @@ LL | use bar::baz; help: you can use `as` to change the binding name of the import | LL | use bar::baz as other_baz; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error[E0252]: the name `Quux` is defined multiple times --> $DIR/issue-25396.rs:7:5 @@ -24,7 +24,7 @@ LL | use bar::Quux; help: you can use `as` to change the binding name of the import | LL | use bar::Quux as OtherQuux; - | ~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error[E0252]: the name `blah` is defined multiple times --> $DIR/issue-25396.rs:10:5 @@ -38,7 +38,7 @@ LL | use bar::blah; help: you can use `as` to change the binding name of the import | LL | use bar::blah as other_blah; - | ~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++++ error[E0252]: the name `WOMP` is defined multiple times --> $DIR/issue-25396.rs:13:5 @@ -52,7 +52,7 @@ LL | use bar::WOMP; help: you can use `as` to change the binding name of the import | LL | use bar::WOMP as OtherWOMP; - | ~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/imports/issue-32354-suggest-import-rename.stderr b/tests/ui/imports/issue-32354-suggest-import-rename.stderr index de9bdc4f2cc..753fa434ffb 100644 --- a/tests/ui/imports/issue-32354-suggest-import-rename.stderr +++ b/tests/ui/imports/issue-32354-suggest-import-rename.stderr @@ -10,7 +10,7 @@ LL | use extension2::ConstructorExtension; help: you can use `as` to change the binding name of the import | LL | use extension2::ConstructorExtension as OtherConstructorExtension; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-45829/import-self.stderr b/tests/ui/imports/issue-45829/import-self.stderr index 0c9424f3083..3c9d4fe6ba6 100644 --- a/tests/ui/imports/issue-45829/import-self.stderr +++ b/tests/ui/imports/issue-45829/import-self.stderr @@ -48,7 +48,7 @@ LL | use foo::self; help: you can use `as` to change the binding name of the import | LL | use foo as other_foo; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0252]: the name `A` is defined multiple times --> $DIR/import-self.rs:16:11 diff --git a/tests/ui/imports/issue-45829/issue-45829.stderr b/tests/ui/imports/issue-45829/issue-45829.stderr index 627a09a07b8..c6835c3bd7a 100644 --- a/tests/ui/imports/issue-45829/issue-45829.stderr +++ b/tests/ui/imports/issue-45829/issue-45829.stderr @@ -10,7 +10,7 @@ LL | use foo::{A, B as A}; help: you can use `as` to change the binding name of the import | LL | use foo::{A, B as OtherA}; - | ~~~~~~~~~~~ + | ~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-45829/rename-use-vs-extern.stderr b/tests/ui/imports/issue-45829/rename-use-vs-extern.stderr index 9b0a2534a1d..fd4fb9db0b6 100644 --- a/tests/ui/imports/issue-45829/rename-use-vs-extern.stderr +++ b/tests/ui/imports/issue-45829/rename-use-vs-extern.stderr @@ -10,7 +10,7 @@ LL | use std as issue_45829_b; help: you can use `as` to change the binding name of the import | LL | use std as other_issue_45829_b; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-45829/rename-use-with-tabs.stderr b/tests/ui/imports/issue-45829/rename-use-with-tabs.stderr index 5751f41ae9d..178303bbc1d 100644 --- a/tests/ui/imports/issue-45829/rename-use-with-tabs.stderr +++ b/tests/ui/imports/issue-45829/rename-use-with-tabs.stderr @@ -10,7 +10,7 @@ LL | use foo::{A, bar::B as A}; help: you can use `as` to change the binding name of the import | LL | use foo::{A, bar::B as OtherA}; - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-45829/rename-with-path.stderr b/tests/ui/imports/issue-45829/rename-with-path.stderr index 69e084db6ff..a83fdb37324 100644 --- a/tests/ui/imports/issue-45829/rename-with-path.stderr +++ b/tests/ui/imports/issue-45829/rename-with-path.stderr @@ -10,7 +10,7 @@ LL | use std::{collections::HashMap as A, sync::Arc as A}; help: you can use `as` to change the binding name of the import | LL | use std::{collections::HashMap as A, sync::Arc as OtherA}; - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-45829/rename.stderr b/tests/ui/imports/issue-45829/rename.stderr index f1ee5112dc1..4977909487c 100644 --- a/tests/ui/imports/issue-45829/rename.stderr +++ b/tests/ui/imports/issue-45829/rename.stderr @@ -10,7 +10,7 @@ LL | use std as core; help: you can use `as` to change the binding name of the import | LL | use std as other_core; - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/issue-52891.stderr b/tests/ui/imports/issue-52891.stderr index 7bb1301edf2..730962d702a 100644 --- a/tests/ui/imports/issue-52891.stderr +++ b/tests/ui/imports/issue-52891.stderr @@ -98,7 +98,7 @@ LL | use issue_52891::b::inner; help: you can use `as` to change the binding name of the import | LL | use issue_52891::b::inner as other_inner; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++ error[E0254]: the name `issue_52891` is defined multiple times --> $DIR/issue-52891.rs:31:19 diff --git a/tests/ui/imports/issue-8640.stderr b/tests/ui/imports/issue-8640.stderr index ea350e97e64..d22fddb1a69 100644 --- a/tests/ui/imports/issue-8640.stderr +++ b/tests/ui/imports/issue-8640.stderr @@ -10,7 +10,7 @@ LL | mod bar {} help: you can use `as` to change the binding name of the import | LL | use baz::bar as other_bar; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr index 15c3a876afc..26f72b34eca 100644 --- a/tests/ui/inline-const/const-match-pat-generic.stderr +++ b/tests/ui/inline-const/const-match-pat-generic.stderr @@ -1,10 +1,10 @@ -error: constant pattern depends on a generic parameter +error[E0158]: constant pattern depends on a generic parameter --> $DIR/const-match-pat-generic.rs:7:9 | LL | const { V } => {}, | ^^^^^^^^^^^ -error: constant pattern depends on a generic parameter +error[E0158]: constant pattern depends on a generic parameter --> $DIR/const-match-pat-generic.rs:19:9 | LL | const { f(V) } => {}, @@ -12,3 +12,4 @@ LL | const { f(V) } => {}, error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/issues/issue-23217.stderr b/tests/ui/issues/issue-23217.stderr index 05ee0474c78..d14da75ab72 100644 --- a/tests/ui/issues/issue-23217.stderr +++ b/tests/ui/issues/issue-23217.stderr @@ -4,10 +4,12 @@ error[E0599]: no variant or associated item named `A` found for enum `SomeEnum` LL | pub enum SomeEnum { | ----------------- variant or associated item `A` not found for this enum LL | B = SomeEnum::A, - | ^ - | | - | variant or associated item not found in `SomeEnum` - | help: there is a variant with a similar name: `B` + | ^ variant or associated item not found in `SomeEnum` + | +help: there is a variant with a similar name + | +LL | B = SomeEnum::B, + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-28971.stderr b/tests/ui/issues/issue-28971.stderr index 26057cbc2d1..7ca57d6b998 100644 --- a/tests/ui/issues/issue-28971.stderr +++ b/tests/ui/issues/issue-28971.stderr @@ -5,10 +5,12 @@ LL | enum Foo { | -------- variant or associated item `Baz` not found for this enum ... LL | Foo::Baz(..) => (), - | ^^^ - | | - | variant or associated item not found in `Foo` - | help: there is a variant with a similar name: `Bar` + | ^^^ variant or associated item not found in `Foo` + | +help: there is a variant with a similar name + | +LL | Foo::Bar(..) => (), + | ~~~ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable --> $DIR/issue-28971.rs:15:5 diff --git a/tests/ui/issues/issue-34209.stderr b/tests/ui/issues/issue-34209.stderr index 41bc60d03dd..4c61d250f52 100644 --- a/tests/ui/issues/issue-34209.stderr +++ b/tests/ui/issues/issue-34209.stderr @@ -5,7 +5,12 @@ LL | enum S { | ------ variant `B` not found here ... LL | S::B {} => {}, - | ^ help: there is a variant with a similar name: `A` + | ^ + | +help: there is a variant with a similar name + | +LL | S::A {} => {}, + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-4736.stderr b/tests/ui/issues/issue-4736.stderr index 146dd1d57ce..c1ae2c47b43 100644 --- a/tests/ui/issues/issue-4736.stderr +++ b/tests/ui/issues/issue-4736.stderr @@ -9,8 +9,8 @@ LL | let z = NonCopyable{ p: () }; | help: `NonCopyable` is a tuple struct, use the appropriate syntax | -LL | let z = NonCopyable(/* fields */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | let z = NonCopyable(/* () */); + | ~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-4935.stderr b/tests/ui/issues/issue-4935.stderr index f18cf66f14d..7ee895d91c7 100644 --- a/tests/ui/issues/issue-4935.stderr +++ b/tests/ui/issues/issue-4935.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | LL | fn main() { foo(5, 6) } - | ^^^ - unexpected argument of type `{integer}` + | ^^^ - unexpected argument #2 of type `{integer}` | note: function defined here --> $DIR/issue-4935.rs:3:4 diff --git a/tests/ui/issues/issue-54410.stderr b/tests/ui/issues/issue-54410.stderr index 7cc67ab72c3..6cc5cd95e2f 100644 --- a/tests/ui/issues/issue-54410.stderr +++ b/tests/ui/issues/issue-54410.stderr @@ -19,7 +19,7 @@ LL | println!("{:p}", unsafe { &symbol }); help: use `addr_of!` instead to create a raw pointer | LL | println!("{:p}", unsafe { addr_of!(symbol) }); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/issues/issue-80607.stderr b/tests/ui/issues/issue-80607.stderr index 20494f319dd..d096910297b 100644 --- a/tests/ui/issues/issue-80607.stderr +++ b/tests/ui/issues/issue-80607.stderr @@ -9,8 +9,8 @@ LL | Enum::V1 { x } | help: `Enum::V1` is a tuple variant, use the appropriate syntax | -LL | Enum::V1(/* fields */) - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | Enum::V1(/* i32 */) + | ~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr index 944fe8aa8e5..192b5eebdaa 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.next.stderr @@ -4,23 +4,27 @@ error[E0275]: overflow evaluating the requirement `Loop == _` LL | impl Loop {} | ^^^^ -error[E0392]: type parameter `T` is never used - --> $DIR/inherent-impls-overflow.rs:14:12 +error: type parameter `T` is only used recursively + --> $DIR/inherent-impls-overflow.rs:14:24 | LL | type Poly0<T> = Poly1<(T,)>; - | ^ unused type parameter + | - ^ + | | + | type parameter must be used non-recursively in the definition | = help: consider removing `T` or referring to it in the body of the type alias - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0392]: type parameter `T` is never used - --> $DIR/inherent-impls-overflow.rs:17:12 +error: type parameter `T` is only used recursively + --> $DIR/inherent-impls-overflow.rs:17:24 | LL | type Poly1<T> = Poly0<(T,)>; - | ^ unused type parameter + | - ^ + | | + | type parameter must be used non-recursively in the definition | = help: consider removing `T` or referring to it in the body of the type alias - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + = note: all type parameters must be used in a non-recursive way in order to constrain their variance error[E0275]: overflow evaluating the requirement `Poly0<()> == _` --> $DIR/inherent-impls-overflow.rs:21:6 @@ -32,5 +36,4 @@ LL | impl Poly0<()> {} error: aborting due to 4 previous errors -Some errors have detailed explanations: E0275, E0392. -For more information about an error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs index 98f0d811a47..1397695a3fe 100644 --- a/tests/ui/lazy-type-alias/inherent-impls-overflow.rs +++ b/tests/ui/lazy-type-alias/inherent-impls-overflow.rs @@ -13,10 +13,10 @@ impl Loop {} type Poly0<T> = Poly1<(T,)>; //[current]~^ ERROR overflow normalizing the type alias `Poly0<(((((((...,),),),),),),)>` -//[next]~^^ ERROR type parameter `T` is never used +//[next]~^^ ERROR type parameter `T` is only used recursively type Poly1<T> = Poly0<(T,)>; //[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` -//[next]~^^ ERROR type parameter `T` is never used +//[next]~^^ ERROR type parameter `T` is only used recursively impl Poly0<()> {} //[current]~^ ERROR overflow normalizing the type alias `Poly1<(((((((...,),),),),),),)>` diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr index 403a8c67ccb..dc18e0f1f7a 100644 --- a/tests/ui/lifetimes/issue-26638.stderr +++ b/tests/ui/lifetimes/issue-26638.stderr @@ -50,7 +50,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-26638.rs:4:47 | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } - | ^^^^-- an argument of type `&u8` is missing + | ^^^^-- argument #1 of type `&u8` is missing | help: provide the argument | diff --git a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr index f8d919fd68b..4ea14cdf042 100644 --- a/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr +++ b/tests/ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.stderr @@ -6,8 +6,9 @@ LL | fn bar(foo: Foo<Target = usize>) {} | help: consider removing this associated item binding | -LL | fn bar(foo: Foo<Target = usize>) {} - | ~~~~~~~~~~~~~~~~ +LL - fn bar(foo: Foo<Target = usize>) {} +LL + fn bar(foo: Foo) {} + | error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/issue-95023.rs b/tests/ui/lifetimes/issue-95023.rs index 7a67297c763..bcacd01474f 100644 --- a/tests/ui/lifetimes/issue-95023.rs +++ b/tests/ui/lifetimes/issue-95023.rs @@ -9,6 +9,5 @@ impl Fn(&isize) for Error { //~^ ERROR associated function in `impl` without body //~^^ ERROR method `foo` is not a member of trait `Fn` [E0407] //~^^^ ERROR associated type `B` not found for `Self` [E0220] - //~| ERROR associated type `B` not found for `Self` [E0220] } fn main() {} diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index 310dee51406..cbc0eeebee1 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -56,15 +56,7 @@ error[E0220]: associated type `B` not found for `Self` LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>; | ^ help: `Self` has the following associated type: `Output` -error[E0220]: associated type `B` not found for `Self` - --> $DIR/issue-95023.rs:8:44 - | -LL | fn foo<const N: usize>(&self) -> Self::B<{ N }>; - | ^ help: `Self` has the following associated type: `Output` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0046, E0183, E0220, E0229, E0277, E0407. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/macros/builtin-std-paths-fail.stderr b/tests/ui/macros/builtin-std-paths-fail.stderr index 331943843c0..49034c3987b 100644 --- a/tests/ui/macros/builtin-std-paths-fail.stderr +++ b/tests/ui/macros/builtin-std-paths-fail.stderr @@ -104,6 +104,8 @@ LL | #[std::test] | note: found an item that was configured out --> $SRC_DIR/std/src/lib.rs:LL:COL +note: the item is gated here + --> $SRC_DIR/std/src/lib.rs:LL:COL error: aborting due to 16 previous errors diff --git a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs index 1acefa314aa..695a752fe17 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/allowed-operations.rs @@ -1,6 +1,6 @@ //@ run-pass -#![allow(dead_code, non_camel_case_types, non_upper_case_globals)] +#![allow(dead_code, non_camel_case_types, non_upper_case_globals, unused_variables)] #![feature(macro_metavar_expr_concat)] macro_rules! create_things { @@ -37,13 +37,58 @@ macro_rules! without_dollar_sign_is_an_ident { }; } -macro_rules! literals { - ($ident:ident) => {{ - let ${concat(_a, "_b")}: () = (); - let ${concat("_b", _a)}: () = (); +macro_rules! combinations { + ($ident:ident, $literal:literal, $tt_ident:tt, $tt_literal:tt) => {{ + // tt ident + let ${concat($tt_ident, b)} = (); + let ${concat($tt_ident, _b)} = (); + let ${concat($tt_ident, "b")} = (); + let ${concat($tt_ident, $tt_ident)} = (); + let ${concat($tt_ident, $tt_literal)} = (); + let ${concat($tt_ident, $ident)} = (); + let ${concat($tt_ident, $literal)} = (); + // tt literal + let ${concat($tt_literal, b)} = (); + let ${concat($tt_literal, _b)} = (); + let ${concat($tt_literal, "b")} = (); + let ${concat($tt_literal, $tt_ident)} = (); + let ${concat($tt_literal, $tt_literal)} = (); + let ${concat($tt_literal, $ident)} = (); + let ${concat($tt_literal, $literal)} = (); - let ${concat($ident, "_b")}: () = (); - let ${concat("_b", $ident)}: () = (); + // ident (adhoc) + let ${concat(_b, b)} = (); + let ${concat(_b, _b)} = (); + let ${concat(_b, "b")} = (); + let ${concat(_b, $tt_ident)} = (); + let ${concat(_b, $tt_literal)} = (); + let ${concat(_b, $ident)} = (); + let ${concat(_b, $literal)} = (); + // ident (param) + let ${concat($ident, b)} = (); + let ${concat($ident, _b)} = (); + let ${concat($ident, "b")} = (); + let ${concat($ident, $tt_ident)} = (); + let ${concat($ident, $tt_literal)} = (); + let ${concat($ident, $ident)} = (); + let ${concat($ident, $literal)} = (); + + // literal (adhoc) + let ${concat("a", b)} = (); + let ${concat("a", _b)} = (); + let ${concat("a", "b")} = (); + let ${concat("a", $tt_ident)} = (); + let ${concat("a", $tt_literal)} = (); + let ${concat("a", $ident)} = (); + let ${concat("a", $literal)} = (); + // literal (param) + let ${concat($literal, b)} = (); + let ${concat($literal, _b)} = (); + let ${concat($literal, "b")} = (); + let ${concat($literal, $tt_ident)} = (); + let ${concat($literal, $tt_literal)} = (); + let ${concat($literal, $ident)} = (); + let ${concat($literal, $literal)} = (); }}; } @@ -66,5 +111,5 @@ fn main() { assert_eq!(VARident, 1); assert_eq!(VAR_123, 2); - literals!(_hello); + combinations!(_hello, "a", b, "b"); } diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs index b2845c8d1c1..7673bd3200f 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.rs @@ -20,7 +20,7 @@ macro_rules! wrong_concat_declarations { //~^ ERROR `concat` must have at least two elements ${concat($ex, aaaa)} - //~^ ERROR `${concat(..)}` currently only accepts identifiers + //~^ ERROR metavariables of `${concat(..)}` must be of type ${concat($ex, aaaa 123)} //~^ ERROR expected comma @@ -98,6 +98,39 @@ macro_rules! unsupported_literals { }}; } +macro_rules! bad_literal_string { + ($literal:literal) => { + const ${concat(_foo, $literal)}: () = (); + //~^ ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + //~| ERROR `${concat(..)}` is not generating a valid identifier + } +} + +macro_rules! bad_literal_non_string { + ($literal:literal) => { + const ${concat(_foo, $literal)}: () = (); + //~^ 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 metavariables of `${concat(..)}` must be of type + } +} + +macro_rules! bad_tt_literal { + ($tt:tt) => { + 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 + } +} + fn main() { wrong_concat_declarations!(1); @@ -113,4 +146,23 @@ fn main() { unsupported_literals!(_abc); empty!(); + + bad_literal_string!("\u{00BD}"); + bad_literal_string!("\x41"); + bad_literal_string!("🤷"); + bad_literal_string!("d[-_-]b"); + + bad_literal_string!("-1"); + 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_tt_literal!(1); + bad_tt_literal!(1.0); + bad_tt_literal!('1'); } diff --git a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr index 2fe5842b39e..2de6d2b3ce3 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/syntax-errors.stderr @@ -64,11 +64,13 @@ error: expected identifier or string literal LL | let ${concat($ident, 1)}: () = (); | ^ -error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters +error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` --> $DIR/syntax-errors.rs:22:19 | LL | ${concat($ex, aaaa)} | ^^ + | + = note: currently only string literals are supported error: variable `foo` is not recognized in meta-variable expression --> $DIR/syntax-errors.rs:35:30 @@ -131,5 +133,152 @@ LL | empty!(); | = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 18 previous errors +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("\u{00BD}"); + | ------------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("\x41"); + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("🤷"); + | ------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("d[-_-]b"); + | ------------------------------ in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("-1"); + | ------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("1.0"); + | -------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `${concat(..)}` is not generating a valid identifier + --> $DIR/syntax-errors.rs:103:16 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | bad_literal_string!("'1'"); + | -------------------------- in this macro invocation + | + = note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` + --> $DIR/syntax-errors.rs:116:31 + | +LL | const ${concat(_foo, $literal)}: () = (); + | ^^^^^^^ + | + = note: currently only string literals are supported + +error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` + --> $DIR/syntax-errors.rs:116:31 + | +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/syntax-errors.rs:116:31 + | +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/syntax-errors.rs:116:31 + | +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/syntax-errors.rs:116:31 + | +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/syntax-errors.rs:127:31 + | +LL | const ${concat(_foo, $tt)}: () = (); + | ^^ + | + = note: currently only string literals are supported + +error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt` + --> $DIR/syntax-errors.rs:127:31 + | +LL | const ${concat(_foo, $tt)}: () = (); + | ^^ + | + = 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/syntax-errors.rs:127:31 + | +LL | const ${concat(_foo, $tt)}: () = (); + | ^^ + | + = note: currently only string literals are supported + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 33 previous errors diff --git a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs index b2cfb211e2d..4eeb2384deb 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/unicode-expansion.rs @@ -3,12 +3,17 @@ #![feature(macro_metavar_expr_concat)] macro_rules! turn_to_page { - ($ident:ident) => { + ($ident:ident, $literal:literal, $tt:tt) => { const ${concat("Ḧ", $ident)}: i32 = 394; + const ${concat("Ḧ", $literal)}: i32 = 394; + const ${concat("Ḧ", $tt)}: i32 = 394; }; } fn main() { - turn_to_page!(P); - assert_eq!(ḦP, 394); + turn_to_page!(P1, "Ṕ2", Ṕ); + assert_eq!(ḦṔ, 394); + assert_eq!(ḦP1, 394); + assert_eq!(ḦṔ2, 394); + } diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr index 87c0655a422..a8809f3fcff 100644 --- a/tests/ui/macros/macro-outer-attributes.stderr +++ b/tests/ui/macros/macro-outer-attributes.stderr @@ -9,6 +9,17 @@ note: found an item that was configured out | LL | pub fn bar() { }); | ^^^ +note: the item is gated here + --> $DIR/macro-outer-attributes.rs:5:45 + | +LL | $i:item) => (mod $nm { #[$a] $i }); } + | ^^^^^ +LL | +LL | / test!(a, +LL | | #[cfg(FALSE)], +LL | | pub fn bar() { }); + | |_______________________- in this macro invocation + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this function | LL + use b::bar; diff --git a/tests/ui/methods/filter-relevant-fn-bounds.rs b/tests/ui/methods/filter-relevant-fn-bounds.rs new file mode 100644 index 00000000000..76ececf7baa --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.rs @@ -0,0 +1,23 @@ +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper<O, F>(self, _: F) + //~^ ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> F: Output<'a>` is not satisfied + where + F: for<'a> FnOnce(<F as Output<'a>>::Type), + //~^ ERROR the trait bound `F: Output<'_>` is not satisfied + //~| ERROR the trait bound `F: Output<'_>` is not satisfied + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); + //~^ ERROR expected a `FnOnce +} diff --git a/tests/ui/methods/filter-relevant-fn-bounds.stderr b/tests/ui/methods/filter-relevant-fn-bounds.stderr new file mode 100644 index 00000000000..b737c0ab11f --- /dev/null +++ b/tests/ui/methods/filter-relevant-fn-bounds.stderr @@ -0,0 +1,74 @@ +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:5 + | +LL | / fn do_something_wrapper<O, F>(self, _: F) +LL | | +LL | | +LL | | where +LL | | F: for<'a> FnOnce(<F as Output<'a>>::Type), + | |___________________________________________________^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `for<'a> F: Output<'a>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:8:8 + | +LL | fn do_something_wrapper<O, F>(self, _: F) + | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Output<'a>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + for<'a> Output<'a>, + | ++++++++++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: the trait bound `F: Output<'_>` is not satisfied + --> $DIR/filter-relevant-fn-bounds.rs:12:20 + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Output<'_>` is not implemented for `F` + | +help: consider further restricting this bound + | +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type) + Output<'_>, + | ++++++++++++ + +error[E0277]: expected a `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + --> $DIR/filter-relevant-fn-bounds.rs:21:34 + | +LL | wrapper.do_something_wrapper(|value| ()); + | -------------------- ^^^^^^^^^^ expected an `FnOnce(<{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41} as Output<'a>>::Type)` closure, found `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> Output<'a>` is not implemented for closure `{closure@$DIR/filter-relevant-fn-bounds.rs:21:34: 21:41}` +help: this trait has no implementations, consider adding one + --> $DIR/filter-relevant-fn-bounds.rs:1:1 + | +LL | trait Output<'a> { + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Wrapper::do_something_wrapper` + --> $DIR/filter-relevant-fn-bounds.rs:12:12 + | +LL | fn do_something_wrapper<O, F>(self, _: F) + | -------------------- required by a bound in this associated function +... +LL | F: for<'a> FnOnce(<F as Output<'a>>::Type), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Wrapper::do_something_wrapper` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index 0855a17b333..84005119a87 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -19,7 +19,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 | LL | .one() - | ^^^-- an argument of type `isize` is missing + | ^^^-- argument #1 of type `isize` is missing | note: method defined here --> $DIR/method-call-err-msg.rs:6:8 @@ -35,7 +35,7 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 | LL | .two(0); - | ^^^--- an argument of type `isize` is missing + | ^^^--- argument #2 of type `isize` is missing | note: method defined here --> $DIR/method-call-err-msg.rs:7:8 diff --git a/tests/ui/mismatched_types/overloaded-calls-bad.stderr b/tests/ui/mismatched_types/overloaded-calls-bad.stderr index cd483e7ad2c..c52fa713615 100644 --- a/tests/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/tests/ui/mismatched_types/overloaded-calls-bad.stderr @@ -16,7 +16,7 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:35:15 | LL | let ans = s(); - | ^-- an argument of type `isize` is missing + | ^-- argument #1 of type `isize` is missing | note: implementation defined here --> $DIR/overloaded-calls-bad.rs:10:1 @@ -32,7 +32,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:37:15 | LL | let ans = s("burma", "shave"); - | ^ ------- ------- unexpected argument of type `&'static str` + | ^ ------- ------- unexpected argument #2 of type `&'static str` | | | expected `isize`, found `&str` | diff --git a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr index 82065cc06ea..a6d4f9a2a5c 100644 --- a/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr +++ b/tests/ui/nll/borrowck-thread-local-static-mut-borrow-outlives-fn.stderr @@ -11,7 +11,7 @@ LL | S1 { a: unsafe { &mut X1 } } help: use `addr_of_mut!` instead to create a raw pointer | LL | S1 { a: unsafe { addr_of_mut!(X1) } } - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/not-enough-arguments.stderr b/tests/ui/not-enough-arguments.stderr index 8b2dafb4e1d..89e98866667 100644 --- a/tests/ui/not-enough-arguments.stderr +++ b/tests/ui/not-enough-arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 4 arguments but 3 arguments were supplied --> $DIR/not-enough-arguments.rs:27:3 | LL | foo(1, 2, 3); - | ^^^--------- an argument of type `isize` is missing + | ^^^--------- argument #4 of type `isize` is missing | note: function defined here --> $DIR/not-enough-arguments.rs:5:4 diff --git a/tests/ui/numeric/numeric-fields.stderr b/tests/ui/numeric/numeric-fields.stderr index 668405ed638..8ab1718ff5e 100644 --- a/tests/ui/numeric/numeric-fields.stderr +++ b/tests/ui/numeric/numeric-fields.stderr @@ -9,8 +9,8 @@ LL | let s = S{0b1: 10, 0: 11}; | help: `S` is a tuple struct, use the appropriate syntax | -LL | let s = S(/* fields */); - | ~~~~~~~~~~~~~~~ +LL | let s = S(/* u8 */, /* u16 */); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0026]: struct `S` does not have a field named `0x1` --> $DIR/numeric-fields.rs:7:17 diff --git a/tests/ui/parser/cfg-keyword-lifetime.rs b/tests/ui/parser/cfg-keyword-lifetime.rs new file mode 100644 index 00000000000..a1588eddc07 --- /dev/null +++ b/tests/ui/parser/cfg-keyword-lifetime.rs @@ -0,0 +1,15 @@ +// Disallow `'keyword` even in cfg'd code. + +#[cfg(any())] +fn hello() -> &'ref () {} +//~^ ERROR lifetimes cannot use keyword names + +macro_rules! macro_invocation { + ($i:item) => {} +} +macro_invocation! { + fn hello() -> &'ref () {} + //~^ ERROR lifetimes cannot use keyword names +} + +fn main() {} diff --git a/tests/ui/parser/cfg-keyword-lifetime.stderr b/tests/ui/parser/cfg-keyword-lifetime.stderr new file mode 100644 index 00000000000..52d305e2521 --- /dev/null +++ b/tests/ui/parser/cfg-keyword-lifetime.stderr @@ -0,0 +1,14 @@ +error: lifetimes cannot use keyword names + --> $DIR/cfg-keyword-lifetime.rs:4:16 + | +LL | fn hello() -> &'ref () {} + | ^^^^ + +error: lifetimes cannot use keyword names + --> $DIR/cfg-keyword-lifetime.rs:11:20 + | +LL | fn hello() -> &'ref () {} + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issues/issue-101477-enum.stderr b/tests/ui/parser/issues/issue-101477-enum.stderr index c6dadeab8b3..8d4efdd17f7 100644 --- a/tests/ui/parser/issues/issue-101477-enum.stderr +++ b/tests/ui/parser/issues/issue-101477-enum.stderr @@ -7,9 +7,8 @@ LL | B == 2 = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` help: try using `=` instead | -LL - B == 2 -LL + B = 2 - | +LL | B = 2 + | ~ error: expected item, found `==` --> $DIR/issue-101477-enum.rs:6:7 diff --git a/tests/ui/parser/issues/issue-101477-let.stderr b/tests/ui/parser/issues/issue-101477-let.stderr index 59e90c8102f..d2671abbdea 100644 --- a/tests/ui/parser/issues/issue-101477-let.stderr +++ b/tests/ui/parser/issues/issue-101477-let.stderr @@ -6,9 +6,8 @@ LL | let x == 2; | help: try using `=` instead | -LL - let x == 2; -LL + let x = 2; - | +LL | let x = 2; + | ~ error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs new file mode 100644 index 00000000000..722303dd034 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.rs @@ -0,0 +1,5 @@ +fn foo<T>() where T: Default -> impl Default + 'static {} +//~^ ERROR return type should be specified after the function parameters +//~| HELP place the return type after the function parameters + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr new file mode 100644 index 00000000000..2ce3b78bb8b --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-complex-type-issue-126311.stderr @@ -0,0 +1,14 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-complex-type-issue-126311.rs:1:30 + | +LL | fn foo<T>() where T: Default -> impl Default + 'static {} + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + | +help: place the return type after the function parameters + | +LL - fn foo<T>() where T: Default -> impl Default + 'static {} +LL + fn foo<T>() -> impl Default + 'static where T: Default {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs new file mode 100644 index 00000000000..ad164f77bee --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-issue-126311.rs @@ -0,0 +1,5 @@ +fn foo<T>() where T: Default -> u8 {} +//~^ ERROR return type should be specified after the function parameters +//~| HELP place the return type after the function parameters + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr new file mode 100644 index 00000000000..e473b902ce3 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-issue-126311.stderr @@ -0,0 +1,14 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-issue-126311.rs:1:30 + | +LL | fn foo<T>() where T: Default -> u8 {} + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + | +help: place the return type after the function parameters + | +LL - fn foo<T>() where T: Default -> u8 {} +LL + fn foo<T>() -> u8 where T: Default {} + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs new file mode 100644 index 00000000000..782d7d5ee49 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.rs @@ -0,0 +1,11 @@ +fn foo<T, K>() +//~^ HELP place the return type after the function parameters +where + T: Default, + K: Clone, -> Result<u8, String> +//~^ ERROR return type should be specified after the function parameters +{ + Ok(0) +} + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr new file mode 100644 index 00000000000..196a46d7ea5 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-where-in-next-line-issue-126311.stderr @@ -0,0 +1,17 @@ +error: return type should be specified after the function parameters + --> $DIR/misplaced-return-type-where-in-next-line-issue-126311.rs:5:15 + | +LL | K: Clone, -> Result<u8, String> + | ^^ expected one of `{`, lifetime, or type + | +help: place the return type after the function parameters + | +LL ~ fn foo<T, K>() -> Result<u8, String> +LL | +LL | where +LL | T: Default, +LL ~ K: Clone, + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs new file mode 100644 index 00000000000..2c09edbc792 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.rs @@ -0,0 +1,6 @@ +fn foo<T>() where T: Default -> { +//~^ ERROR expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->` + 0 +} + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr new file mode 100644 index 00000000000..0eb3bb7d812 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-type-issue-126311.stderr @@ -0,0 +1,8 @@ +error: expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `->` + --> $DIR/misplaced-return-type-without-type-issue-126311.rs:1:30 + | +LL | fn foo<T>() where T: Default -> { + | ^^ expected one of `(`, `+`, `,`, `::`, `<`, or `{` + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs new file mode 100644 index 00000000000..672233674a0 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.rs @@ -0,0 +1,4 @@ +fn bar<T>() -> u8 -> u64 {} +//~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `->` + +fn main() {} diff --git a/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr new file mode 100644 index 00000000000..730904d3671 --- /dev/null +++ b/tests/ui/parser/issues/misplaced-return-type-without-where-issue-126311.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `->` + --> $DIR/misplaced-return-type-without-where-issue-126311.rs:1:19 + | +LL | fn bar<T>() -> u8 -> u64 {} + | ^^ expected one of 7 possible tokens + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/recover/unicode-double-equals-recovery.rs b/tests/ui/parser/recover/unicode-double-equals-recovery.rs new file mode 100644 index 00000000000..589f0a559bb --- /dev/null +++ b/tests/ui/parser/recover/unicode-double-equals-recovery.rs @@ -0,0 +1,3 @@ +const A: usize ⩵ 2; +//~^ ERROR unknown start of token: \u{2a75} +//~| ERROR unexpected `==` diff --git a/tests/ui/parser/recover/unicode-double-equals-recovery.stderr b/tests/ui/parser/recover/unicode-double-equals-recovery.stderr new file mode 100644 index 00000000000..6e10dcce04a --- /dev/null +++ b/tests/ui/parser/recover/unicode-double-equals-recovery.stderr @@ -0,0 +1,24 @@ +error: unknown start of token: \u{2a75} + --> $DIR/unicode-double-equals-recovery.rs:1:16 + | +LL | const A: usize ⩵ 2; + | ^ + | +help: Unicode character '⩵' (Two Consecutive Equals Signs) looks like '==' (Double Equals Sign), but it is not + | +LL | const A: usize == 2; + | ~~ + +error: unexpected `==` + --> $DIR/unicode-double-equals-recovery.rs:1:16 + | +LL | const A: usize ⩵ 2; + | ^ + | +help: try using `=` instead + | +LL | const A: usize = 2; + | ~ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/require-parens-for-chained-comparison.rs b/tests/ui/parser/require-parens-for-chained-comparison.rs index 5b90e905a64..916f1b83db2 100644 --- a/tests/ui/parser/require-parens-for-chained-comparison.rs +++ b/tests/ui/parser/require-parens-for-chained-comparison.rs @@ -24,12 +24,14 @@ fn main() { //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| ERROR expected //~| HELP add `'` to close the char literal + //~| ERROR invalid label name f<'_>(); //~^ comparison operators cannot be chained //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| ERROR expected //~| HELP add `'` to close the char literal + //~| ERROR invalid label name let _ = f<u8>; //~^ ERROR comparison operators cannot be chained diff --git a/tests/ui/parser/require-parens-for-chained-comparison.stderr b/tests/ui/parser/require-parens-for-chained-comparison.stderr index 52e201c435c..857c4a55788 100644 --- a/tests/ui/parser/require-parens-for-chained-comparison.stderr +++ b/tests/ui/parser/require-parens-for-chained-comparison.stderr @@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::<u8, i8>(); | ++ +error: invalid label name `'_` + --> $DIR/require-parens-for-chained-comparison.rs:22:15 + | +LL | let _ = f<'_, i8>(); + | ^^ + error: expected `while`, `for`, `loop` or `{` after a label --> $DIR/require-parens-for-chained-comparison.rs:22:17 | @@ -75,8 +81,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::<'_, i8>(); | ++ +error: invalid label name `'_` + --> $DIR/require-parens-for-chained-comparison.rs:29:7 + | +LL | f<'_>(); + | ^^ + error: expected `while`, `for`, `loop` or `{` after a label - --> $DIR/require-parens-for-chained-comparison.rs:28:9 + --> $DIR/require-parens-for-chained-comparison.rs:29:9 | LL | f<'_>(); | ^ expected `while`, `for`, `loop` or `{` after a label @@ -87,7 +99,7 @@ LL | f<'_'>(); | + error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:28:6 + --> $DIR/require-parens-for-chained-comparison.rs:29:6 | LL | f<'_>(); | ^ ^ @@ -98,7 +110,7 @@ LL | f::<'_>(); | ++ error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:34:14 + --> $DIR/require-parens-for-chained-comparison.rs:36:14 | LL | let _ = f<u8>; | ^ ^ @@ -106,5 +118,5 @@ LL | let _ = f<u8>; = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments = help: or use `(...)` if you meant to specify fn arguments -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/parser/struct-literal-variant-in-if.stderr b/tests/ui/parser/struct-literal-variant-in-if.stderr index 9f0c0074d67..15f059f145b 100644 --- a/tests/ui/parser/struct-literal-variant-in-if.stderr +++ b/tests/ui/parser/struct-literal-variant-in-if.stderr @@ -47,6 +47,11 @@ error[E0533]: expected value, found struct variant `E::V` | LL | if x == E::V { field } {} | ^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | if x == (E::V { field }) {} + | + + error[E0308]: mismatched types --> $DIR/struct-literal-variant-in-if.rs:10:20 diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs deleted file mode 100644 index 95ead6b5d4a..00000000000 --- a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.rs +++ /dev/null @@ -1,26 +0,0 @@ -pub enum EFoo { - A, -} - -pub trait Foo { - const X: EFoo; -} - -struct Abc; - -impl Foo for Abc { - const X: EFoo = EFoo::A; -} - -struct Def; -impl Foo for Def { - const X: EFoo = EFoo::A; -} - -pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { - //~^ ERROR associated consts cannot be referenced in patterns - let A::X = arg; - //~^ ERROR associated consts cannot be referenced in patterns -} - -fn main() {} diff --git a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr b/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr deleted file mode 100644 index 62c90b638d7..00000000000 --- a/tests/ui/pattern/issue-68393-let-pat-assoc-constant.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0158]: associated consts cannot be referenced in patterns - --> $DIR/issue-68393-let-pat-assoc-constant.rs:22:9 - | -LL | let A::X = arg; - | ^^^^ - -error[E0158]: associated consts cannot be referenced in patterns - --> $DIR/issue-68393-let-pat-assoc-constant.rs:20:40 - | -LL | pub fn test<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) { - | ^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0158`. diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr index 915d07fd08a..8ab6e83641d 100644 --- a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr +++ b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr @@ -29,7 +29,7 @@ LL | pub use core as reexported_core; | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> + = note: for more information, see issue #127909 <https://github.com/rust-lang/rust/issues/127909> = note: `#[deny(pub_use_of_private_extern_crate)]` on by default help: consider making the `extern crate` item publicly accessible | @@ -40,3 +40,18 @@ error: aborting due to 3 previous errors Some errors have detailed explanations: E0365, E0603. For more information about an error, try `rustc --explain E0365`. +Future incompatibility report: Future breakage diagnostic: +error[E0365]: extern crate `core` is private and cannot be re-exported + --> $DIR/pub-reexport-priv-extern-crate.rs:2:9 + | +LL | pub use core as reexported_core; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #127909 <https://github.com/rust-lang/rust/issues/127909> + = note: `#[deny(pub_use_of_private_extern_crate)]` on by default +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ + diff --git a/tests/ui/resolve/issue-18252.stderr b/tests/ui/resolve/issue-18252.stderr index 511b8da716f..6cb9c1f1dd2 100644 --- a/tests/ui/resolve/issue-18252.stderr +++ b/tests/ui/resolve/issue-18252.stderr @@ -3,6 +3,11 @@ error[E0533]: expected value, found struct variant `Foo::Variant` | LL | let f = Foo::Variant(42); | ^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let f = Foo::Variant { x: /* value */ }; + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-19452.stderr b/tests/ui/resolve/issue-19452.stderr index eff89241fd2..aa7b752ca50 100644 --- a/tests/ui/resolve/issue-19452.stderr +++ b/tests/ui/resolve/issue-19452.stderr @@ -3,12 +3,22 @@ error[E0533]: expected value, found struct variant `Homura::Madoka` | LL | let homura = Homura::Madoka; | ^^^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let homura = Homura::Madoka { age: /* value */ }; + | ++++++++++++++++++++ error[E0533]: expected value, found struct variant `issue_19452_aux::Homura::Madoka` --> $DIR/issue-19452.rs:13:18 | LL | let homura = issue_19452_aux::Homura::Madoka; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let homura = issue_19452_aux::Homura::Madoka { age: /* value */ }; + | ++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index ee3aecddcc3..12a6580048e 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -295,6 +295,11 @@ error[E0533]: expected value, found struct variant `Z::Struct` | LL | let _: Z = Z::Struct; | ^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let _: Z = Z::Struct { s: /* value */ }; + | ++++++++++++++++++ error[E0618]: expected function, found enum variant `Z::Unit` --> $DIR/privacy-enum-ctor.rs:31:17 @@ -336,6 +341,11 @@ error[E0533]: expected value, found struct variant `m::E::Struct` | LL | let _: E = m::E::Struct; | ^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let _: E = m::E::Struct { s: /* value */ }; + | ++++++++++++++++++ error[E0618]: expected function, found enum variant `m::E::Unit` --> $DIR/privacy-enum-ctor.rs:47:16 @@ -377,6 +387,11 @@ error[E0533]: expected value, found struct variant `E::Struct` | LL | let _: E = E::Struct; | ^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let _: E = E::Struct { s: /* value */ }; + | ++++++++++++++++++ error[E0618]: expected function, found enum variant `E::Unit` --> $DIR/privacy-enum-ctor.rs:55:16 @@ -400,6 +415,11 @@ error[E0533]: expected value, found struct variant `m::n::Z::Struct` | LL | let _: Z = m::n::Z::Struct; | ^^^^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let _: Z = m::n::Z::Struct { s: /* value */ }; + | ++++++++++++++++++ error: aborting due to 23 previous errors diff --git a/tests/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr b/tests/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr index e22e636adb6..a8d0efedb6c 100644 --- a/tests/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr +++ b/tests/ui/resolve/resolve-conflict-import-vs-extern-crate.stderr @@ -8,7 +8,7 @@ LL | use std::slice as std; help: you can use `as` to change the binding name of the import | LL | use std::slice as other_std; - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/resolve/resolve-conflict-item-vs-import.stderr b/tests/ui/resolve/resolve-conflict-item-vs-import.stderr index 3b1b5f1ad00..a8b16009c55 100644 --- a/tests/ui/resolve/resolve-conflict-item-vs-import.stderr +++ b/tests/ui/resolve/resolve-conflict-item-vs-import.stderr @@ -11,7 +11,7 @@ LL | fn transmute() {} help: you can use `as` to change the binding name of the import | LL | use std::mem::transmute as other_transmute; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/resolve/resolve-conflict-type-vs-import.stderr b/tests/ui/resolve/resolve-conflict-type-vs-import.stderr index c5cb4e07862..241e48d0cd5 100644 --- a/tests/ui/resolve/resolve-conflict-type-vs-import.stderr +++ b/tests/ui/resolve/resolve-conflict-type-vs-import.stderr @@ -11,7 +11,7 @@ LL | struct Iter; help: you can use `as` to change the binding name of the import | LL | use std::slice::Iter as OtherIter; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs index c69fe145f77..c01f8934c75 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs @@ -13,7 +13,7 @@ const A: &[B] = &[]; pub fn main() { match &[][..] { A => (), - //~^ ERROR must be annotated with `#[derive(PartialEq)]` + //~^ ERROR must implement `PartialEq` _ => (), } } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr index 02e2bab4d0a..736e4c30c8a 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr @@ -1,11 +1,8 @@ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]` +error: to use a constant of type `&[B]` in a pattern, the type must implement `PartialEq` --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9 | LL | A => (), | ^ - | - = note: the traits must be derived, manual `impl`s are not sufficient - = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs index 6d6a336e688..f343013f2b0 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs @@ -28,13 +28,9 @@ fn main() { // Also cover range patterns match x { NAN..=1.0 => {}, //~ ERROR cannot use NaN in patterns - //~^ ERROR lower range bound must be less than or equal to upper -1.0..=NAN => {}, //~ ERROR cannot use NaN in patterns - //~^ ERROR lower range bound must be less than or equal to upper NAN.. => {}, //~ ERROR cannot use NaN in patterns - //~^ ERROR lower range bound must be less than or equal to upper ..NAN => {}, //~ ERROR cannot use NaN in patterns - //~^ ERROR lower range bound must be less than upper _ => {}, }; } diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr index baca1d75048..44b05ea31e9 100644 --- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr +++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr @@ -34,14 +34,8 @@ LL | NAN..=1.0 => {}, = note: NaNs compare inequal to everything, even themselves, so this pattern would never match = help: try using the `is_nan` method instead -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/issue-6804-nan-match.rs:30:9 - | -LL | NAN..=1.0 => {}, - | ^^^^^^^^^ lower bound larger than upper bound - error: cannot use NaN in patterns - --> $DIR/issue-6804-nan-match.rs:32:16 + --> $DIR/issue-6804-nan-match.rs:31:16 | LL | -1.0..=NAN => {}, | ^^^ @@ -49,14 +43,8 @@ LL | -1.0..=NAN => {}, = note: NaNs compare inequal to everything, even themselves, so this pattern would never match = help: try using the `is_nan` method instead -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/issue-6804-nan-match.rs:32:9 - | -LL | -1.0..=NAN => {}, - | ^^^^^^^^^^ lower bound larger than upper bound - error: cannot use NaN in patterns - --> $DIR/issue-6804-nan-match.rs:34:9 + --> $DIR/issue-6804-nan-match.rs:32:9 | LL | NAN.. => {}, | ^^^ @@ -64,14 +52,8 @@ LL | NAN.. => {}, = note: NaNs compare inequal to everything, even themselves, so this pattern would never match = help: try using the `is_nan` method instead -error[E0030]: lower range bound must be less than or equal to upper - --> $DIR/issue-6804-nan-match.rs:34:9 - | -LL | NAN.. => {}, - | ^^^^^ lower bound larger than upper bound - error: cannot use NaN in patterns - --> $DIR/issue-6804-nan-match.rs:36:11 + --> $DIR/issue-6804-nan-match.rs:33:11 | LL | ..NAN => {}, | ^^^ @@ -79,13 +61,5 @@ LL | ..NAN => {}, = note: NaNs compare inequal to everything, even themselves, so this pattern would never match = help: try using the `is_nan` method instead -error[E0579]: lower range bound must be less than upper - --> $DIR/issue-6804-nan-match.rs:36:9 - | -LL | ..NAN => {}, - | ^^^^^ - -error: aborting due to 11 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0030, E0579. -For more information about an error, try `rustc --explain E0030`. diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr index c2b9899e20d..f515cb62c7c 100644 --- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr +++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr @@ -9,6 +9,10 @@ LL | let _ = dbg!(a); | ^^^^^^^ value used here after move | = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing instead of transferring ownership + | +LL | let _ = dbg!(&a); + | + error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr index 4d543f6a155..7db6a77c77b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.stderr @@ -4,20 +4,11 @@ error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#0 LL | fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] { | ^^^^^^^^^^^^^^^^ cannot normalize `process<T>::{constant#0}` -error[E0284]: type annotations needed: cannot satisfy `the constant `T::make(P)` can be evaluated` - --> $DIR/const-trait-bounds.rs:18:5 +error[E0284]: type annotations needed: cannot normalize `Struct<T, P>::field::{constant#0}` + --> $DIR/const-trait-bounds.rs:20:12 | -LL | [u32; T::make(P)]:, - | ^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `T::make(P)` can be evaluated` - | -note: required by a bound in `Struct` - --> $DIR/const-trait-bounds.rs:18:11 - | -LL | struct Struct<T: const Trait, const P: usize> - | ------ required by a bound in this struct -LL | where -LL | [u32; T::make(P)]:, - | ^^^^^^^^^^ required by this bound in `Struct` +LL | field: [u32; T::make(P)], + | ^^^^^^^^^^^^^^^^^ cannot normalize `Struct<T, P>::field::{constant#0}` error[E0284]: type annotations needed: cannot normalize `process<T>::{constant#1}` --> $DIR/const-trait-bounds.rs:13:5 diff --git a/tests/ui/rust-2024/safe-outside-extern.gated.stderr b/tests/ui/rust-2024/safe-outside-extern.gated.stderr index 18a3361f35b..e0b218281f3 100644 --- a/tests/ui/rust-2024/safe-outside-extern.gated.stderr +++ b/tests/ui/rust-2024/safe-outside-extern.gated.stderr @@ -28,5 +28,11 @@ error: function pointers cannot be declared with `safe` safety qualifier LL | type FnPtr = safe fn(i32, i32) -> i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/safe-outside-extern.rs:28:1 + | +LL | unsafe static LOL: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/tests/ui/rust-2024/safe-outside-extern.rs b/tests/ui/rust-2024/safe-outside-extern.rs index 9ec0c5c70e1..6773df5ef03 100644 --- a/tests/ui/rust-2024/safe-outside-extern.rs +++ b/tests/ui/rust-2024/safe-outside-extern.rs @@ -25,4 +25,7 @@ type FnPtr = safe fn(i32, i32) -> i32; //~^ ERROR: function pointers cannot be declared with `safe` safety qualifier //[ungated]~| ERROR: unsafe extern {}` blocks and `safe` keyword are experimental [E0658] +unsafe static LOL: u8 = 0; +//~^ ERROR: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + fn main() {} diff --git a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr index 9ea6d451e8c..98a4c0eab92 100644 --- a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr +++ b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr @@ -28,6 +28,12 @@ error: function pointers cannot be declared with `safe` safety qualifier LL | type FnPtr = safe fn(i32, i32) -> i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: static items cannot be declared with `unsafe` safety qualifier outside of `extern` block + --> $DIR/safe-outside-extern.rs:28:1 + | +LL | unsafe static LOL: u8 = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental --> $DIR/safe-outside-extern.rs:4:1 | @@ -78,6 +84,6 @@ LL | type FnPtr = safe fn(i32, i32) -> i32; = help: add `#![feature(unsafe_extern_blocks)]` 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 10 previous errors +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/sanitizer/cfi-supertraits.rs b/tests/ui/sanitizer/cfi-supertraits.rs index ed3d722ebb7..4bb6177577f 100644 --- a/tests/ui/sanitizer/cfi-supertraits.rs +++ b/tests/ui/sanitizer/cfi-supertraits.rs @@ -16,6 +16,9 @@ trait Parent1 { type P1; fn p1(&self) -> Self::P1; + fn d(&self) -> i32 { + 42 + } } trait Parent2 { @@ -60,14 +63,17 @@ fn main() { x.c(); x.p1(); x.p2(); + x.d(); // Parents can be created and access their methods. let y = &Foo as &dyn Parent1<P1=u16>; y.p1(); + y.d(); let z = &Foo as &dyn Parent2<P2=u32>; z.p2(); // Trait upcasting works let x1 = x as &dyn Parent1<P1=u16>; x1.p1(); + x1.d(); let x2 = x as &dyn Parent2<P2=u32>; x2.p2(); } diff --git a/tests/ui/self/elision/ignore-non-reference-lifetimes.rs b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs new file mode 100644 index 00000000000..f7f61b8c810 --- /dev/null +++ b/tests/ui/self/elision/ignore-non-reference-lifetimes.rs @@ -0,0 +1,22 @@ +//@ check-pass + +struct Foo<'a>(&'a str); + +impl<'b> Foo<'b> { + fn a<'a>(self: Self, a: &'a str) -> &str { + a + } + fn b<'a>(self: Foo<'b>, a: &'a str) -> &str { + a + } +} + +struct Foo2<'a>(&'a u32); +impl<'a> Foo2<'a> { + fn foo(self: &Self) -> &u32 { self.0 } // ok + fn bar(self: &Foo2<'a>) -> &u32 { self.0 } // ok (do not look into `Foo`) + fn baz2(self: Self, arg: &u32) -> &u32 { arg } // use lt from `arg` + fn baz3(self: Foo2<'a>, arg: &u32) -> &u32 { arg } // use lt from `arg` +} + +fn main() {} diff --git a/tests/ui/self/elision/multiple-ref-self-async.rs b/tests/ui/self/elision/multiple-ref-self-async.rs index fb77f91396c..f63b455901e 100644 --- a/tests/ui/self/elision/multiple-ref-self-async.rs +++ b/tests/ui/self/elision/multiple-ref-self-async.rs @@ -1,4 +1,3 @@ -//@ check-pass //@ edition:2018 #![feature(arbitrary_self_types)] @@ -21,22 +20,27 @@ impl Struct { // Test using multiple `&Self`: async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + //~^ ERROR missing lifetime specifier f } async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } } diff --git a/tests/ui/self/elision/multiple-ref-self-async.stderr b/tests/ui/self/elision/multiple-ref-self-async.stderr new file mode 100644 index 00000000000..e2abc7c1e78 --- /dev/null +++ b/tests/ui/self/elision/multiple-ref-self-async.stderr @@ -0,0 +1,63 @@ +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:22:74 + | +LL | async fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + | ------------------ --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:27:84 + | +LL | async fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:32:84 + | +LL | async fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:37:93 + | +LL | async fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self-async.rs:42:93 + | +LL | async fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | async fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/self/elision/multiple-ref-self.rs b/tests/ui/self/elision/multiple-ref-self.rs index 01d6bb47c04..dd9b138051d 100644 --- a/tests/ui/self/elision/multiple-ref-self.rs +++ b/tests/ui/self/elision/multiple-ref-self.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![feature(arbitrary_self_types)] #![allow(non_snake_case)] @@ -20,22 +18,27 @@ impl Struct { // Test using multiple `&Self`: fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + //~^ ERROR missing lifetime specifier f } fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier f } } diff --git a/tests/ui/self/elision/multiple-ref-self.stderr b/tests/ui/self/elision/multiple-ref-self.stderr new file mode 100644 index 00000000000..24d74d352e4 --- /dev/null +++ b/tests/ui/self/elision/multiple-ref-self.stderr @@ -0,0 +1,63 @@ +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:20:68 + | +LL | fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 { + | ------------------ --- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn wrap_ref_Self_ref_Self<'a>(self: Wrap<&'a Self, &'a Self>, f: &'a u8) -> &'a u8 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:25:78 + | +LL | fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_wrap_ref_Self_ref_Self<'a>(self: Box<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:30:78 + | +LL | fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 { + | ----------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn pin_wrap_ref_Self_ref_Self<'a>(self: Pin<Wrap<&'a Self, &'a Self>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:35:87 + | +LL | fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_box_wrap_ref_Self_ref_Self<'a>(self: Box<Box<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/multiple-ref-self.rs:40:87 + | +LL | fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 { + | ---------------------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn box_pin_wrap_ref_Self_ref_Self<'a>(self: Box<Pin<Wrap<&'a Self, &'a Self>>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/self/elision/no-shadow-pin-self.rs b/tests/ui/self/elision/no-shadow-pin-self.rs new file mode 100644 index 00000000000..e390b869ca7 --- /dev/null +++ b/tests/ui/self/elision/no-shadow-pin-self.rs @@ -0,0 +1,17 @@ +use std::pin::Pin; +trait Trait { + fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + f + } +} + +impl<P> Trait for Pin<P> { + // This should not hide `&Self`, which would cause this to compile. + fn method(self: Pin<&Self>, f: &u32) -> &u32 { + //~^ ERROR `impl` item signature doesn't match `trait` + f + //~^ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/self/elision/no-shadow-pin-self.stderr b/tests/ui/self/elision/no-shadow-pin-self.stderr new file mode 100644 index 00000000000..23485e9de79 --- /dev/null +++ b/tests/ui/self/elision/no-shadow-pin-self.stderr @@ -0,0 +1,32 @@ +error: `impl` item signature doesn't match `trait` item signature + --> $DIR/no-shadow-pin-self.rs:10:5 + | +LL | fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ------------------------------------------------------ expected `fn(Pin<&'1 Pin<P>>, &'a u32) -> &'a u32` +... +LL | fn method(self: Pin<&Self>, f: &u32) -> &u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(Pin<&'1 Pin<P>>, &'2 u32) -> &'1 u32` + | + = note: expected signature `fn(Pin<&'1 Pin<P>>, &'a u32) -> &'a u32` + found signature `fn(Pin<&'1 Pin<P>>, &'2 u32) -> &'1 u32` + = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output + +error: lifetime may not live long enough + --> $DIR/no-shadow-pin-self.rs:12:9 + | +LL | fn method(self: Pin<&Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn method<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/self/elision/ref-assoc-async.rs b/tests/ui/self/elision/ref-assoc-async.rs index 2af4f13a41b..25deb25253d 100644 --- a/tests/ui/self/elision/ref-assoc-async.rs +++ b/tests/ui/self/elision/ref-assoc-async.rs @@ -1,5 +1,4 @@ //@ edition:2018 -//@ check-pass #![allow(non_snake_case)] @@ -18,22 +17,27 @@ impl Trait for Struct { impl Struct { async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/self/elision/ref-assoc-async.stderr b/tests/ui/self/elision/ref-assoc-async.stderr new file mode 100644 index 00000000000..cf54a86b45f --- /dev/null +++ b/tests/ui/self/elision/ref-assoc-async.stderr @@ -0,0 +1,77 @@ +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:19:9 + | +LL | async fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn ref_AssocType<'a>(self: &'a <Struct as Trait>::AssocType, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:24:9 + | +LL | async fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_ref_AssocType<'a>(self: Box<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:29:9 + | +LL | async fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn pin_ref_AssocType<'a>(self: Pin<&'a <Struct as Trait>::AssocType>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:34:9 + | +LL | async fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_box_ref_AssocType<'a>(self: Box<Box<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc-async.rs:39:9 + | +LL | async fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | async fn box_pin_ref_AssocType<'a>(self: Box<Pin<&'a <Struct as Trait>::AssocType>>, f: &'a u32) -> &u32 { + | ++++ ++ ++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/self/elision/ref-assoc.rs b/tests/ui/self/elision/ref-assoc.rs index 8dc78d31d39..01d2556df62 100644 --- a/tests/ui/self/elision/ref-assoc.rs +++ b/tests/ui/self/elision/ref-assoc.rs @@ -1,5 +1,3 @@ -//@ check-pass - #![allow(non_snake_case)] use std::pin::Pin; @@ -17,22 +15,27 @@ impl Trait for Struct { impl Struct { fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { f + //~^ ERROR lifetime may not live long enough } } diff --git a/tests/ui/self/elision/ref-assoc.stderr b/tests/ui/self/elision/ref-assoc.stderr new file mode 100644 index 00000000000..7c8a1de95ae --- /dev/null +++ b/tests/ui/self/elision/ref-assoc.stderr @@ -0,0 +1,77 @@ +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:17:9 + | +LL | fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_AssocType<'a>(self: &<Struct as Trait>::AssocType, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:22:9 + | +LL | fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_ref_AssocType<'a>(self: Box<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:27:9 + | +LL | fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn pin_ref_AssocType<'a>(self: Pin<&<Struct as Trait>::AssocType>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:32:9 + | +LL | fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_box_ref_AssocType<'a>(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: lifetime may not live long enough + --> $DIR/ref-assoc.rs:37:9 + | +LL | fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn box_pin_ref_AssocType<'a>(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/self/elision/ref-self-multi.rs b/tests/ui/self/elision/ref-self-multi.rs new file mode 100644 index 00000000000..ed431a9c852 --- /dev/null +++ b/tests/ui/self/elision/ref-self-multi.rs @@ -0,0 +1,29 @@ +#![feature(arbitrary_self_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +use std::marker::PhantomData; +use std::ops::Deref; + +struct Struct { } + +struct Wrap<T, P>(T, PhantomData<P>); + +impl<T, P> Deref for Wrap<T, P> { + type Target = T; + fn deref(&self) -> &T { &self.0 } +} + +impl Struct { + fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier + f + } + + fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 { + //~^ ERROR missing lifetime specifier + f + } +} + +fn main() { } diff --git a/tests/ui/self/elision/ref-self-multi.stderr b/tests/ui/self/elision/ref-self-multi.stderr new file mode 100644 index 00000000000..7e0451aa0d5 --- /dev/null +++ b/tests/ui/self/elision/ref-self-multi.stderr @@ -0,0 +1,27 @@ +error[E0106]: missing lifetime specifier + --> $DIR/ref-self-multi.rs:18:56 + | +LL | fn ref_box_ref_Self(self: &Box<&Self>, f: &u32) -> &u32 { + | ----------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn ref_box_ref_Self<'a>(self: &'a Box<&'a Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/ref-self-multi.rs:23:63 + | +LL | fn ref_wrap_ref_Self(self: &Wrap<&Self, u32>, f: &u32) -> &u32 { + | ----------------- ---- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from one of `self`'s 2 lifetimes or `f` +help: consider introducing a named lifetime parameter + | +LL | fn ref_wrap_ref_Self<'a>(self: &'a Wrap<&'a Self, u32>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ ++ ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/self/elision/ref-self.fixed b/tests/ui/self/elision/ref-self.fixed index 8bf5a0bb223..784ccb9efe2 100644 --- a/tests/ui/self/elision/ref-self.fixed +++ b/tests/ui/self/elision/ref-self.fixed @@ -1,4 +1,6 @@ //@ run-rustfix +//@ edition:2018 + #![feature(arbitrary_self_types)] #![allow(non_snake_case, dead_code)] @@ -56,6 +58,11 @@ impl Struct { f //~^ ERROR lifetime may not live long enough } + + fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 { + f + //~^ ERROR lifetime may not live long enough + } } fn main() {} diff --git a/tests/ui/self/elision/ref-self.rs b/tests/ui/self/elision/ref-self.rs index 4b4b8aa5b51..dbe441879cc 100644 --- a/tests/ui/self/elision/ref-self.rs +++ b/tests/ui/self/elision/ref-self.rs @@ -1,4 +1,6 @@ //@ run-rustfix +//@ edition:2018 + #![feature(arbitrary_self_types)] #![allow(non_snake_case, dead_code)] @@ -56,6 +58,11 @@ impl Struct { f //~^ ERROR lifetime may not live long enough } + + fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 { + f + //~^ ERROR lifetime may not live long enough + } } fn main() {} diff --git a/tests/ui/self/elision/ref-self.stderr b/tests/ui/self/elision/ref-self.stderr index c4ec8c55a00..64e7bfc1bb0 100644 --- a/tests/ui/self/elision/ref-self.stderr +++ b/tests/ui/self/elision/ref-self.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/ref-self.rs:24:9 + --> $DIR/ref-self.rs:26:9 | LL | fn ref_self(&self, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -14,7 +14,7 @@ LL | fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:31:9 + --> $DIR/ref-self.rs:33:9 | LL | fn ref_Self(self: &Self, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -29,7 +29,7 @@ LL | fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:36:9 + --> $DIR/ref-self.rs:38:9 | LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -44,7 +44,7 @@ LL | fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:41:9 + --> $DIR/ref-self.rs:43:9 | LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -59,7 +59,7 @@ LL | fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:46:9 + --> $DIR/ref-self.rs:48:9 | LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -74,7 +74,7 @@ LL | fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:51:9 + --> $DIR/ref-self.rs:53:9 | LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 { | - - let's call the lifetime of this reference `'1` @@ -89,7 +89,7 @@ LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 { | ++++ ++ ++ error: lifetime may not live long enough - --> $DIR/ref-self.rs:56:9 + --> $DIR/ref-self.rs:58:9 | LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 { | - - let's call the lifetime of this reference `'1` @@ -103,5 +103,20 @@ help: consider introducing a named lifetime parameter and update trait if needed LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 { | ++++ ++ ++ -error: aborting due to 7 previous errors +error: lifetime may not live long enough + --> $DIR/ref-self.rs:63:9 + | +LL | fn ref_box_Self(self: &Box<Self>, f: &u32) -> &u32 { + | - - let's call the lifetime of this reference `'1` + | | + | let's call the lifetime of this reference `'2` +LL | f + | ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + | +help: consider introducing a named lifetime parameter and update trait if needed + | +LL | fn ref_box_Self<'a>(self: &Box<Self>, f: &'a u32) -> &'a u32 { + | ++++ ++ ++ + +error: aborting due to 8 previous errors diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr index 8298293a8cb..f9cde810cad 100644 --- a/tests/ui/self/self_type_keyword.stderr +++ b/tests/ui/self/self_type_keyword.stderr @@ -4,6 +4,12 @@ error: expected identifier, found keyword `Self` LL | struct Self; | ^^^^ expected identifier, found keyword +error: lifetimes cannot use keyword names + --> $DIR/self_type_keyword.rs:6:12 + | +LL | struct Bar<'Self>; + | ^^^^^ + error: expected identifier, found keyword `Self` --> $DIR/self_type_keyword.rs:14:13 | @@ -53,12 +59,6 @@ error: expected identifier, found keyword `Self` LL | trait Self {} | ^^^^ expected identifier, found keyword -error: lifetimes cannot use keyword names - --> $DIR/self_type_keyword.rs:6:12 - | -LL | struct Bar<'Self>; - | ^^^^^ - error: cannot find macro `Self` in this scope --> $DIR/self_type_keyword.rs:21:9 | diff --git a/tests/ui/span/issue-34264.stderr b/tests/ui/span/issue-34264.stderr index 89c67719b5a..b581cdd0be2 100644 --- a/tests/ui/span/issue-34264.stderr +++ b/tests/ui/span/issue-34264.stderr @@ -54,7 +54,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | LL | foo(Some(42), 2, ""); - | ^^^ -- unexpected argument of type `&'static str` + | ^^^ -- unexpected argument #3 of type `&'static str` | note: function defined here --> $DIR/issue-34264.rs:1:4 @@ -85,7 +85,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | LL | bar(1, 2, 3); - | ^^^ - unexpected argument of type `{integer}` + | ^^^ - unexpected argument #3 of type `{integer}` | note: function defined here --> $DIR/issue-34264.rs:3:4 diff --git a/tests/ui/span/missing-unit-argument.stderr b/tests/ui/span/missing-unit-argument.stderr index ff89f775334..79980f48ab6 100644 --- a/tests/ui/span/missing-unit-argument.stderr +++ b/tests/ui/span/missing-unit-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:11:33 | LL | let _: Result<(), String> = Ok(); - | ^^-- an argument of type `()` is missing + | ^^-- argument #1 of type `()` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -31,7 +31,7 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | LL | foo(()); - | ^^^---- an argument of type `()` is missing + | ^^^---- argument #2 of type `()` is missing | note: function defined here --> $DIR/missing-unit-argument.rs:1:4 @@ -47,7 +47,7 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | LL | bar(); - | ^^^-- an argument of type `()` is missing + | ^^^-- argument #1 of type `()` is missing | note: function defined here --> $DIR/missing-unit-argument.rs:2:4 @@ -63,7 +63,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | LL | S.baz(); - | ^^^-- an argument of type `()` is missing + | ^^^-- argument #1 of type `()` is missing | note: method defined here --> $DIR/missing-unit-argument.rs:6:8 @@ -79,7 +79,7 @@ error[E0061]: this method takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | LL | S.generic::<()>(); - | ^^^^^^^^^^^^^-- an argument of type `()` is missing + | ^^^^^^^^^^^^^-- argument #1 of type `()` is missing | note: method defined here --> $DIR/missing-unit-argument.rs:7:8 diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs index 59a015da84e..fb962ad24bf 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.rs @@ -14,6 +14,5 @@ struct Wrapper<const C: <i32 as Trait>::Type> {} impl<const C: usize> Wrapper<C> {} //~^ ERROR the constant `C` is not of type `<i32 as Trait>::Type` -//~^^ ERROR mismatched types fn main() {} diff --git a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr index 71d4277275f..7094ee8c67c 100644 --- a/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr +++ b/tests/ui/specialization/default-proj-ty-as-type-of-const-issue-125757.stderr @@ -20,17 +20,5 @@ note: required by a const generic parameter in `Wrapper` LL | struct Wrapper<const C: <i32 as Trait>::Type> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `Wrapper` -error[E0308]: mismatched types - --> $DIR/default-proj-ty-as-type-of-const-issue-125757.rs:15:30 - | -LL | impl<const C: usize> Wrapper<C> {} - | ^ expected associated type, found `usize` - | - = note: expected associated type `<i32 as Trait>::Type` - found type `usize` - = help: consider constraining the associated type `<i32 as Trait>::Type` to `usize` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs index f89a463bc58..a0ee7714417 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs @@ -6,7 +6,6 @@ struct S<const L: usize>; impl<const N: i32> Copy for S<N> {} -//~^ ERROR: mismatched types impl<const M: usize> Copy for S<M> {} //~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>` diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr index 1dac58e1f69..2953bc95917 100644 --- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr +++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr @@ -1,19 +1,11 @@ error[E0119]: conflicting implementations of trait `Copy` for type `S<_>` - --> $DIR/bad-const-wf-doesnt-specialize.rs:10:1 + --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1 | LL | impl<const N: i32> Copy for S<N> {} | -------------------------------- first implementation here -LL | LL | impl<const M: usize> Copy for S<M> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>` -error[E0308]: mismatched types - --> $DIR/bad-const-wf-doesnt-specialize.rs:8:31 - | -LL | impl<const N: i32> Copy for S<N> {} - | ^ expected `usize`, found `i32` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0119, E0308. -For more information about an error, try `rustc --explain E0119`. +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr index 9ea34290e36..9fdfc00dfcd 100644 --- a/tests/ui/static/reference-to-mut-static-safe.e2021.stderr +++ b/tests/ui/static/reference-to-mut-static-safe.e2021.stderr @@ -11,7 +11,7 @@ LL | let _x = &X; help: use `addr_of!` instead to create a raw pointer | LL | let _x = addr_of!(X); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/reference-to-mut-static-safe.rs:9:15 diff --git a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr index c57b418d7b2..b3e0c84d1d8 100644 --- a/tests/ui/static/reference-to-mut-static-safe.e2024.stderr +++ b/tests/ui/static/reference-to-mut-static-safe.e2024.stderr @@ -8,7 +8,7 @@ LL | let _x = &X; help: use `addr_of!` instead to create a raw pointer | LL | let _x = addr_of!(X); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe block --> $DIR/reference-to-mut-static-safe.rs:9:15 diff --git a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr index b24943cf593..ca9cfbf7ac7 100644 --- a/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr +++ b/tests/ui/static/reference-to-mut-static-unsafe-fn.stderr @@ -8,7 +8,7 @@ LL | let _y = &X; help: use `addr_of!` instead to create a raw pointer | LL | let _y = addr_of!(X); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static-unsafe-fn.rs:13:22 @@ -20,7 +20,7 @@ LL | let ref _a = X; help: use `addr_of!` instead to create a raw pointer | LL | let ref _a = addr_of!(X); - | ~~~~~~~~~~~ + | +++++++++ + error[E0796]: creating a mutable reference to a mutable static --> $DIR/reference-to-mut-static-unsafe-fn.rs:16:26 @@ -32,7 +32,7 @@ LL | let ref mut _a = X; help: use `addr_of_mut!` instead to create a raw pointer | LL | let ref mut _a = addr_of_mut!(X); - | ~~~~~~~~~~~~~~~ + | +++++++++++++ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static-unsafe-fn.rs:19:25 @@ -44,7 +44,7 @@ LL | let (_b, _c) = (&X, &mut Y); help: use `addr_of!` instead to create a raw pointer | LL | let (_b, _c) = (addr_of!(X), &mut Y); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0796]: creating a mutable reference to a mutable static --> $DIR/reference-to-mut-static-unsafe-fn.rs:19:29 @@ -56,7 +56,7 @@ LL | let (_b, _c) = (&X, &mut Y); help: use `addr_of_mut!` instead to create a raw pointer | LL | let (_b, _c) = (&X, addr_of_mut!(Y)); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static-unsafe-fn.rs:23:13 @@ -68,7 +68,7 @@ LL | foo(&X); help: use `addr_of!` instead to create a raw pointer | LL | foo(addr_of!(X)); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: aborting due to 6 previous errors diff --git a/tests/ui/static/reference-to-mut-static.e2021.stderr b/tests/ui/static/reference-to-mut-static.e2021.stderr index f477e5ac6c5..667d7602f34 100644 --- a/tests/ui/static/reference-to-mut-static.e2021.stderr +++ b/tests/ui/static/reference-to-mut-static.e2021.stderr @@ -15,7 +15,7 @@ LL | #![deny(static_mut_refs)] help: use `addr_of!` instead to create a raw pointer | LL | let _y = addr_of!(X); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: creating a mutable reference to mutable static is discouraged --> $DIR/reference-to-mut-static.rs:20:18 @@ -29,7 +29,7 @@ LL | let _y = &mut X; help: use `addr_of_mut!` instead to create a raw pointer | LL | let _y = addr_of_mut!(X); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error: creating a shared reference to mutable static is discouraged --> $DIR/reference-to-mut-static.rs:28:22 @@ -43,7 +43,7 @@ LL | let ref _a = X; help: use `addr_of!` instead to create a raw pointer | LL | let ref _a = addr_of!(X); - | ~~~~~~~~~~~ + | +++++++++ + error: creating a shared reference to mutable static is discouraged --> $DIR/reference-to-mut-static.rs:32:25 @@ -57,7 +57,7 @@ LL | let (_b, _c) = (&X, &Y); help: use `addr_of!` instead to create a raw pointer | LL | let (_b, _c) = (addr_of!(X), &Y); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: creating a shared reference to mutable static is discouraged --> $DIR/reference-to-mut-static.rs:32:29 @@ -71,7 +71,7 @@ LL | let (_b, _c) = (&X, &Y); help: use `addr_of!` instead to create a raw pointer | LL | let (_b, _c) = (&X, addr_of!(Y)); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: creating a shared reference to mutable static is discouraged --> $DIR/reference-to-mut-static.rs:38:13 @@ -85,7 +85,7 @@ LL | foo(&X); help: use `addr_of!` instead to create a raw pointer | LL | foo(addr_of!(X)); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: aborting due to 6 previous errors diff --git a/tests/ui/static/reference-to-mut-static.e2024.stderr b/tests/ui/static/reference-to-mut-static.e2024.stderr index b18e214e84f..e77f4355466 100644 --- a/tests/ui/static/reference-to-mut-static.e2024.stderr +++ b/tests/ui/static/reference-to-mut-static.e2024.stderr @@ -8,7 +8,7 @@ LL | let _y = &X; help: use `addr_of!` instead to create a raw pointer | LL | let _y = addr_of!(X); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0796]: creating a mutable reference to a mutable static --> $DIR/reference-to-mut-static.rs:20:18 @@ -20,7 +20,7 @@ LL | let _y = &mut X; help: use `addr_of_mut!` instead to create a raw pointer | LL | let _y = addr_of_mut!(X); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static.rs:28:22 @@ -32,7 +32,7 @@ LL | let ref _a = X; help: use `addr_of!` instead to create a raw pointer | LL | let ref _a = addr_of!(X); - | ~~~~~~~~~~~ + | +++++++++ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static.rs:32:25 @@ -44,7 +44,7 @@ LL | let (_b, _c) = (&X, &Y); help: use `addr_of!` instead to create a raw pointer | LL | let (_b, _c) = (addr_of!(X), &Y); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static.rs:32:29 @@ -56,7 +56,7 @@ LL | let (_b, _c) = (&X, &Y); help: use `addr_of!` instead to create a raw pointer | LL | let (_b, _c) = (&X, addr_of!(Y)); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0796]: creating a shared reference to a mutable static --> $DIR/reference-to-mut-static.rs:38:13 @@ -68,7 +68,7 @@ LL | foo(&X); help: use `addr_of!` instead to create a raw pointer | LL | foo(addr_of!(X)); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + error: aborting due to 6 previous errors diff --git a/tests/ui/static/safe-extern-statics-mut.stderr b/tests/ui/static/safe-extern-statics-mut.stderr index 9a4b651405f..7705a897e27 100644 --- a/tests/ui/static/safe-extern-statics-mut.stderr +++ b/tests/ui/static/safe-extern-statics-mut.stderr @@ -11,7 +11,7 @@ LL | let rb = &B; help: use `addr_of!` instead to create a raw pointer | LL | let rb = addr_of!(B); - | ~~~~~~~~~~~ + | ~~~~~~~~~ + warning: creating a shared reference to mutable static is discouraged --> $DIR/safe-extern-statics-mut.rs:15:15 @@ -25,7 +25,7 @@ LL | let xrb = &XB; help: use `addr_of!` instead to create a raw pointer | LL | let xrb = addr_of!(XB); - | ~~~~~~~~~~~~ + | ~~~~~~~~~ + error[E0133]: use of mutable static is unsafe and requires unsafe function or block --> $DIR/safe-extern-statics-mut.rs:11:13 diff --git a/tests/ui/statics/issue-15261.stderr b/tests/ui/statics/issue-15261.stderr index c31793f3d8f..6035eef5b71 100644 --- a/tests/ui/statics/issue-15261.stderr +++ b/tests/ui/statics/issue-15261.stderr @@ -11,7 +11,7 @@ LL | static n: &'static usize = unsafe { &n_mut }; help: use `addr_of!` instead to create a raw pointer | LL | static n: &'static usize = unsafe { addr_of!(n_mut) }; - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/statics/static-mut-xc.stderr b/tests/ui/statics/static-mut-xc.stderr index d381328c071..9751f754332 100644 --- a/tests/ui/statics/static-mut-xc.stderr +++ b/tests/ui/statics/static-mut-xc.stderr @@ -11,7 +11,7 @@ LL | static_bound(&static_mut_xc::a); help: use `addr_of!` instead to create a raw pointer | LL | static_bound(addr_of!(static_mut_xc::a)); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~ + warning: creating a mutable reference to mutable static is discouraged --> $DIR/static-mut-xc.rs:30:22 @@ -25,7 +25,7 @@ LL | static_bound_set(&mut static_mut_xc::a); help: use `addr_of_mut!` instead to create a raw pointer | LL | static_bound_set(addr_of_mut!(static_mut_xc::a)); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ + warning: 2 warnings emitted diff --git a/tests/ui/statics/static-recursive.stderr b/tests/ui/statics/static-recursive.stderr index cd285c6c2a4..a7a1a1610af 100644 --- a/tests/ui/statics/static-recursive.stderr +++ b/tests/ui/statics/static-recursive.stderr @@ -11,7 +11,7 @@ LL | static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 }; help: use `addr_of!` instead to create a raw pointer | LL | static mut S: *const u8 = unsafe { addr_of!(S) as *const *const u8 as *const u8 }; - | ~~~~~~~~~~~ + | ~~~~~~~~~ + warning: 1 warning emitted diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index a7a612a8a9e..b27f769ba34 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -123,15 +123,15 @@ hir-stats Lifetime 24 ( 0.3%) 1 24 hir-stats Mod 32 ( 0.4%) 1 32 hir-stats ExprField 40 ( 0.4%) 1 40 hir-stats TraitItemRef 56 ( 0.6%) 2 28 +hir-stats GenericArg 64 ( 0.7%) 4 16 +hir-stats - Type 16 ( 0.2%) 1 +hir-stats - Lifetime 48 ( 0.5%) 3 hir-stats Local 64 ( 0.7%) 1 64 hir-stats Param 64 ( 0.7%) 2 32 hir-stats Body 72 ( 0.8%) 3 24 hir-stats InlineAsm 72 ( 0.8%) 1 72 hir-stats ImplItemRef 72 ( 0.8%) 2 36 hir-stats Arm 80 ( 0.9%) 2 40 -hir-stats GenericArg 96 ( 1.1%) 4 24 -hir-stats - Type 24 ( 0.3%) 1 -hir-stats - Lifetime 72 ( 0.8%) 3 hir-stats FieldDef 96 ( 1.1%) 2 48 hir-stats Stmt 96 ( 1.1%) 3 32 hir-stats - Let 32 ( 0.4%) 1 @@ -155,8 +155,8 @@ hir-stats Generics 560 ( 6.2%) 10 56 hir-stats Ty 720 ( 8.0%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Ref 48 ( 0.5%) 1 -hir-stats - Path 624 ( 6.9%) 13 -hir-stats Expr 768 ( 8.5%) 12 64 +hir-stats - Path 624 ( 7.0%) 13 +hir-stats Expr 768 ( 8.6%) 12 64 hir-stats - Path 64 ( 0.7%) 1 hir-stats - Struct 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.8%) 31 40 hir-stats PathSegment 1_920 (21.4%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_992 +hir-stats Total 8_960 hir-stats diff --git a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr index 510b99bb5af..1051a16b40d 100644 --- a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:6:34 | LL | let _: Option<(i32, bool)> = Some(1, 2); - | ^^^^ - unexpected argument of type `{integer}` + | ^^^^ - unexpected argument #2 of type `{integer}` | note: expected `(i32, bool)`, found integer --> $DIR/args-instead-of-tuple-errors.rs:6:39 @@ -30,7 +30,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:8:5 | LL | int_bool(1, 2); - | ^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^ - unexpected argument #2 of type `{integer}` | note: expected `(i32, bool)`, found integer --> $DIR/args-instead-of-tuple-errors.rs:8:14 @@ -54,7 +54,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:11:28 | LL | let _: Option<(i8,)> = Some(); - | ^^^^-- an argument of type `(i8,)` is missing + | ^^^^-- argument #1 of type `(i8,)` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/suggestions/args-instead-of-tuple.stderr b/tests/ui/suggestions/args-instead-of-tuple.stderr index 0bdf10b0d63..3ca560f93eb 100644 --- a/tests/ui/suggestions/args-instead-of-tuple.stderr +++ b/tests/ui/suggestions/args-instead-of-tuple.stderr @@ -28,7 +28,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/args-instead-of-tuple.rs:11:25 | LL | let _: Option<()> = Some(); - | ^^^^-- an argument of type `()` is missing + | ^^^^-- argument #1 of type `()` is missing | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr index 40bb87c8a40..1af86860ce1 100644 --- a/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr +++ b/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr @@ -129,6 +129,11 @@ error[E0533]: expected value, found struct variant `E::B` | LL | let _: E = E::B; | ^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | let _: E = E::B { a: /* value */ }; + | ++++++++++++++++++ error[E0308]: mismatched types --> $DIR/fn-or-tuple-struct-without-args.rs:37:20 diff --git a/tests/ui/suggestions/incorrect-variant-literal.rs b/tests/ui/suggestions/incorrect-variant-literal.rs new file mode 100644 index 00000000000..aac2cc54904 --- /dev/null +++ b/tests/ui/suggestions/incorrect-variant-literal.rs @@ -0,0 +1,55 @@ +//@ only-linux +//@ compile-flags: --error-format=human --color=always + +enum Enum { + Unit, + Tuple(i32), + Struct { x: i32 }, +} + +fn main() { + Enum::Unit; + Enum::Tuple; + Enum::Struct; + Enum::Unit(); + Enum::Tuple(); + Enum::Struct(); + Enum::Unit {}; + Enum::Tuple {}; + Enum::Struct {}; + Enum::Unit(0); + Enum::Tuple(0); + Enum::Struct(0); + Enum::Unit { x: 0 }; + Enum::Tuple { x: 0 }; + Enum::Struct { x: 0 }; // ok + Enum::Unit(0, 0); + Enum::Tuple(0, 0); + Enum::Struct(0, 0); + Enum::Unit { x: 0, y: 0 }; + + Enum::Tuple { x: 0, y: 0 }; + + Enum::Struct { x: 0, y: 0 }; + Enum::unit; + Enum::tuple; + Enum::r#struct; + Enum::unit(); + Enum::tuple(); + Enum::r#struct(); + Enum::unit {}; + Enum::tuple {}; + Enum::r#struct {}; + Enum::unit(0); + Enum::tuple(0); + Enum::r#struct(0); + Enum::unit { x: 0 }; + Enum::tuple { x: 0 }; + Enum::r#struct { x: 0 }; + Enum::unit(0, 0); + Enum::tuple(0, 0); + Enum::r#struct(0, 0); + Enum::unit { x: 0, y: 0 }; + Enum::tuple { x: 0, y: 0 }; + Enum::r#struct { x: 0, y: 0 }; +} diff --git a/tests/ui/suggestions/incorrect-variant-literal.svg b/tests/ui/suggestions/incorrect-variant-literal.svg new file mode 100644 index 00000000000..980a7b29a00 --- /dev/null +++ b/tests/ui/suggestions/incorrect-variant-literal.svg @@ -0,0 +1,1028 @@ +<svg width="886px" height="9038px" xmlns="http://www.w3.org/2000/svg"> + <style> + .fg { fill: #AAAAAA } + .bg { background: #000000 } + .fg-ansi256-009 { fill: #FF5555 } + .fg-ansi256-010 { fill: #55FF55 } + .fg-ansi256-012 { fill: #5555FF } + .fg-ansi256-014 { fill: #55FFFF } + .container { + padding: 0 10px; + line-height: 18px; + } + .bold { font-weight: bold; } + tspan { + font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + white-space: pre; + line-height: 18px; + } + </style> + + <rect width="100%" height="100%" y="0" rx="4.5" class="bg" /> + + <text xml:space="preserve" class="container fg"> + <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0533]</tspan><tspan class="bold">: expected value, found struct variant `Enum::Struct`</tspan> +</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:13:5</tspan> +</tspan> + <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct;</tspan> +</tspan> + <tspan x="10px" y="100px"><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">not a value</tspan> +</tspan> + <tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="136px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: you might have meant to create a new value of the struct</tspan> +</tspan> + <tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="172px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Struct</tspan><tspan class="fg-ansi256-010"> { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="190px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">++++++++++++++++++</tspan> +</tspan> + <tspan x="10px" y="208px"> +</tspan> + <tspan x="10px" y="226px"><tspan class="fg-ansi256-009 bold">error[E0618]</tspan><tspan class="bold">: expected function, found enum variant `Enum::Unit`</tspan> +</tspan> + <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:14:5</tspan> +</tspan> + <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="280px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Unit,</tspan> +</tspan> + <tspan x="10px" y="298px"><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">enum variant `Enum::Unit` defined here</tspan> +</tspan> + <tspan x="10px" y="316px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="334px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit();</tspan> +</tspan> + <tspan x="10px" y="352px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^</tspan><tspan class="fg-ansi256-012 bold">--</tspan> +</tspan> + <tspan x="10px" y="370px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="388px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">call expression requires function</tspan> +</tspan> + <tspan x="10px" y="406px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="424px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: `Enum::Unit` is a unit enum variant, and does not take parentheses to be constructed</tspan> +</tspan> + <tspan x="10px" y="442px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="460px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> Enum::Unit</tspan><tspan class="fg-ansi256-009">()</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="478px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> Enum::Unit;</tspan> +</tspan> + <tspan x="10px" y="496px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="514px"> +</tspan> + <tspan x="10px" y="532px"><tspan class="fg-ansi256-009 bold">error[E0061]</tspan><tspan class="bold">: this enum variant takes 1 argument but 0 arguments were supplied</tspan> +</tspan> + <tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:15:5</tspan> +</tspan> + <tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="586px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple();</tspan> +</tspan> + <tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^</tspan><tspan class="fg-ansi256-012 bold">--</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">argument #1 of type `i32` is missing</tspan> +</tspan> + <tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="640px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: tuple variant defined here</tspan> +</tspan> + <tspan x="10px" y="658px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:6:5</tspan> +</tspan> + <tspan x="10px" y="676px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="694px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Tuple(i32),</tspan> +</tspan> + <tspan x="10px" y="712px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^</tspan> +</tspan> + <tspan x="10px" y="730px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: provide the argument</tspan> +</tspan> + <tspan x="10px" y="748px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="766px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Tuple</tspan><tspan class="fg-ansi256-010">(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="784px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="802px"> +</tspan> + <tspan x="10px" y="820px"><tspan class="fg-ansi256-009 bold">error[E0533]</tspan><tspan class="bold">: expected value, found struct variant `Enum::Struct`</tspan> +</tspan> + <tspan x="10px" y="838px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:16:5</tspan> +</tspan> + <tspan x="10px" y="856px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="874px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct();</tspan> +</tspan> + <tspan x="10px" y="892px"><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">not a value</tspan> +</tspan> + <tspan x="10px" y="910px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="928px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: you might have meant to create a new value of the struct</tspan> +</tspan> + <tspan x="10px" y="946px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="964px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Struct</tspan><tspan class="fg-ansi256-010"> { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="982px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="1000px"> +</tspan> + <tspan x="10px" y="1018px"><tspan class="fg-ansi256-009 bold">error[E0063]</tspan><tspan class="bold">: missing field `0` in initializer of `Enum`</tspan> +</tspan> + <tspan x="10px" y="1036px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:18:5</tspan> +</tspan> + <tspan x="10px" y="1054px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1072px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple {};</tspan> +</tspan> + <tspan x="10px" y="1090px"><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">missing `0`</tspan> +</tspan> + <tspan x="10px" y="1108px"> +</tspan> + <tspan x="10px" y="1126px"><tspan class="fg-ansi256-009 bold">error[E0063]</tspan><tspan class="bold">: missing field `x` in initializer of `Enum`</tspan> +</tspan> + <tspan x="10px" y="1144px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:19:5</tspan> +</tspan> + <tspan x="10px" y="1162px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1180px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct {};</tspan> +</tspan> + <tspan x="10px" y="1198px"><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">missing `x`</tspan> +</tspan> + <tspan x="10px" y="1216px"> +</tspan> + <tspan x="10px" y="1234px"><tspan class="fg-ansi256-009 bold">error[E0618]</tspan><tspan class="bold">: expected function, found `Enum`</tspan> +</tspan> + <tspan x="10px" y="1252px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:20:5</tspan> +</tspan> + <tspan x="10px" y="1270px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1288px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Unit,</tspan> +</tspan> + <tspan x="10px" y="1306px"><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">`Enum::Unit` defined here</tspan> +</tspan> + <tspan x="10px" y="1324px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="1342px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit(0);</tspan> +</tspan> + <tspan x="10px" y="1360px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^</tspan><tspan class="fg-ansi256-012 bold">---</tspan> +</tspan> + <tspan x="10px" y="1378px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1396px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">call expression requires function</tspan> +</tspan> + <tspan x="10px" y="1414px"> +</tspan> + <tspan x="10px" y="1432px"><tspan class="fg-ansi256-009 bold">error[E0533]</tspan><tspan class="bold">: expected value, found struct variant `Enum::Struct`</tspan> +</tspan> + <tspan x="10px" y="1450px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:22:5</tspan> +</tspan> + <tspan x="10px" y="1468px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1486px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct(0);</tspan> +</tspan> + <tspan x="10px" y="1504px"><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">not a value</tspan> +</tspan> + <tspan x="10px" y="1522px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1540px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: you might have meant to create a new value of the struct</tspan> +</tspan> + <tspan x="10px" y="1558px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</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> Enum::Struct</tspan><tspan class="fg-ansi256-010"> { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="1594px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="1612px"> +</tspan> + <tspan x="10px" y="1630px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Unit` has no field named `x`</tspan> +</tspan> + <tspan x="10px" y="1648px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:23:18</tspan> +</tspan> + <tspan x="10px" y="1666px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1684px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit { x: 0 };</tspan> +</tspan> + <tspan x="10px" y="1702px"><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">`Enum::Unit` does not have this field</tspan> +</tspan> + <tspan x="10px" y="1720px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1738px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: all struct fields are already assigned</tspan> +</tspan> + <tspan x="10px" y="1756px"> +</tspan> + <tspan x="10px" y="1774px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Tuple` has no field named `x`</tspan> +</tspan> + <tspan x="10px" y="1792px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:24:19</tspan> +</tspan> + <tspan x="10px" y="1810px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</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> Tuple(i32),</tspan> +</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><tspan class="fg-ansi256-012 bold">`Enum::Tuple` defined here</tspan> +</tspan> + <tspan x="10px" y="1864px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="1882px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple { x: 0 };</tspan> +</tspan> + <tspan x="10px" y="1900px"><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">field does not exist</tspan> +</tspan> + <tspan x="10px" y="1918px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1936px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: `Enum::Tuple` is a tuple variant, use the appropriate syntax</tspan> +</tspan> + <tspan x="10px" y="1954px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="1972px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Tuple</tspan><tspan class="fg-ansi256-010">(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="1990px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="2008px"> +</tspan> + <tspan x="10px" y="2026px"><tspan class="fg-ansi256-009 bold">error[E0618]</tspan><tspan class="bold">: expected function, found `Enum`</tspan> +</tspan> + <tspan x="10px" y="2044px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:26:5</tspan> +</tspan> + <tspan x="10px" y="2062px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2080px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Unit,</tspan> +</tspan> + <tspan x="10px" y="2098px"><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">`Enum::Unit` defined here</tspan> +</tspan> + <tspan x="10px" y="2116px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="2134px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit(0, 0);</tspan> +</tspan> + <tspan x="10px" y="2152px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^</tspan><tspan class="fg-ansi256-012 bold">------</tspan> +</tspan> + <tspan x="10px" y="2170px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2188px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">call expression requires function</tspan> +</tspan> + <tspan x="10px" y="2206px"> +</tspan> + <tspan x="10px" y="2224px"><tspan class="fg-ansi256-009 bold">error[E0061]</tspan><tspan class="bold">: this enum variant takes 1 argument but 2 arguments were supplied</tspan> +</tspan> + <tspan x="10px" y="2242px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:27:5</tspan> +</tspan> + <tspan x="10px" y="2260px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2278px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple(0, 0);</tspan> +</tspan> + <tspan x="10px" y="2296px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">-</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unexpected argument #2 of type `{integer}`</tspan> +</tspan> + <tspan x="10px" y="2314px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2332px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: tuple variant defined here</tspan> +</tspan> + <tspan x="10px" y="2350px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:6:5</tspan> +</tspan> + <tspan x="10px" y="2368px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2386px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Tuple(i32),</tspan> +</tspan> + <tspan x="10px" y="2404px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010 bold">^^^^^</tspan> +</tspan> + <tspan x="10px" y="2422px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: remove the extra argument</tspan> +</tspan> + <tspan x="10px" y="2440px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2458px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-009">- </tspan><tspan> Enum::Tuple(0</tspan><tspan class="fg-ansi256-009">, 0</tspan><tspan>);</tspan> +</tspan> + <tspan x="10px" y="2476px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-010">+ </tspan><tspan> Enum::Tuple(0);</tspan> +</tspan> + <tspan x="10px" y="2494px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2512px"> +</tspan> + <tspan x="10px" y="2530px"><tspan class="fg-ansi256-009 bold">error[E0533]</tspan><tspan class="bold">: expected value, found struct variant `Enum::Struct`</tspan> +</tspan> + <tspan x="10px" y="2548px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:28:5</tspan> +</tspan> + <tspan x="10px" y="2566px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2584px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct(0, 0);</tspan> +</tspan> + <tspan x="10px" y="2602px"><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">not a value</tspan> +</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-014 bold">help</tspan><tspan>: you might have meant to create a new value of the struct</tspan> +</tspan> + <tspan x="10px" y="2656px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2674px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Struct</tspan><tspan class="fg-ansi256-010"> { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="2692px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="2710px"> +</tspan> + <tspan x="10px" y="2728px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Unit` has no field named `x`</tspan> +</tspan> + <tspan x="10px" y="2746px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:29:18</tspan> +</tspan> + <tspan x="10px" y="2764px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2782px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="2800px"><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">`Enum::Unit` does not have this field</tspan> +</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 class="bold">note</tspan><tspan>: all struct fields are already assigned</tspan> +</tspan> + <tspan x="10px" y="2854px"> +</tspan> + <tspan x="10px" y="2872px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Unit` has no field named `y`</tspan> +</tspan> + <tspan x="10px" y="2890px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:29:24</tspan> +</tspan> + <tspan x="10px" y="2908px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2926px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Unit { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="2944px"><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">`Enum::Unit` does not have this field</tspan> +</tspan> + <tspan x="10px" y="2962px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="2980px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: all struct fields are already assigned</tspan> +</tspan> + <tspan x="10px" y="2998px"> +</tspan> + <tspan x="10px" y="3016px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Tuple` has no field named `x`</tspan> +</tspan> + <tspan x="10px" y="3034px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:31:19</tspan> +</tspan> + <tspan x="10px" y="3052px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3070px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Tuple(i32),</tspan> +</tspan> + <tspan x="10px" y="3088px"><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">`Enum::Tuple` defined here</tspan> +</tspan> + <tspan x="10px" y="3106px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="3124px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="3142px"><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">field does not exist</tspan> +</tspan> + <tspan x="10px" y="3160px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3178px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: `Enum::Tuple` is a tuple variant, use the appropriate syntax</tspan> +</tspan> + <tspan x="10px" y="3196px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3214px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Tuple</tspan><tspan class="fg-ansi256-010">(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="3232px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="3250px"> +</tspan> + <tspan x="10px" y="3268px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Tuple` has no field named `y`</tspan> +</tspan> + <tspan x="10px" y="3286px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:31:25</tspan> +</tspan> + <tspan x="10px" y="3304px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3322px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Tuple(i32),</tspan> +</tspan> + <tspan x="10px" y="3340px"><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">`Enum::Tuple` defined here</tspan> +</tspan> + <tspan x="10px" y="3358px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="3376px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Tuple { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="3394px"><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">field does not exist</tspan> +</tspan> + <tspan x="10px" y="3412px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3430px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: `Enum::Tuple` is a tuple variant, use the appropriate syntax</tspan> +</tspan> + <tspan x="10px" y="3448px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3466px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::Tuple</tspan><tspan class="fg-ansi256-010">(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="3484px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="3502px"> +</tspan> + <tspan x="10px" y="3520px"><tspan class="fg-ansi256-009 bold">error[E0559]</tspan><tspan class="bold">: variant `Enum::Struct` has no field named `y`</tspan> +</tspan> + <tspan x="10px" y="3538px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:33:26</tspan> +</tspan> + <tspan x="10px" y="3556px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3574px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::Struct { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="3592px"><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">`Enum::Struct` does not have this field</tspan> +</tspan> + <tspan x="10px" y="3610px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3628px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">note</tspan><tspan>: all struct fields are already assigned</tspan> +</tspan> + <tspan x="10px" y="3646px"> +</tspan> + <tspan x="10px" y="3664px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `unit` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="3682px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:34:11</tspan> +</tspan> + <tspan x="10px" y="3700px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3718px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="3736px"><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">variant or associated item `unit` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="3754px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="3772px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit;</tspan> +</tspan> + <tspan x="10px" y="3790px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="3808px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="3826px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name (notice the capitalization difference)</tspan> +</tspan> + <tspan x="10px" y="3844px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</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> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="3880px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="3898px"> +</tspan> + <tspan x="10px" y="3916px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `tuple` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="3934px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:35:11</tspan> +</tspan> + <tspan x="10px" y="3952px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</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> enum Enum {</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">variant or associated item `tuple` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="4006px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="4024px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple;</tspan> +</tspan> + <tspan x="10px" y="4042px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="4060px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4078px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="4096px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4114px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="4132px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="4150px"> +</tspan> + <tspan x="10px" y="4168px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `r#struct` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="4186px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:36:11</tspan> +</tspan> + <tspan x="10px" y="4204px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4222px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="4240px"><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">variant or associated item `r#struct` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="4258px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="4276px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct;</tspan> +</tspan> + <tspan x="10px" y="4294px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="4312px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4330px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="4348px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4366px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="4384px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="4402px"> +</tspan> + <tspan x="10px" y="4420px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `unit` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="4438px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:37:11</tspan> +</tspan> + <tspan x="10px" y="4456px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4474px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="4492px"><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">variant or associated item `unit` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="4510px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="4528px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit();</tspan> +</tspan> + <tspan x="10px" y="4546px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="4564px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4582px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="4600px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4618px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="4636px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="4654px"> +</tspan> + <tspan x="10px" y="4672px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `tuple` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="4690px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:38:11</tspan> +</tspan> + <tspan x="10px" y="4708px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4726px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="4744px"><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">variant or associated item `tuple` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="4762px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="4780px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple();</tspan> +</tspan> + <tspan x="10px" y="4798px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="4816px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4834px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="4852px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4870px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="4888px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="4906px"> +</tspan> + <tspan x="10px" y="4924px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `r#struct` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="4942px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:39:11</tspan> +</tspan> + <tspan x="10px" y="4960px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="4978px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="4996px"><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">variant or associated item `r#struct` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="5014px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="5032px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct();</tspan> +</tspan> + <tspan x="10px" y="5050px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="5068px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5086px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="5104px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5122px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="5140px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="5158px"> +</tspan> + <tspan x="10px" y="5176px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `unit` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="5194px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:40:11</tspan> +</tspan> + <tspan x="10px" y="5212px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5230px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="5248px"><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">variant `unit` not found here</tspan> +</tspan> + <tspan x="10px" y="5266px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="5284px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit {};</tspan> +</tspan> + <tspan x="10px" y="5302px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^</tspan> +</tspan> + <tspan x="10px" y="5320px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5338px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="5356px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5374px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="5392px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="5410px"> +</tspan> + <tspan x="10px" y="5428px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `tuple` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="5446px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:41:11</tspan> +</tspan> + <tspan x="10px" y="5464px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5482px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="5500px"><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">variant `tuple` not found here</tspan> +</tspan> + <tspan x="10px" y="5518px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="5536px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple {};</tspan> +</tspan> + <tspan x="10px" y="5554px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^</tspan> +</tspan> + <tspan x="10px" y="5572px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5590px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="5608px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5626px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="5644px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="5662px"> +</tspan> + <tspan x="10px" y="5680px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `r#struct` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="5698px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:42:11</tspan> +</tspan> + <tspan x="10px" y="5716px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5734px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="5752px"><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">variant `r#struct` not found here</tspan> +</tspan> + <tspan x="10px" y="5770px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="5788px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct {};</tspan> +</tspan> + <tspan x="10px" y="5806px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^</tspan> +</tspan> + <tspan x="10px" y="5824px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5842px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="5860px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5878px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="5896px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="5914px"> +</tspan> + <tspan x="10px" y="5932px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `unit` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="5950px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:43:11</tspan> +</tspan> + <tspan x="10px" y="5968px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="5986px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="6004px"><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">variant or associated item `unit` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="6022px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="6040px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit(0);</tspan> +</tspan> + <tspan x="10px" y="6058px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="6076px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6094px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="6112px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6130px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="6148px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="6166px"> +</tspan> + <tspan x="10px" y="6184px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `tuple` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="6202px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:44:11</tspan> +</tspan> + <tspan x="10px" y="6220px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6238px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="6256px"><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">variant or associated item `tuple` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="6274px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="6292px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple(0);</tspan> +</tspan> + <tspan x="10px" y="6310px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="6328px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6346px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="6364px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6382px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple</tspan><tspan>(0);</tspan> +</tspan> + <tspan x="10px" y="6400px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~</tspan> +</tspan> + <tspan x="10px" y="6418px"> +</tspan> + <tspan x="10px" y="6436px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `r#struct` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="6454px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:45:11</tspan> +</tspan> + <tspan x="10px" y="6472px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6490px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="6508px"><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">variant or associated item `r#struct` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="6526px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="6544px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct(0);</tspan> +</tspan> + <tspan x="10px" y="6562px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="6580px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6598px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="6616px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6634px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="6652px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="6670px"> +</tspan> + <tspan x="10px" y="6688px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `unit` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="6706px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:46:11</tspan> +</tspan> + <tspan x="10px" y="6724px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6742px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="6760px"><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">variant `unit` not found here</tspan> +</tspan> + <tspan x="10px" y="6778px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="6796px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit { x: 0 };</tspan> +</tspan> + <tspan x="10px" y="6814px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^</tspan> +</tspan> + <tspan x="10px" y="6832px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6850px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="6868px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6886px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="6904px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="6922px"> +</tspan> + <tspan x="10px" y="6940px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `tuple` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="6958px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:47:11</tspan> +</tspan> + <tspan x="10px" y="6976px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="6994px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="7012px"><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">variant `tuple` not found here</tspan> +</tspan> + <tspan x="10px" y="7030px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="7048px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple { x: 0 };</tspan> +</tspan> + <tspan x="10px" y="7066px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^</tspan> +</tspan> + <tspan x="10px" y="7084px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7102px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="7120px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7138px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="7156px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="7174px"> +</tspan> + <tspan x="10px" y="7192px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `r#struct` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="7210px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:48:11</tspan> +</tspan> + <tspan x="10px" y="7228px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7246px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="7264px"><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">variant `r#struct` not found here</tspan> +</tspan> + <tspan x="10px" y="7282px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="7300px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct { x: 0 };</tspan> +</tspan> + <tspan x="10px" y="7318px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^</tspan> +</tspan> + <tspan x="10px" y="7336px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7354px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="7372px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7390px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="7408px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="7426px"> +</tspan> + <tspan x="10px" y="7444px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `unit` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="7462px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:49:11</tspan> +</tspan> + <tspan x="10px" y="7480px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7498px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="7516px"><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">variant or associated item `unit` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="7534px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="7552px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit(0, 0);</tspan> +</tspan> + <tspan x="10px" y="7570px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="7588px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7606px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="7624px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7642px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="7660px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="7678px"> +</tspan> + <tspan x="10px" y="7696px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `tuple` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="7714px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:50:11</tspan> +</tspan> + <tspan x="10px" y="7732px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7750px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="7768px"><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">variant or associated item `tuple` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="7786px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="7804px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple(0, 0);</tspan> +</tspan> + <tspan x="10px" y="7822px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="7840px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7858px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="7876px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="7894px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple</tspan><tspan>(</tspan><tspan class="fg-ansi256-010">/* i32 */</tspan><tspan>);</tspan> +</tspan> + <tspan x="10px" y="7912px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="7930px"> +</tspan> + <tspan x="10px" y="7948px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant or associated item named `r#struct` found for enum `Enum` in the current scope</tspan> +</tspan> + <tspan x="10px" y="7966px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:51:11</tspan> +</tspan> + <tspan x="10px" y="7984px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8002px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="8020px"><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">variant or associated item `r#struct` not found for this enum</tspan> +</tspan> + <tspan x="10px" y="8038px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="8056px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct(0, 0);</tspan> +</tspan> + <tspan x="10px" y="8074px"><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">variant or associated item not found in `Enum`</tspan> +</tspan> + <tspan x="10px" y="8092px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8110px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="8128px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8146px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="8164px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="8182px"> +</tspan> + <tspan x="10px" y="8200px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `unit` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="8218px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:52:11</tspan> +</tspan> + <tspan x="10px" y="8236px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8254px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="8272px"><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">variant `unit` not found here</tspan> +</tspan> + <tspan x="10px" y="8290px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="8308px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::unit { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="8326px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^</tspan> +</tspan> + <tspan x="10px" y="8344px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8362px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="8380px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8398px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Unit</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="8416px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~</tspan> +</tspan> + <tspan x="10px" y="8434px"> +</tspan> + <tspan x="10px" y="8452px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `tuple` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="8470px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:53:11</tspan> +</tspan> + <tspan x="10px" y="8488px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8506px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="8524px"><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">variant `tuple` not found here</tspan> +</tspan> + <tspan x="10px" y="8542px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="8560px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::tuple { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="8578px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^</tspan> +</tspan> + <tspan x="10px" y="8596px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8614px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="8632px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8650px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Tuple(/* i32 */)</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="8668px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="8686px"> +</tspan> + <tspan x="10px" y="8704px"><tspan class="fg-ansi256-009 bold">error[E0599]</tspan><tspan class="bold">: no variant named `r#struct` found for enum `Enum`</tspan> +</tspan> + <tspan x="10px" y="8722px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">--> </tspan><tspan>$DIR/incorrect-variant-literal.rs:54:11</tspan> +</tspan> + <tspan x="10px" y="8740px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8758px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> enum Enum {</tspan> +</tspan> + <tspan x="10px" y="8776px"><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">variant `r#struct` not found here</tspan> +</tspan> + <tspan x="10px" y="8794px"><tspan class="fg-ansi256-012 bold">...</tspan> +</tspan> + <tspan x="10px" y="8812px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Enum::r#struct { x: 0, y: 0 };</tspan> +</tspan> + <tspan x="10px" y="8830px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^</tspan> +</tspan> + <tspan x="10px" y="8848px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8866px"><tspan class="fg-ansi256-014 bold">help</tspan><tspan>: there is a variant with a similar name</tspan> +</tspan> + <tspan x="10px" y="8884px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan> +</tspan> + <tspan x="10px" y="8902px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">| </tspan><tspan> Enum::</tspan><tspan class="fg-ansi256-010">Struct { x: /* value */ }</tspan><tspan>;</tspan> +</tspan> + <tspan x="10px" y="8920px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-010">~~~~~~~~~~~~~~~~~~~~~~~~~</tspan> +</tspan> + <tspan x="10px" y="8938px"> +</tspan> + <tspan x="10px" y="8956px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 39 previous errors</tspan> +</tspan> + <tspan x="10px" y="8974px"> +</tspan> + <tspan x="10px" y="8992px"><tspan class="bold">Some errors have detailed explanations: E0061, E0063, E0533, E0559, E0599, E0618.</tspan> +</tspan> + <tspan x="10px" y="9010px"><tspan class="bold">For more information about an error, try `rustc --explain E0061`.</tspan> +</tspan> + <tspan x="10px" y="9028px"> +</tspan> + </text> + +</svg> diff --git a/tests/ui/suggestions/issue-109396.stderr b/tests/ui/suggestions/issue-109396.stderr index d4956872a39..5419e8240c5 100644 --- a/tests/ui/suggestions/issue-109396.stderr +++ b/tests/ui/suggestions/issue-109396.stderr @@ -11,14 +11,14 @@ LL | let mut mutex = std::mem::zeroed( | ^^^^^^^^^^^^^^^^ LL | LL | file.as_raw_fd(), - | ---------------- unexpected argument + | ---------------- unexpected argument #1 LL | LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #2 of type `{integer}` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #3 of type `{integer}` LL | 0, - | - unexpected argument of type `{integer}` + | - unexpected argument #4 of type `{integer}` | note: function defined here --> $SRC_DIR/core/src/mem/mod.rs:LL:COL diff --git a/tests/ui/suggestions/issue-109854.stderr b/tests/ui/suggestions/issue-109854.stderr index 52444cd4c45..d9cbbe37d46 100644 --- a/tests/ui/suggestions/issue-109854.stderr +++ b/tests/ui/suggestions/issue-109854.stderr @@ -7,9 +7,9 @@ LL | String::with_capacity( LL | / r#" LL | | pub(crate) struct Person<T: Clone> {} LL | | "#, - | |__- unexpected argument of type `&'static str` + | |__- unexpected argument #2 of type `&'static str` LL | r#""#, - | ----- unexpected argument of type `&'static str` + | ----- unexpected argument #3 of type `&'static str` | note: expected `usize`, found fn item --> $DIR/issue-109854.rs:4:5 diff --git a/tests/ui/suggestions/issue-85347.stderr b/tests/ui/suggestions/issue-85347.stderr index b3616041c4c..af77ddd35e3 100644 --- a/tests/ui/suggestions/issue-85347.stderr +++ b/tests/ui/suggestions/issue-85347.stderr @@ -22,8 +22,9 @@ LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; | help: consider removing this associated item binding | -LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; - | ~~~~~~~~~~~~~~~ +LL - type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; +LL + type Bar<'a>: Deref<Target = <Self>::Bar>; + | error[E0107]: associated type takes 1 lifetime argument but 0 lifetime arguments were supplied --> $DIR/issue-85347.rs:3:42 @@ -51,8 +52,9 @@ LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider removing this associated item binding | -LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; - | ~~~~~~~~~~~~~~~ +LL - type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; +LL + type Bar<'a>: Deref<Target = <Self>::Bar>; + | error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/nested-non-tuple-tuple-struct.stderr b/tests/ui/suggestions/nested-non-tuple-tuple-struct.stderr index 948f09fc3fa..4523333850c 100644 --- a/tests/ui/suggestions/nested-non-tuple-tuple-struct.stderr +++ b/tests/ui/suggestions/nested-non-tuple-tuple-struct.stderr @@ -9,8 +9,8 @@ LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); | help: `S` is a tuple struct, use the appropriate syntax | -LL | let _x = (S(/* fields */), S { x: 3.0, y: 4.0 }); - | ~~~~~~~~~~~~~~~ +LL | let _x = (S(/* f32 */, /* f32 */), S { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0560]: struct `S` has no field named `y` --> $DIR/nested-non-tuple-tuple-struct.rs:8:27 @@ -23,8 +23,8 @@ LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); | help: `S` is a tuple struct, use the appropriate syntax | -LL | let _x = (S(/* fields */), S { x: 3.0, y: 4.0 }); - | ~~~~~~~~~~~~~~~ +LL | let _x = (S(/* f32 */, /* f32 */), S { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0560]: struct `S` has no field named `x` --> $DIR/nested-non-tuple-tuple-struct.rs:8:41 @@ -37,8 +37,8 @@ LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); | help: `S` is a tuple struct, use the appropriate syntax | -LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */)); - | ~~~~~~~~~~~~~~~ +LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* f32 */, /* f32 */)); + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0560]: struct `S` has no field named `y` --> $DIR/nested-non-tuple-tuple-struct.rs:8:49 @@ -51,8 +51,8 @@ LL | let _x = (S { x: 1.0, y: 2.0 }, S { x: 3.0, y: 4.0 }); | help: `S` is a tuple struct, use the appropriate syntax | -LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* fields */)); - | ~~~~~~~~~~~~~~~ +LL | let _x = (S { x: 1.0, y: 2.0 }, S(/* f32 */, /* f32 */)); + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0559]: variant `E::V` has no field named `x` --> $DIR/nested-non-tuple-tuple-struct.rs:13:22 @@ -65,8 +65,8 @@ LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); | help: `E::V` is a tuple variant, use the appropriate syntax | -LL | let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 }); - | ~~~~~~~~~~~~~~~~~~ +LL | let _y = (E::V(/* f32 */, /* f32 */), E::V { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0559]: variant `E::V` has no field named `y` --> $DIR/nested-non-tuple-tuple-struct.rs:13:30 @@ -79,8 +79,8 @@ LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); | help: `E::V` is a tuple variant, use the appropriate syntax | -LL | let _y = (E::V(/* fields */), E::V { x: 3.0, y: 4.0 }); - | ~~~~~~~~~~~~~~~~~~ +LL | let _y = (E::V(/* f32 */, /* f32 */), E::V { x: 3.0, y: 4.0 }); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0559]: variant `E::V` has no field named `x` --> $DIR/nested-non-tuple-tuple-struct.rs:13:47 @@ -93,8 +93,8 @@ LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); | help: `E::V` is a tuple variant, use the appropriate syntax | -LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */)); - | ~~~~~~~~~~~~~~~~~~ +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* f32 */, /* f32 */)); + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0559]: variant `E::V` has no field named `y` --> $DIR/nested-non-tuple-tuple-struct.rs:13:55 @@ -107,8 +107,8 @@ LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V { x: 3.0, y: 4.0 }); | help: `E::V` is a tuple variant, use the appropriate syntax | -LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* fields */)); - | ~~~~~~~~~~~~~~~~~~ +LL | let _y = (E::V { x: 1.0, y: 2.0 }, E::V(/* f32 */, /* f32 */)); + | ~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 8 previous errors diff --git a/tests/ui/suggestions/suggest-variants.stderr b/tests/ui/suggestions/suggest-variants.stderr index a422bc65635..d93bf2d8cd7 100644 --- a/tests/ui/suggestions/suggest-variants.stderr +++ b/tests/ui/suggestions/suggest-variants.stderr @@ -5,7 +5,12 @@ LL | enum Shape { | ---------- variant `Squareee` not found here ... LL | println!("My shape is {:?}", Shape::Squareee { size: 5}); - | ^^^^^^^^ help: there is a variant with a similar name: `Square` + | ^^^^^^^^ + | +help: there is a variant with a similar name + | +LL | println!("My shape is {:?}", Shape::Square { size: 5}); + | ~~~~~~ error[E0599]: no variant named `Circl` found for enum `Shape` --> $DIR/suggest-variants.rs:13:41 @@ -14,7 +19,12 @@ LL | enum Shape { | ---------- variant `Circl` not found here ... LL | println!("My shape is {:?}", Shape::Circl { size: 5}); - | ^^^^^ help: there is a variant with a similar name: `Circle` + | ^^^^^ + | +help: there is a variant with a similar name + | +LL | println!("My shape is {:?}", Shape::Circle { size: 5}); + | ~~~~~~ error[E0599]: no variant named `Rombus` found for enum `Shape` --> $DIR/suggest-variants.rs:14:41 @@ -32,10 +42,12 @@ LL | enum Shape { | ---------- variant or associated item `Squareee` not found for this enum ... LL | Shape::Squareee; - | ^^^^^^^^ - | | - | variant or associated item not found in `Shape` - | help: there is a variant with a similar name: `Square` + | ^^^^^^^^ variant or associated item not found in `Shape` + | +help: there is a variant with a similar name + | +LL | Shape::Square { size: /* value */ }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0599]: no variant or associated item named `Circl` found for enum `Shape` in the current scope --> $DIR/suggest-variants.rs:16:12 @@ -44,10 +56,12 @@ LL | enum Shape { | ---------- variant or associated item `Circl` not found for this enum ... LL | Shape::Circl; - | ^^^^^ - | | - | variant or associated item not found in `Shape` - | help: there is a variant with a similar name: `Circle` + | ^^^^^ variant or associated item not found in `Shape` + | +help: there is a variant with a similar name + | +LL | Shape::Circle { radius: /* value */ }; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0599]: no variant or associated item named `Rombus` found for enum `Shape` in the current scope --> $DIR/suggest-variants.rs:17:12 diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index c2c3d6d547d..f3485d9c1fa 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -10,7 +10,6 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support -//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 4c94518d4d1..16001b3eecd 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:35:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:29:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 0c44acaffd7..84740161a70 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -10,7 +10,6 @@ //@ ignore-wasm no panic or subprocess support //@ ignore-emscripten no panic or subprocess support //@ ignore-sgx no subprocess support -//@ ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#127539) #![cfg(test)] #![feature(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 25105f38fcf..f5d14e77da9 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -17,7 +17,7 @@ hello, world testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:40:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: assertion `left == right` failed left: 2 right: 5 diff --git a/tests/ui/traits/issue-105231.rs b/tests/ui/traits/issue-105231.rs index 89b2da4452a..7338642beef 100644 --- a/tests/ui/traits/issue-105231.rs +++ b/tests/ui/traits/issue-105231.rs @@ -1,9 +1,9 @@ //~ ERROR overflow evaluating the requirement `A<A<A<A<A<A<A<...>>>>>>>: Send` struct A<T>(B<T>); //~^ ERROR recursive types `A` and `B` have infinite size -//~| ERROR `T` is never used +//~| ERROR `T` is only used recursively struct B<T>(A<A<T>>); -//~^ ERROR `T` is never used +//~^ ERROR `T` is only used recursively trait Foo {} impl<T> Foo for T where T: Send {} impl Foo for B<u8> {} diff --git a/tests/ui/traits/issue-105231.stderr b/tests/ui/traits/issue-105231.stderr index 6467a438375..d3014a79ad6 100644 --- a/tests/ui/traits/issue-105231.stderr +++ b/tests/ui/traits/issue-105231.stderr @@ -15,23 +15,27 @@ LL | LL ~ struct B<T>(Box<A<A<T>>>); | -error[E0392]: type parameter `T` is never used - --> $DIR/issue-105231.rs:2:10 +error: type parameter `T` is only used recursively + --> $DIR/issue-105231.rs:2:15 | LL | struct A<T>(B<T>); - | ^ unused type parameter + | - ^ + | | + | type parameter must be used non-recursively in the definition | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0392]: type parameter `T` is never used - --> $DIR/issue-105231.rs:5:10 +error: type parameter `T` is only used recursively + --> $DIR/issue-105231.rs:5:17 | LL | struct B<T>(A<A<T>>); - | ^ unused type parameter + | - ^ + | | + | type parameter must be used non-recursively in the definition | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + = note: all type parameters must be used in a non-recursive way in order to constrain their variance error[E0275]: overflow evaluating the requirement `A<A<A<A<A<A<A<...>>>>>>>: Send` | @@ -44,5 +48,5 @@ LL | struct B<T>(A<A<T>>); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0072, E0275, E0392. +Some errors have detailed explanations: E0072, E0275. For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs deleted file mode 100644 index bbae67f0bad..00000000000 --- a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(non_lifetime_binders)] -//~^ WARN the feature `non_lifetime_binders` is incomplete - -fn b() -where - for<const C: usize> [(); C]: Copy, - //~^ ERROR cannot capture late-bound const parameter in constant -{ -} - -fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr b/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr deleted file mode 100644 index 4e0441c1c7d..00000000000 --- a/tests/ui/traits/non_lifetime_binders/capture-late-ct-in-anon.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/capture-late-ct-in-anon.rs:1:12 - | -LL | #![feature(non_lifetime_binders)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information - = note: `#[warn(incomplete_features)]` on by default - -error: cannot capture late-bound const parameter in constant - --> $DIR/capture-late-ct-in-anon.rs:6:30 - | -LL | for<const C: usize> [(); C]: Copy, - | -------------- ^ - | | - | parameter defined here - -error: aborting due to 1 previous error; 1 warning emitted - diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs new file mode 100644 index 00000000000..a71657316ae --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.rs @@ -0,0 +1,18 @@ +fn main() { + let fields = vec![1]; + let variant = vec![2]; + + // should not suggest `*&variant.iter()` + for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + //~^ ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + //~| ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + eprintln!("{} {}", src, dest); + } + + // don't suggest add `variant.iter().clone().clone()` + for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + //~^ ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + //~| ERROR `&std::slice::Iter<'_, {integer}>` is not an iterator + eprintln!("{} {}", src, dest); + } +} diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr new file mode 100644 index 00000000000..a3ed51ace08 --- /dev/null +++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr @@ -0,0 +1,61 @@ +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:6:54 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + | -------------- ^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` +note: required by a bound in `std::iter::zip` + --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL +help: consider removing the leading `&`-reference + | +LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { +LL + for (src, dest) in std::iter::zip(fields.iter(), variant.iter()) { + | + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:6:24 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` + = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:13:54 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + | -------------- ^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator` + = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator` +note: required by a bound in `std::iter::zip` + --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL +help: consider removing the leading `&`-reference + | +LL - for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { +LL + for (src, dest) in std::iter::zip(fields.iter(), variant.iter().clone()) { + | + +error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator + --> $DIR/invalid-suggest-deref-issue-127590.rs:13:24 + | +LL | for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator` + = help: the trait `Iterator` is implemented for `std::slice::Iter<'a, T>` + = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator` + = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/issue-101739-1.rs b/tests/ui/transmutability/issue-101739-1.rs index 0695d7d409f..20bd7917e53 100644 --- a/tests/ui/transmutability/issue-101739-1.rs +++ b/tests/ui/transmutability/issue-101739-1.rs @@ -7,7 +7,6 @@ mod assert { where Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, //~ ERROR cannot find type `Dst` in this scope //~^ the constant `ASSUME_ALIGNMENT` is not of type `Assume` - //~| ERROR: mismatched types { } } diff --git a/tests/ui/transmutability/issue-101739-1.stderr b/tests/ui/transmutability/issue-101739-1.stderr index 6f79bf7b424..ba18a980f4d 100644 --- a/tests/ui/transmutability/issue-101739-1.stderr +++ b/tests/ui/transmutability/issue-101739-1.stderr @@ -13,13 +13,6 @@ LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, note: required by a const generic parameter in `BikeshedIntrinsicFrom` --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL -error[E0308]: mismatched types - --> $DIR/issue-101739-1.rs:8:41 - | -LL | Dst: BikeshedIntrinsicFrom<Src, ASSUME_ALIGNMENT>, - | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0412. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs index 1c0bd29d707..8b36bf3dcb1 100644 --- a/tests/ui/transmutability/issue-101739-2.rs +++ b/tests/ui/transmutability/issue-101739-2.rs @@ -16,7 +16,7 @@ mod assert { where Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied Src, - ASSUME_ALIGNMENT, //~ ERROR: mismatched types + ASSUME_ALIGNMENT, ASSUME_LIFETIMES, ASSUME_VALIDITY, ASSUME_VISIBILITY, diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index 38912696c18..519a374dc22 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -9,13 +9,6 @@ LL | | ASSUME_VALIDITY, LL | | ASSUME_VISIBILITY, | |_____________________________- help: remove these generic arguments -error[E0308]: mismatched types - --> $DIR/issue-101739-2.rs:19:13 - | -LL | ASSUME_ALIGNMENT, - | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0107, E0308. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/tuple/wrong_argument_ice-3.stderr b/tests/ui/tuple/wrong_argument_ice-3.stderr index ce21751f39d..78212ed1e76 100644 --- a/tests/ui/tuple/wrong_argument_ice-3.stderr +++ b/tests/ui/tuple/wrong_argument_ice-3.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 1 argument but 2 arguments were supplied --> $DIR/wrong_argument_ice-3.rs:9:16 | LL | groups.push(new_group, vec![process]); - | ^^^^ ------------- unexpected argument of type `Vec<&Process>` + | ^^^^ ------------- unexpected argument #2 of type `Vec<&Process>` | note: expected `(Vec<String>, Vec<Process>)`, found `Vec<String>` --> $DIR/wrong_argument_ice-3.rs:9:21 diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index db75a520c65..371f5b10988 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | LL | <E>::V(); - | ^^^^^^-- an argument of type `u8` is missing + | ^^^^^^-- argument #1 of type `u8` is missing | note: tuple variant defined here --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5 diff --git a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr index c9ac99ede6f..c21c59397c7 100644 --- a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr +++ b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr @@ -3,6 +3,11 @@ error[E0533]: expected value, found struct variant `Alias::Braced` | LL | Alias::Braced; | ^^^^^^^^^^^^^ not a value + | +help: you might have meant to create a new value of the struct + | +LL | Alias::Braced {}; + | ++ error[E0533]: expected unit struct, unit variant or constant, found struct variant `Alias::Braced` --> $DIR/incorrect-variant-form-through-alias-caught.rs:10:9 diff --git a/tests/ui/type/type-ascription-instead-of-initializer.stderr b/tests/ui/type/type-ascription-instead-of-initializer.stderr index 224ff6e7404..630e82d254e 100644 --- a/tests/ui/type/type-ascription-instead-of-initializer.stderr +++ b/tests/ui/type/type-ascription-instead-of-initializer.stderr @@ -11,7 +11,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | LL | let x: Vec::with_capacity(10, 20); - | ^^^^^^^^^^^^^^^^^^ -- unexpected argument of type `{integer}` + | ^^^^^^^^^^^^^^^^^^ -- unexpected argument #2 of type `{integer}` | note: associated function defined here --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 3deb234c275..5745b738532 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -13,7 +13,7 @@ fn main() { //~^ ERROR this method takes 2 arguments but 1 argument was supplied //~| NOTE this argument has type `i32`... //~| NOTE ... which causes `s` to have type `S<i32, _>` - //~| NOTE an argument is missing + //~| NOTE argument #2 is missing //~| HELP provide the argument //~| HELP change the type of the numeric literal from `i32` to `u32` let t: S<u32, _> = s; diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index 5f7bb8b9367..a953ca70ea2 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -2,7 +2,7 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied --> $DIR/point-at-inference-4.rs:12:7 | LL | s.infer(0i32); - | ^^^^^------ an argument is missing + | ^^^^^------ argument #2 is missing | note: method defined here --> $DIR/point-at-inference-4.rs:4:8 diff --git a/tests/ui/typeck/cyclic_type_ice.stderr b/tests/ui/typeck/cyclic_type_ice.stderr index bfff6830fc5..36715b4ee5d 100644 --- a/tests/ui/typeck/cyclic_type_ice.stderr +++ b/tests/ui/typeck/cyclic_type_ice.stderr @@ -13,7 +13,7 @@ error[E0057]: this function takes 2 arguments but 1 argument was supplied --> $DIR/cyclic_type_ice.rs:3:5 | LL | f(f); - | ^--- an argument is missing + | ^--- argument #2 is missing | note: closure defined here --> $DIR/cyclic_type_ice.rs:2:13 diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs index 193544ebd3f..9fc249198d0 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs @@ -5,7 +5,7 @@ trait Trait { - fn func<const N: u32>() -> [ (); N ]; //~ ERROR mismatched types + fn func<const N: u32>() -> [ (); N ]; //~ ERROR the constant `N` is not of type `usize` } struct S {} diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr index 16aaf0615ed..bff926a2081 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | fn func<const N: u32>() -> [ (); { () }] { | ^^ expected `usize`, found `()` -error[E0308]: mismatched types - --> $DIR/const-in-impl-fn-return-type.rs:8:38 +error: the constant `N` is not of type `usize` + --> $DIR/const-in-impl-fn-return-type.rs:8:32 | LL | fn func<const N: u32>() -> [ (); N ]; - | ^ expected `usize`, found `u32` + | ^^^^^^^^^ expected `usize`, found `u32` error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/remove-extra-argument.stderr b/tests/ui/typeck/remove-extra-argument.stderr index 4bab2959651..d4e0dcb50ae 100644 --- a/tests/ui/typeck/remove-extra-argument.stderr +++ b/tests/ui/typeck/remove-extra-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/remove-extra-argument.rs:6:5 | LL | l(vec![], vec![]) - | ^ ------ unexpected argument of type `Vec<_>` + | ^ ------ unexpected argument #2 of type `Vec<_>` | note: function defined here --> $DIR/remove-extra-argument.rs:3:4 diff --git a/tests/ui/typeck/struct-enum-wrong-args.stderr b/tests/ui/typeck/struct-enum-wrong-args.stderr index d005eca841e..e58d162901e 100644 --- a/tests/ui/typeck/struct-enum-wrong-args.stderr +++ b/tests/ui/typeck/struct-enum-wrong-args.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:6:13 | LL | let _ = Some(3, 2); - | ^^^^ - unexpected argument of type `{integer}` + | ^^^^ - unexpected argument #2 of type `{integer}` | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -16,9 +16,9 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:7:13 | LL | let _ = Ok(3, 6, 2); - | ^^ - - unexpected argument of type `{integer}` + | ^^ - - unexpected argument #3 of type `{integer}` | | - | unexpected argument of type `{integer}` + | unexpected argument #2 of type `{integer}` | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -32,7 +32,7 @@ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:8:13 | LL | let _ = Ok(); - | ^^-- an argument is missing + | ^^-- argument #1 is missing | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -45,7 +45,7 @@ error[E0061]: this struct takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:9:13 | LL | let _ = Wrapper(); - | ^^^^^^^-- an argument of type `i32` is missing + | ^^^^^^^-- argument #1 of type `i32` is missing | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -61,7 +61,7 @@ error[E0061]: this struct takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:10:13 | LL | let _ = Wrapper(5, 2); - | ^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^ - unexpected argument #2 of type `{integer}` | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -94,7 +94,7 @@ error[E0061]: this struct takes 2 arguments but 1 argument was supplied --> $DIR/struct-enum-wrong-args.rs:12:13 | LL | let _ = DoubleWrapper(5); - | ^^^^^^^^^^^^^--- an argument of type `i32` is missing + | ^^^^^^^^^^^^^--- argument #2 of type `i32` is missing | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 @@ -110,7 +110,7 @@ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:13:13 | LL | let _ = DoubleWrapper(5, 2, 7); - | ^^^^^^^^^^^^^ - unexpected argument of type `{integer}` + | ^^^^^^^^^^^^^ - unexpected argument #3 of type `{integer}` | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 diff --git a/tests/ui/variance/variance-unused-type-param.rs b/tests/ui/variance/variance-unused-type-param.rs index d1114064364..ef3c41ca556 100644 --- a/tests/ui/variance/variance-unused-type-param.rs +++ b/tests/ui/variance/variance-unused-type-param.rs @@ -11,11 +11,14 @@ enum SomeEnum<A> { Nothing } // Here T might *appear* used, but in fact it isn't. enum ListCell<T> { -//~^ ERROR parameter `T` is never used Cons(Box<ListCell<T>>), + //~^ ERROR parameter `T` is only used recursively Nil } +struct SelfTyAlias<T>(Box<Self>); +//~^ ERROR parameter `T` is only used recursively + struct WithBounds<T: Sized> {} //~^ ERROR parameter `T` is never used @@ -25,4 +28,9 @@ struct WithWhereBounds<T> where T: Sized {} struct WithOutlivesBounds<T: 'static> {} //~^ ERROR parameter `T` is never used +struct DoubleNothing<T> { +//~^ ERROR parameter `T` is never used + s: SomeStruct<T>, +} + fn main() {} diff --git a/tests/ui/variance/variance-unused-type-param.stderr b/tests/ui/variance/variance-unused-type-param.stderr index 3011b7bd18f..c747532e628 100644 --- a/tests/ui/variance/variance-unused-type-param.stderr +++ b/tests/ui/variance/variance-unused-type-param.stderr @@ -16,17 +16,30 @@ LL | enum SomeEnum<A> { Nothing } = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead -error[E0392]: type parameter `T` is never used - --> $DIR/variance-unused-type-param.rs:13:15 +error: type parameter `T` is only used recursively + --> $DIR/variance-unused-type-param.rs:14:23 | LL | enum ListCell<T> { - | ^ unused type parameter + | - type parameter must be used non-recursively in the definition +LL | Cons(Box<ListCell<T>>), + | ^ | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + = note: all type parameters must be used in a non-recursive way in order to constrain their variance + +error: type parameter `T` is only used recursively + --> $DIR/variance-unused-type-param.rs:19:27 + | +LL | struct SelfTyAlias<T>(Box<Self>); + | - ^^^^ + | | + | type parameter must be used non-recursively in the definition + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = note: all type parameters must be used in a non-recursive way in order to constrain their variance error[E0392]: type parameter `T` is never used - --> $DIR/variance-unused-type-param.rs:19:19 + --> $DIR/variance-unused-type-param.rs:22:19 | LL | struct WithBounds<T: Sized> {} | ^ unused type parameter @@ -34,7 +47,7 @@ LL | struct WithBounds<T: Sized> {} = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: type parameter `T` is never used - --> $DIR/variance-unused-type-param.rs:22:24 + --> $DIR/variance-unused-type-param.rs:25:24 | LL | struct WithWhereBounds<T> where T: Sized {} | ^ unused type parameter @@ -42,13 +55,25 @@ LL | struct WithWhereBounds<T> where T: Sized {} = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: type parameter `T` is never used - --> $DIR/variance-unused-type-param.rs:25:27 + --> $DIR/variance-unused-type-param.rs:28:27 | LL | struct WithOutlivesBounds<T: 'static> {} | ^ unused type parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` -error: aborting due to 6 previous errors +error[E0392]: type parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:31:22 + | +LL | struct DoubleNothing<T> { + | ^ unused type parameter +LL | +LL | s: SomeStruct<T>, + | - `T` is named here, but is likely unused in the containing type + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/variants/variant-namespacing.stderr b/tests/ui/variants/variant-namespacing.stderr index 9e91ff7178d..2a2491b81f9 100644 --- a/tests/ui/variants/variant-namespacing.stderr +++ b/tests/ui/variants/variant-namespacing.stderr @@ -11,7 +11,7 @@ LL | pub use variant_namespacing::XE::{XStruct, XTuple, XUnit}; help: you can use `as` to change the binding name of the import | LL | pub use variant_namespacing::XE::{XStruct as OtherXStruct, XTuple, XUnit}; - | ~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++++++ error[E0255]: the name `XTuple` is defined multiple times --> $DIR/variant-namespacing.rs:24:44 @@ -26,7 +26,7 @@ LL | pub use variant_namespacing::XE::{XStruct, XTuple, XUnit}; help: you can use `as` to change the binding name of the import | LL | pub use variant_namespacing::XE::{XStruct, XTuple as OtherXTuple, XUnit}; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++ error[E0255]: the name `XUnit` is defined multiple times --> $DIR/variant-namespacing.rs:24:52 @@ -41,7 +41,7 @@ LL | pub use variant_namespacing::XE::{XStruct, XTuple, XUnit}; help: you can use `as` to change the binding name of the import | LL | pub use variant_namespacing::XE::{XStruct, XTuple, XUnit as OtherXUnit}; - | ~~~~~~~~~~~~~~~~~~~ + | +++++++++++++ error[E0255]: the name `Struct` is defined multiple times --> $DIR/variant-namespacing.rs:28:13 @@ -56,7 +56,7 @@ LL | pub use E::{Struct, Tuple, Unit}; help: you can use `as` to change the binding name of the import | LL | pub use E::{Struct as OtherStruct, Tuple, Unit}; - | ~~~~~~~~~~~~~~~~~~~~~ + | ++++++++++++++ error[E0255]: the name `Tuple` is defined multiple times --> $DIR/variant-namespacing.rs:28:21 @@ -71,7 +71,7 @@ LL | pub use E::{Struct, Tuple, Unit}; help: you can use `as` to change the binding name of the import | LL | pub use E::{Struct, Tuple as OtherTuple, Unit}; - | ~~~~~~~~~~~~~~~~~~~ + | +++++++++++++ error[E0255]: the name `Unit` is defined multiple times --> $DIR/variant-namespacing.rs:28:28 @@ -86,7 +86,7 @@ LL | pub use E::{Struct, Tuple, Unit}; help: you can use `as` to change the binding name of the import | LL | pub use E::{Struct, Tuple, Unit as OtherUnit}; - | ~~~~~~~~~~~~~~~~~ + | ++++++++++++ error: aborting due to 6 previous errors diff --git a/triagebot.toml b/triagebot.toml index d47d54d45c0..5335cf4e4bf 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -905,7 +905,7 @@ cc = ["@kobzol"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514"] +users_on_vacation = ["jyn514", "jhpratt", "oli-obk"] [assign.adhoc_groups] compiler-team = [ @@ -928,6 +928,7 @@ compiler-team-contributors = [ "@fee1-dead", "@jieyouxu", "@BoxyUwU", + "@chenyukang", ] compiler = [ "compiler-team", @@ -976,6 +977,7 @@ diagnostics = [ "@estebank", "@oli-obk", "@TaKO8Ki", + "@chenyukang", ] parser = [ "@compiler-errors", @@ -989,6 +991,7 @@ lexer = [ "@nnethercote", "@petrochenkov", "@estebank", + "@chenyukang", ] arena = [ "@nnethercote", |
