From 1696f534abe0655ee43ed57972a62d1cce42c233 Mon Sep 17 00:00:00 2001 From: Sven Kanoldt Date: Wed, 9 Oct 2024 14:24:15 +0200 Subject: [PATCH 001/197] fix: rust-lang/rust#47446 - Add test for issue 47446 - Implement the new lint lint_builtin_mixed_export_name_and_no_mangle - Add suggestion how to fix it --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/Cargo.toml | 1 + compiler/rustc_codegen_ssa/messages.ftl | 5 ++ .../rustc_codegen_ssa/src/codegen_attrs.rs | 57 ++++++++++++++++++- compiler/rustc_codegen_ssa/src/errors.rs | 14 ++++- tests/ui/asm/naked-functions.rs | 1 - .../mixed_export_name_and_no_mangle.fixed | 14 +++++ .../mixed_export_name_and_no_mangle.rs | 16 ++++++ .../mixed_export_name_and_no_mangle.stderr | 39 +++++++++++++ 9 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle.fixed create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle.rs create mode 100644 tests/ui/attributes/mixed_export_name_and_no_mangle.stderr diff --git a/Cargo.lock b/Cargo.lock index b98c4fd0642d..762f98cd4ac9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3453,6 +3453,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", + "rustc_ast_pretty", "rustc_attr", "rustc_data_structures", "rustc_errors", diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index b898cfec7966..01cf9369df7e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -17,6 +17,7 @@ regex = "1.4" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 62db3d5a98cd..56188714b44f 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -201,6 +201,11 @@ codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering codegen_ssa_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified +codegen_ssa_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `#[export_name]` + .label = `{$no_mangle_attr}` is ignored + .note = `#[export_name]` takes precedence + .suggestion = remove the `{$no_mangle_attr}` attribute + codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 32e9422e005a..59c543bb3978 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,11 +3,10 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_nam use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{LangItem, lang_items}; +use rustc_hir::{self as hir, HirId, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -78,6 +77,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; + let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -116,7 +116,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::no_mangle => { if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + mixed_export_name_no_mangle_lint_state.track_no_mangle( + attr.span, + tcx.local_def_id_to_hir_id(did), + rustc_ast_pretty::pprust::attribute_to_string(attr), + ); } else { tcx.dcx() .struct_span_err( @@ -240,6 +245,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } codegen_fn_attrs.export_name = Some(s); + mixed_export_name_no_mangle_lint_state.track_export_name(attr.span); } } sym::target_feature => { @@ -513,6 +519,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); + codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if !attr.has_name(sym::inline) { return ia; @@ -779,6 +787,49 @@ fn check_link_name_xor_ordinal( } } +#[derive(Default)] +struct MixedExportNameAndNoMangleState { + export_name: Option, + hir_id: Option, + no_mangle: Option, + no_mangle_attr_name: Option, +} + +impl MixedExportNameAndNoMangleState { + fn track_export_name(&mut self, span: Span) { + self.export_name = Some(span); + } + + fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: String) { + self.no_mangle = Some(span); + self.hir_id = Some(hir_id); + self.no_mangle_attr_name = Some(attr_name); + } + + /// Emit diagnostics if the lint condition is met. + fn lint_if_mixed(self, tcx: TyCtxt<'_>) { + if let Self { + export_name: Some(export_name), + no_mangle: Some(no_mangle), + hir_id: Some(hir_id), + no_mangle_attr_name: Some(no_mangle_attr_name), + } = self + { + tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle, + errors::MixedExportNameAndNoMangle { + no_mangle, + no_mangle_attr: no_mangle_attr_name, + export_name, + removal_span: no_mangle, + }, + ); + } + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f93cb52ea3ea..00f8654e670b 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -10,7 +10,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; use rustc_span::{Span, Symbol}; @@ -1114,3 +1114,15 @@ impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ #[derive(Diagnostic)] #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; + +#[derive(LintDiagnostic)] +#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] +pub(crate) struct MixedExportNameAndNoMangle { + #[label] + pub no_mangle: Span, + pub no_mangle_attr: String, + #[note] + pub export_name: Span, + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub removal_span: Span, +} diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 5c58f1498cc9..e7e5d84f2a5d 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -219,7 +219,6 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[export_name = "exported_function_name"] #[link_section = ".custom_section"] -#[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed new file mode 100644 index 000000000000..7224d4289e3f --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed @@ -0,0 +1,14 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass + +#![warn(unused_attributes)] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "foo"] +pub fn bar() {} + +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "baz"] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs new file mode 100644 index 000000000000..149a7904e1ea --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs @@ -0,0 +1,16 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass + +#![warn(unused_attributes)] +#[no_mangle] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "foo"] +pub fn bar() {} + +#[unsafe(no_mangle)] +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "baz"] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr new file mode 100644 index 000000000000..ba63127ba2db --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr @@ -0,0 +1,39 @@ +warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]` + --> $DIR/mixed_export_name_and_no_mangle.rs:6:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ `#[no_mangle]` is ignored + | +note: `#[export_name]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle.rs:8:1 + | +LL | #[export_name = "foo"] + | ^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/mixed_export_name_and_no_mangle.rs:5:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ +help: remove the `#[no_mangle]` attribute + | +LL - #[no_mangle] + | + +warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` + --> $DIR/mixed_export_name_and_no_mangle.rs:11:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | +note: `#[export_name]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle.rs:13:1 + | +LL | #[export_name = "baz"] + | ^^^^^^^^^^^^^^^^^^^^^^ +help: remove the `#[unsafe(no_mangle)]` attribute + | +LL - #[unsafe(no_mangle)] + | + +warning: 2 warnings emitted + From 529aae6fc368818bf64d21aab217826a6c0745fc Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 18 Nov 2024 18:58:56 +0100 Subject: [PATCH 002/197] wasi/fs: Improve stopping condition for ::next When upgrading [Zed](https://github.com/zed-industries/zed/pull/19349) to Rust 1.82 I've encountered a test failure in our test suite. Specifically, one of our extension tests started hanging. I've tracked it down to a call to std::fs::remove_dir_all not returning when an extension is compiled with Rust 1.82 Our extension system uses WASM components, thus I've looked at the diff between 1.81 and 1.82 with respect to WASI and found 736f773844e7ebf05ccb827c17b7ad9eb28aa295 As it turned out, calling remove_dir_all from extension returned io::ErrorKind::NotFound in 1.81; the underlying issue is that the ReadDir iterator never actually terminates iteration, however since it loops around, with 1.81 we'd come across an entry second time and fail to remove it, since it would've been removed previously. With 1.82 and 736f773844e7ebf05ccb827c17b7ad9eb28aa295 it is no longer the case, thus we're seeing the hang. This commit makes ReadDir::next adhere to readdir contract, namely it will no longer call readdir once the returned # of bytes is smaller than the size of a passed-in buffer. Previously we'd only terminate the loop if readdir returned 0. --- library/std/src/sys/pal/wasi/fs.rs | 31 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 3296c762cca2..b519a0fe6a3a 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -172,20 +172,22 @@ impl Iterator for ReadDir { let offset = if self.offset == self.cap { let cookie = self.cookie.take()?; match self.inner.dir.fd.readdir(&mut self.buf, cookie) { - Ok(bytes) => self.cap = bytes, + Ok(bytes) => { + // No more entries if we read less than buffer size + if bytes < self.buf.len() { + self.cookie = None; + if bytes == 0 { + return None; + } + } else { + self.cookie = Some(cookie); + } + self.cap = self.buf.len(); + self.offset = 0; + 0 + } Err(e) => return Some(Err(e)), } - self.offset = 0; - self.cookie = Some(cookie); - - // If we didn't actually read anything, this is in theory the - // end of the directory. - if self.cap == 0 { - self.cookie = None; - return None; - } - - 0 } else { self.offset }; @@ -197,7 +199,6 @@ impl Iterator for ReadDir { // where we last left off. let dirent_size = mem::size_of::(); if data.len() < dirent_size { - assert!(self.cookie.is_some()); assert!(self.buf.len() >= dirent_size); self.offset = self.cap; continue; @@ -218,7 +219,9 @@ impl Iterator for ReadDir { self.offset = self.cap; continue; } - self.cookie = Some(dirent.d_next); + self.cookie.as_mut().map(|cookie| { + *cookie = dirent.d_next; + }); self.offset = offset + dirent_size + dirent.d_namlen as usize; let name = &data[..(dirent.d_namlen as usize)]; From 95bf87563a1d0eee53de6af41b7795a222c8a590 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 25 Nov 2024 14:52:58 +0200 Subject: [PATCH 003/197] Fix a bug when synthetic AST node were searched in the AST ID map and caused panics --- .../rust-analyzer/crates/hir-def/src/lower.rs | 26 ++++++++++- .../rust-analyzer/crates/hir/src/semantics.rs | 13 ++++-- .../src/handlers/add_missing_impl_members.rs | 45 +++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) 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 6d1a3d174479..350bb8d51724 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -2,7 +2,7 @@ use std::{cell::OnceCell, mem}; use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile}; -use span::{AstIdMap, AstIdNode}; +use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap}; use stdx::thin_vec::ThinVec; use syntax::ast; use triomphe::Arc; @@ -63,6 +63,30 @@ impl<'a> LowerCtx<'a> { } } + /// Prepares a `LowerCtx` for synthetic AST that needs to be lowered. This is intended for IDE things. + pub fn for_synthetic_ast( + db: &'a dyn DefDatabase, + ast_id_map: Arc, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, + ) -> Self { + let file_id = EditionedFileId::new( + FileId::from_raw(EditionedFileId::MAX_FILE_ID), + Edition::Edition2015, + ); + LowerCtx { + db, + // Make up an invalid file id, so that if we will try to actually access it salsa will panic. + file_id: file_id.into(), + span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(), + ast_id_map: ast_id_map.into(), + impl_trait_bounds: Vec::new(), + outer_impl_trait: false, + types_map, + types_source_map, + } + } + pub(crate) fn span_map(&self) -> &SpanMap { self.span_map.get_or_init(|| self.db.span_map(self.file_id)) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 9d3f8e5fba42..46766fcc5b10 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -34,7 +34,7 @@ use intern::Symbol; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use span::{EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; +use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, @@ -42,6 +42,7 @@ use syntax::{ AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::HirDatabase, @@ -1973,10 +1974,16 @@ impl SemanticsScope<'_> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option { + let root = ast_path.syntax().ancestors().last().unwrap(); + let ast_id_map = Arc::new(AstIdMap::from_source(&root)); let (mut types_map, mut types_source_map) = (TypesMap::default(), TypesSourceMap::default()); - let mut ctx = - LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map); + let mut ctx = LowerCtx::for_synthetic_ast( + self.db.upcast(), + ast_id_map, + &mut types_map, + &mut types_source_map, + ); let path = Path::from_src(&mut ctx, ast_path.clone())?; resolve_hir_path( self.db, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 7f8ea44fb12c..57df39d541e9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2318,4 +2318,49 @@ impl<'a> Test<'a, i32> for bool { "#, ); } + + #[test] + fn issue_17321() { + check_assist( + add_missing_impl_members, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct$0 {}"#, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct { + $0type Iter; +}"#, + ); + } } From f091ec669e3f46bbf62048cb2a4b42ea5d9536ad Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 25 Nov 2024 01:01:50 +0900 Subject: [PATCH 004/197] Migrate `add_turbo_fish` to `SyntaxEditor` --- .../src/handlers/add_turbo_fish.rs | 83 +++++++++++++------ .../src/ast/syntax_factory/constructors.rs | 18 ++++ 2 files changed, 77 insertions(+), 24 deletions(-) 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 17efbcbd6c9e..0f6970d9403e 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,8 +1,9 @@ use either::Either; use ide_db::defs::{Definition, NameRefClass}; use syntax::{ - ast::{self, make, HasArgList, HasGenericArgs}, - ted, AstNode, + ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs}, + syntax_editor::Position, + AstNode, }; use crate::{ @@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_type_ascription", AssistKind::RefactorRewrite), "Add `: _` before assignment operator", ident.text_range(), - |edit| { - let let_stmt = edit.make_mut(let_stmt); + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); if let_stmt.semicolon_token().is_none() { - ted::append_child(let_stmt.syntax(), make::tokens::semicolon()); + editor.insert( + Position::last_child_of(let_stmt.syntax()), + make::tokens::semicolon(), + ); } let placeholder_ty = make::ty_placeholder().clone_for_update(); - let_stmt.set_ty(Some(placeholder_ty.clone())); - - if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, placeholder_ty); + if let Some(pat) = let_stmt.pat() { + let elements = vec![ + make::token(syntax::SyntaxKind::COLON).into(), + make::token(syntax::SyntaxKind::WHITESPACE).into(), + placeholder_ty.syntax().clone().into(), + ]; + editor.insert_all(Position::after(pat.syntax()), elements); + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation( + placeholder_ty.syntax(), + builder.make_placeholder_snippet(cap), + ); + } } + + builder.add_file_edits(ctx.file_id(), editor); }, )? } else { @@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_turbo_fish", AssistKind::RefactorRewrite), "Add `::<>`", ident.text_range(), - |edit| { - edit.trigger_parameter_hints(); + |builder| { + builder.trigger_parameter_hints(); - let new_arg_list = match turbofish_target { + let make = SyntaxFactory::new(); + let mut editor = match &turbofish_target { + Either::Left(it) => builder.make_editor(it.syntax()), + Either::Right(it) => builder.make_editor(it.syntax()), + }; + + let fish_head = get_fish_head(&make, number_of_arguments); + + match turbofish_target { Either::Left(path_segment) => { - edit.make_mut(path_segment).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = path_segment.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + editor.insert( + Position::last_child_of(path_segment.syntax()), + fish_head.syntax(), + ); + } } Either::Right(method_call) => { - edit.make_mut(method_call).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = method_call.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + let position = if let Some(arg_list) = method_call.arg_list() { + Position::before(arg_list.syntax()) + } else { + Position::last_child_of(method_call.syntax()) + }; + editor.insert(position, fish_head.syntax()); + } } }; - let fish_head = get_fish_head(number_of_arguments).clone_for_update(); - - // Note: we need to replace the `new_arg_list` instead of being able to use something like - // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list` - // always creates a non-turbofish form generic arg list. - ted::replace(new_arg_list.syntax(), fish_head.syntax()); - if let Some(cap) = ctx.config.snippet_cap { for arg in fish_head.generic_args() { - edit.add_placeholder_snippet(cap, arg) + editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap)); } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } /// This will create a turbofish generic arg list corresponding to the number of arguments -fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList { +fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); - make::turbofish_generic_arg_list(args) + make.turbofish_generic_arg_list(args) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 9f88add0f787..6e90b2ba47fe 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -107,4 +107,22 @@ impl SyntaxFactory { ast } + + pub fn turbofish_generic_arg_list( + &self, + args: impl IntoIterator + Clone, + ) -> ast::GenericArgList { + let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + args.into_iter().map(|arg| arg.syntax().clone()), + ast.generic_args().map(|arg| arg.syntax().clone()), + ); + builder.finish(&mut mapping); + } + + ast + } } From ec5f41a9531947cd87d7daca124e2e7b55f23b35 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Sat, 23 Nov 2024 21:28:09 +0100 Subject: [PATCH 005/197] Run TLS destructors for wasm32-wasip1-threads The target has support for pthreads and allows registration of TLS destructors. --- .../std/src/sys/thread_local/guard/wasi.rs | 71 +++++++++++++++++++ library/std/src/sys/thread_local/mod.rs | 3 + 2 files changed, 74 insertions(+) create mode 100644 library/std/src/sys/thread_local/guard/wasi.rs diff --git a/library/std/src/sys/thread_local/guard/wasi.rs b/library/std/src/sys/thread_local/guard/wasi.rs new file mode 100644 index 000000000000..dfd1f126aa0f --- /dev/null +++ b/library/std/src/sys/thread_local/guard/wasi.rs @@ -0,0 +1,71 @@ +//! wasm32-wasip1 has pthreads support. + +use crate::cell::Cell; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sys::thread_local::destructors; +use crate::{ffi, ptr}; + +// Add a few symbols not in upstream `libc` just yet. +mod libc { + pub use libc::*; + + use crate::ffi; + + #[allow(non_camel_case_types)] + pub type pthread_key_t = ffi::c_uint; + + extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: unsafe extern "C" fn(*mut ffi::c_void), + ) -> ffi::c_int; + + pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; + } +} + +pub fn enable() { + enable_main(); + enable_thread(); +} + +fn enable_main() { + static REGISTERED: AtomicBool = AtomicBool::new(false); + + if !REGISTERED.swap(true, Ordering::AcqRel) { + unsafe { + assert_eq!(libc::atexit(run_main_dtors), 0); + } + } + + extern "C" fn run_main_dtors() { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + } +} + +fn enable_thread() { + #[thread_local] + static REGISTERED: Cell = Cell::new(false); + + if !REGISTERED.replace(true) { + unsafe { + let mut key: libc::pthread_key_t = 0; + assert_eq!(libc::pthread_key_create(&mut key, run_thread_dtors), 0); + + // We must set the value to a non-NULL pointer value so that + // the destructor is run on thread exit. The pointer is only + // passed to run_dtors and never dereferenced. + assert_eq!(libc::pthread_setspecific(key, ptr::without_provenance(1)), 0); + } + } + + extern "C" fn run_thread_dtors(_: *mut ffi::c_void) { + unsafe { + destructors::run(); + crate::rt::thread_cleanup(); + } + } +} diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 31d3b4390600..042f0f76c9a4 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -85,6 +85,9 @@ pub(crate) mod guard { } else if #[cfg(target_os = "windows")] { mod windows; pub(crate) use windows::enable; + } else if #[cfg(all(target_os = "wasi"))] { + mod wasi; + pub(crate) use wasi::enable; } else if #[cfg(any( target_family = "wasm", target_os = "uefi", From c876903523d59ae902970556ebe383605540c4af Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Tue, 26 Nov 2024 00:42:27 -0500 Subject: [PATCH 006/197] Add macro expansion test for raw variable names --- .../src/macro_expansion_tests/mbe/matching.rs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index 23d8b023b8bb..e9a977da913b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -184,3 +184,31 @@ fn test() { "#]], ); } + +#[test] +fn meta_variable_raw_name_equals_non_raw() { + check( + r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + m!(1234) +} +"#, + expect![[r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + 1234 +} +"#]], + ); +} From 68227a3777c7bf8ba6a69e2b8871d224504d1c31 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sat, 17 Aug 2024 05:32:09 +0100 Subject: [PATCH 007/197] Pass end position of span through inline ASM cookie --- compiler/rustc_codegen_llvm/src/asm.rs | 21 +- compiler/rustc_codegen_llvm/src/back/write.rs | 23 +- .../rustc_codegen_llvm/src/llvm/diagnostic.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_codegen_ssa/src/back/write.rs | 21 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 +- compiler/rustc_span/src/lib.rs | 6 + tests/ui/asm/aarch64/srcloc.new.stderr | 320 +++++++++++++++++ .../{srcloc.stderr => srcloc.old.stderr} | 48 +-- tests/ui/asm/aarch64/srcloc.rs | 3 + tests/ui/asm/inline-syntax.arm.stderr | 24 +- tests/ui/asm/inline-syntax.arm_llvm_18.stderr | 90 +++++ tests/ui/asm/inline-syntax.rs | 16 +- tests/ui/asm/inline-syntax.x86_64.stderr | 14 +- .../riscv/riscv32e-registers.riscv32e.stderr | 64 ++-- ...riscv32e-registers.riscv32e_llvm_18.stderr | 194 ++++++++++ .../riscv/riscv32e-registers.riscv32em.stderr | 64 ++-- ...iscv32e-registers.riscv32em_llvm_18.stderr | 194 ++++++++++ .../riscv32e-registers.riscv32emc.stderr | 64 ++-- ...scv32e-registers.riscv32emc_llvm_18.stderr | 194 ++++++++++ tests/ui/asm/riscv/riscv32e-registers.rs | 14 +- tests/ui/asm/x86_64/srcloc.new.stderr | 332 ++++++++++++++++++ .../{srcloc.stderr => srcloc.old.stderr} | 50 +-- tests/ui/asm/x86_64/srcloc.rs | 3 + 24 files changed, 1565 insertions(+), 200 deletions(-) create mode 100644 tests/ui/asm/aarch64/srcloc.new.stderr rename tests/ui/asm/aarch64/{srcloc.stderr => srcloc.old.stderr} (88%) create mode 100644 tests/ui/asm/inline-syntax.arm_llvm_18.stderr create mode 100644 tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr create mode 100644 tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr create mode 100644 tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr create mode 100644 tests/ui/asm/x86_64/srcloc.new.stderr rename tests/ui/asm/x86_64/{srcloc.stderr => srcloc.old.stderr} (90%) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 6ee80c08d4ad..aee6d20ad790 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -504,14 +504,13 @@ pub(crate) fn inline_asm_call<'ll>( let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext( bx.llcx, - key.as_ptr() as *const c_char, + key.as_ptr().cast::(), key.len() as c_uint, ); - // srcloc contains one integer for each line of assembly code. - // Unfortunately this isn't enough to encode a full span so instead - // we just encode the start position of each line. - // FIXME: Figure out a way to pass the entire line spans. + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. let mut srcloc = vec![]; if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { // LLVM inserts an extra line to add the ".intel_syntax", so add @@ -521,13 +520,13 @@ pub(crate) fn inline_asm_call<'ll>( // due to the asm template string coming from a macro. LLVM will // default to the first srcloc for lines that don't have an // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_i32(0))); + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } - srcloc.extend( - line_spans - .iter() - .map(|span| llvm::LLVMValueAsMetadata(bx.const_i32(span.lo().to_u32() as i32))), - ); + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata(bx.const_u64( + u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), + )) + })); let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); llvm::LLVMSetMetadata(call, kind, md); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 00f7b479fa76..89595af38a55 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -25,8 +25,8 @@ use rustc_session::Session; use rustc_session::config::{ self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath, }; -use rustc_span::InnerSpan; use rustc_span::symbol::sym; +use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext}; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::debug; @@ -413,21 +413,32 @@ fn report_inline_asm( cgcx: &CodegenContext, msg: String, level: llvm::DiagnosticLevel, - mut cookie: u64, + cookie: u64, source: Option<(String, Vec)>, ) { // In LTO build we may get srcloc values from other crates which are invalid // since they use a different source map. To be safe we just suppress these // in LTO builds. - if matches!(cgcx.lto, Lto::Fat | Lto::Thin) { - cookie = 0; - } + let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { + SpanData::default() + } else { + let lo = BytePos::from_u32(cookie as u32); + let hi = BytePos::from_u32((cookie >> 32) as u32); + SpanData { + lo, + // LLVM version < 19 silently truncates the cookie to 32 bits in some situations. + hi: if hi.to_u32() != 0 { hi } else { lo }, + ctxt: SyntaxContext::root(), + parent: None, + } + }; let level = match level { llvm::DiagnosticLevel::Error => Level::Error, llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; - cgcx.diag_emitter.inline_asm_error(cookie.try_into().unwrap(), msg, level, source); + let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); + cgcx.diag_emitter.inline_asm_error(span, msg, level, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index a4cb5a25d1b3..11043b664f52 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -151,7 +151,7 @@ impl InlineAsmDiagnostic { unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { level: smdiag.level, - cookie: cookie.into(), + cookie, message: smdiag.message, source: smdiag.source, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 17b0ec4b9360..af49d57cc606 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2316,7 +2316,7 @@ unsafe extern "C" { pub fn LLVMRustGetSMDiagnostic<'a>( DI: &'a DiagnosticInfo, - cookie_out: &mut c_uint, + cookie_out: &mut u64, ) -> &'a SMDiagnostic; pub fn LLVMRustUnpackSMDiagnostic( diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7c0e9cfd5a76..fc98fa381320 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -34,7 +34,7 @@ use rustc_session::config::{ }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; +use rustc_span::{FileName, InnerSpan, Span, SpanData}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -1837,7 +1837,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String, Level, Option<(String, Vec)>), + InlineAsmError(SpanData, String, Level, Option<(String, Vec)>), Fatal(String), } @@ -1859,12 +1859,12 @@ impl SharedEmitter { pub fn inline_asm_error( &self, - cookie: u32, + span: SpanData, msg: String, level: Level, source: Option<(String, Vec)>, ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source))); } fn fatal(&self, msg: &str) { @@ -1949,17 +1949,12 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); sess.dcx().abort_if_errors(); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { + Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => { assert_matches!(level, Level::Error | Level::Warning | Level::Note); - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let mut err = Diag::<()>::new(sess.dcx(), level, msg); - - // If the cookie is 0 then we don't have span information. - if cookie != 0 { - let pos = BytePos::from_u32(cookie); - let span = Span::with_root_ctxt(pos, pos); - err.span(span); - }; + if !span.is_dummy() { + err.span(span.span()); + } // Point to the generated assembly if it is available. if let Some((buffer, spans)) = source { diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 06550728f0f6..b79205ff946d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1535,7 +1535,7 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, - unsigned *Cookie) { + uint64_t *Cookie) { llvm::DiagnosticInfoSrcMgr *SM = static_cast(unwrap(DI)); *Cookie = SM->getLocCookie(); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 1481e1cbd918..9437a422d9ba 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -521,6 +521,12 @@ impl SpanData { } } +impl Default for SpanData { + fn default() -> Self { + Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None } + } +} + impl PartialOrd for Span { fn partial_cmp(&self, rhs: &Self) -> Option { PartialOrd::partial_cmp(&self.data(), &rhs.data()) diff --git a/tests/ui/asm/aarch64/srcloc.new.stderr b/tests/ui/asm/aarch64/srcloc.new.stderr new file mode 100644 index 000000000000..b92a07e5fb13 --- /dev/null +++ b/tests/ui/asm/aarch64/srcloc.new.stderr @@ -0,0 +1,320 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:15:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:19:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:24:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:30:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:37:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:42:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:46:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:52:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:59:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:66:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:73:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:81:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:128:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^ + +error: aborting due to 24 previous errors + diff --git a/tests/ui/asm/aarch64/srcloc.stderr b/tests/ui/asm/aarch64/srcloc.old.stderr similarity index 88% rename from tests/ui/asm/aarch64/srcloc.stderr rename to tests/ui/asm/aarch64/srcloc.old.stderr index 2e17b60b9124..2a15e48f0256 100644 --- a/tests/ui/asm/aarch64/srcloc.stderr +++ b/tests/ui/asm/aarch64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:12:15 + --> $DIR/srcloc.rs:15:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:16:13 + --> $DIR/srcloc.rs:19:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:21:13 + --> $DIR/srcloc.rs:24:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:27:13 + --> $DIR/srcloc.rs:30:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:34:13 + --> $DIR/srcloc.rs:37:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:39:14 + --> $DIR/srcloc.rs:42:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:43:14 + --> $DIR/srcloc.rs:46:14 | LL | "invalid_instruction", | ^ @@ -83,7 +83,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:49:14 + --> $DIR/srcloc.rs:52:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:56:14 + --> $DIR/srcloc.rs:59:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:63:13 + --> $DIR/srcloc.rs:66:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:70:13 + --> $DIR/srcloc.rs:73:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:77:14 + --> $DIR/srcloc.rs:80:14 | LL | "invalid_instruction1", | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:78:14 + --> $DIR/srcloc.rs:81:14 | LL | "invalid_instruction2", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:125:14 + --> $DIR/srcloc.rs:128:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/aarch64/srcloc.rs b/tests/ui/asm/aarch64/srcloc.rs index c635fa6ba700..9b92dfef056d 100644 --- a/tests/ui/asm/aarch64/srcloc.rs +++ b/tests/ui/asm/aarch64/srcloc.rs @@ -1,7 +1,10 @@ +//@ revisions: old new //@ only-aarch64 //@ build-fail //@ needs-asm-support //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 61e5078d6d9b..e36ec125d13f 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -15,10 +15,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -27,10 +27,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -39,10 +39,10 @@ LL | .intel_syntax aaa noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -51,10 +51,10 @@ LL | .att_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -63,10 +63,10 @@ LL | .att_syntax bbb noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :1:2 @@ -75,10 +75,10 @@ LL | .intel_syntax noprefix; nop | ^ error: unknown directive - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> :2:13 diff --git a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr new file mode 100644 index 000000000000..ada3f4891d3a --- /dev/null +++ b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr @@ -0,0 +1,90 @@ +error: unknown directive + | +note: instantiated into assembly here + --> :1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + | +note: instantiated into assembly here + --> :1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:35:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:39:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax aaa noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:43:15 + | +LL | asm!(".att_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .att_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:47:15 + | +LL | asm!(".att_syntax bbb noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .att_syntax bbb noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:51:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | .intel_syntax noprefix; nop + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:58:13 + | +LL | .intel_syntax noprefix + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | .intel_syntax noprefix + | ^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index b8486527e6fd..fda79b2afa38 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -1,10 +1,16 @@ -//@ revisions: x86_64 arm +//@ revisions: x86_64 arm_llvm_18 arm //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 +//@[arm_llvm_18] compile-flags: --target armv7-unknown-linux-gnueabihf +//@[arm_llvm_18] build-fail +//@[arm_llvm_18] needs-llvm-components: arm +//@[arm_llvm_18] ignore-llvm-version: 19 - 99 +// LLVM 19+ has full support for 64-bit cookies. //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf //@[arm] build-fail //@[arm] needs-llvm-components: arm +//@[arm] min-llvm-version: 19 //@ needs-asm-support #![feature(no_core, lang_items, rustc_attrs)] @@ -29,18 +35,23 @@ pub fn main() { asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax aaa noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax bbb noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax noprefix; nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!( r" @@ -49,9 +60,10 @@ pub fn main() { ); //[x86_64]~^^^ WARN avoid using `.intel_syntax` //[arm]~^^^^ ERROR unknown directive + //[arm_llvm_18]~^^^^^ ERROR unknown directive } } global_asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` -// Assembler errors don't have line numbers, so no error on ARM +// Global assembly errors don't have line numbers, so no error on ARM. diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr index 59c95194322a..66dc37f3089e 100644 --- a/tests/ui/asm/inline-syntax.x86_64.stderr +++ b/tests/ui/asm/inline-syntax.x86_64.stderr @@ -1,5 +1,5 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:55:14 + --> $DIR/inline-syntax.rs:67:14 | LL | global_asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop"); = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr index e7a86805b260..ac1373f0e2df 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr new file mode 100644 index 000000000000..f140f54adc55 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr index e7a86805b260..ac1373f0e2df 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr new file mode 100644 index 000000000000..f140f54adc55 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr index e7a86805b260..ac1373f0e2df 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> :1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr new file mode 100644 index 000000000000..f140f54adc55 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> :1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.rs b/tests/ui/asm/riscv/riscv32e-registers.rs index 57b1e169a046..c3fe19991b0a 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.rs +++ b/tests/ui/asm/riscv/riscv32e-registers.rs @@ -1,15 +1,27 @@ // Test that loads into registers x16..=x31 are never generated for riscv32{e,em,emc} targets // //@ build-fail -//@ revisions: riscv32e riscv32em riscv32emc +//@ revisions: riscv32e riscv32em riscv32emc riscv32e_llvm_18 riscv32em_llvm_18 riscv32emc_llvm_18 // //@ compile-flags: --crate-type=rlib //@ [riscv32e] needs-llvm-components: riscv //@ [riscv32e] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32e] min-llvm-version: 19 //@ [riscv32em] needs-llvm-components: riscv //@ [riscv32em] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32em] min-llvm-version: 19 //@ [riscv32emc] needs-llvm-components: riscv //@ [riscv32emc] compile-flags: --target=riscv32emc-unknown-none-elf +//@ [riscv32emc] min-llvm-version: 19 +//@ [riscv32e_llvm_18] needs-llvm-components: riscv +//@ [riscv32e_llvm_18] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32e_llvm_18] ignore-llvm-version: 19 - 99 +//@ [riscv32em_llvm_18] needs-llvm-components: riscv +//@ [riscv32em_llvm_18] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32em_llvm_18] ignore-llvm-version: 19 - 99 +//@ [riscv32emc_llvm_18] needs-llvm-components: riscv +//@ [riscv32emc_llvm_18] compile-flags: --target=riscv32emc-unknown-none-elf +//@ [riscv32emc_llvm_18] ignore-llvm-version: 19 - 99 // Unlike bad-reg.rs, this tests if the assembler can reject invalid registers // usage in assembly code. diff --git a/tests/ui/asm/x86_64/srcloc.new.stderr b/tests/ui/asm/x86_64/srcloc.new.stderr new file mode 100644 index 000000000000..7211f1ab69dc --- /dev/null +++ b/tests/ui/asm/x86_64/srcloc.new.stderr @@ -0,0 +1,332 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:14:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:18:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:23:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:29:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:36:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:41:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:44:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:48:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:54:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:61:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:68:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:75:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:82:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:83:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> :6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:130:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted + diff --git a/tests/ui/asm/x86_64/srcloc.stderr b/tests/ui/asm/x86_64/srcloc.old.stderr similarity index 90% rename from tests/ui/asm/x86_64/srcloc.stderr rename to tests/ui/asm/x86_64/srcloc.old.stderr index 8899c1b916bd..edb9ee46812f 100644 --- a/tests/ui/asm/x86_64/srcloc.stderr +++ b/tests/ui/asm/x86_64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:11:15 + --> $DIR/srcloc.rs:14:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:15:13 + --> $DIR/srcloc.rs:18:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:20:13 + --> $DIR/srcloc.rs:23:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:26:13 + --> $DIR/srcloc.rs:29:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:33:13 + --> $DIR/srcloc.rs:36:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:38:14 + --> $DIR/srcloc.rs:41:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:41:15 + --> $DIR/srcloc.rs:44:15 | LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); | ^ @@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2) | ^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:45:14 + --> $DIR/srcloc.rs:48:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:51:14 + --> $DIR/srcloc.rs:54:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:58:14 + --> $DIR/srcloc.rs:61:14 | LL | "invalid_instruction", | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:65:13 + --> $DIR/srcloc.rs:68:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:72:13 + --> $DIR/srcloc.rs:75:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:79:14 + --> $DIR/srcloc.rs:82:14 | LL | "invalid_instruction1", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:80:14 + --> $DIR/srcloc.rs:83:14 | LL | "invalid_instruction2", | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -287,7 +287,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:127:14 + --> $DIR/srcloc.rs:130:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index 2938bafe5e70..40fc66cbc929 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,6 +1,9 @@ +//@ revisions: old new //@ only-x86_64 //@ build-fail //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; From 692c19ae8032f80fc75912b98651bfc841cfbaf0 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:45:17 +0100 Subject: [PATCH 008/197] Refactor ReadDir into a state machine --- library/std/src/sys/pal/wasi/fs.rs | 169 +++++++++++++++++------------ 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index b519a0fe6a3a..5c6ddfa559ec 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -27,10 +27,26 @@ pub struct FileAttr { pub struct ReadDir { inner: Arc, - cookie: Option, - buf: Vec, - offset: usize, - cap: usize, + state: ReadDirState, +} + +enum ReadDirState { + /// Next DirEntry should be read from contents of buf at `offset` + FillBuffer { + next_read_offset: wasi::Dircookie, + buf: Vec, + }, + ProcessEntry { + buf: Vec, + next_read_offset: Option, + offset: usize, + }, + /// Do not fetch any more entries, process all entries + RunUntilExhaustion { + buf: Vec, + offset: usize, + }, + Done, } struct ReadDirInner { @@ -147,11 +163,8 @@ impl FileType { impl ReadDir { fn new(dir: File, root: PathBuf) -> ReadDir { ReadDir { - cookie: Some(0), - buf: vec![0; 128], - offset: 0, - cap: 0, inner: Arc::new(ReadDirInner { dir, root }), + state: ReadDirState::FillBuffer { next_read_offset: 0, buf: vec![0; 128] }, } } } @@ -162,81 +175,99 @@ impl fmt::Debug for ReadDir { } } +impl core::iter::FusedIterator for ReadDir {} + impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - loop { - // If we've reached the capacity of our buffer then we need to read - // some more from the OS, otherwise we pick up at our old offset. - let offset = if self.offset == self.cap { - let cookie = self.cookie.take()?; - match self.inner.dir.fd.readdir(&mut self.buf, cookie) { - Ok(bytes) => { - // No more entries if we read less than buffer size - if bytes < self.buf.len() { - self.cookie = None; - if bytes == 0 { - return None; - } + match &mut self.state { + ReadDirState::FillBuffer { next_read_offset, ref mut buf } => { + let result = self.inner.dir.fd.readdir(buf, *next_read_offset); + match result { + Ok(read_bytes) => { + if read_bytes < buf.len() { + buf.truncate(read_bytes); + self.state = + ReadDirState::RunUntilExhaustion { buf: mem::take(buf), offset: 0 }; } else { - self.cookie = Some(cookie); + debug_assert_eq!(read_bytes, buf.len()); + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: 0, + next_read_offset: Some(*next_read_offset), + }; } - self.cap = self.buf.len(); - self.offset = 0; - 0 + self.next() + } + Err(e) => { + self.state = ReadDirState::Done; + return Some(Err(e)); } - Err(e) => return Some(Err(e)), } - } else { - self.offset - }; - let data = &self.buf[offset..self.cap]; - - // If we're not able to read a directory entry then that means it - // must have been truncated at the end of the buffer, so reset our - // offset so we can go back and reread into the buffer, picking up - // where we last left off. - let dirent_size = mem::size_of::(); - if data.len() < dirent_size { - assert!(self.buf.len() >= dirent_size); - self.offset = self.cap; - continue; } - let (dirent, data) = data.split_at(dirent_size); - let dirent = unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; + ReadDirState::ProcessEntry { ref mut buf, next_read_offset, offset } => { + let contents = &buf[*offset..]; + const DIRENT_SIZE: usize = crate::mem::size_of::(); + if contents.len() >= DIRENT_SIZE { + let (dirent, data) = contents.split_at(DIRENT_SIZE); + let dirent = + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; + // If the file name was truncated, then we need to reinvoke + // `readdir` so we truncate our buffer to start over and reread this + // descriptor. + if data.len() < dirent.d_namlen as usize { + if buf.len() < dirent.d_namlen as usize + DIRENT_SIZE { + buf.resize(dirent.d_namlen as usize + DIRENT_SIZE, 0); + } + if let Some(next_read_offset) = *next_read_offset { + self.state = + ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; + } - // If the file name was truncated, then we need to reinvoke - // `readdir` so we truncate our buffer to start over and reread this - // descriptor. Note that if our offset is 0 that means the file name - // is massive and we need a bigger buffer. - if data.len() < dirent.d_namlen as usize { - if offset == 0 { - let amt_to_add = self.buf.capacity(); - self.buf.extend(iter::repeat(0).take(amt_to_add)); + return self.next(); + } + next_read_offset.as_mut().map(|cookie| { + *cookie = dirent.d_next; + }); + *offset = *offset + DIRENT_SIZE + dirent.d_namlen as usize; + + let name = &data[..(dirent.d_namlen as usize)]; + + // These names are skipped on all other platforms, so let's skip + // them here too + if name == b"." || name == b".." { + return self.next(); + } + + return Some(Ok(DirEntry { + meta: dirent, + name: name.to_vec(), + inner: self.inner.clone(), + })); + } else if let Some(next_read_offset) = *next_read_offset { + self.state = ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; } - assert!(self.cookie.is_some()); - self.offset = self.cap; - continue; + self.next() } - self.cookie.as_mut().map(|cookie| { - *cookie = dirent.d_next; - }); - self.offset = offset + dirent_size + dirent.d_namlen as usize; + ReadDirState::RunUntilExhaustion { buf, offset } => { + if *offset >= buf.len() { + self.state = ReadDirState::Done; + } else { + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: *offset, + next_read_offset: None, + }; + } - let name = &data[..(dirent.d_namlen as usize)]; - - // These names are skipped on all other platforms, so let's skip - // them here too - if name == b"." || name == b".." { - continue; + self.next() } - - return Some(Ok(DirEntry { - meta: dirent, - name: name.to_vec(), - inner: self.inner.clone(), - })); + ReadDirState::Done => None, } } } From 4866fb457a396669fc2d96a8cf5938f4cce5e162 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 26 Nov 2024 18:37:39 +0100 Subject: [PATCH 009/197] Revert #18197 Our first attempt to make flycheck only check the current crate if the crate is one of bin/bench/test targets had caused `check_workspace` to be ignored, which should have been a config with higher precedence all along. This commit revert #18197 and closes #18562 --- .../crates/rust-analyzer/src/handlers/notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bb03eb3c89b0..49b1ba32a795 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 @@ -380,7 +380,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { if id == flycheck.id() { updated = true; match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) && target.is_some() + !world.config.flycheck_workspace(source_root_id) || target.is_some() }) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), From c33c9518f0a4eed527139a9fc34459a5ca83c229 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 26 Nov 2024 18:54:25 +0100 Subject: [PATCH 010/197] Remove target.is_some() to handle it later inside ra::flycheck --- .../crates/rust-analyzer/src/handlers/notification.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 49b1ba32a795..5e7262b14ca9 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 @@ -379,9 +379,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { for (id, package) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) || target.is_some() - }) { + match package.filter(|_| !world.config.flycheck_workspace(source_root_id)) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), None => flycheck.restart_workspace(saved_file.clone()), From f4ab9829e1a3c6e564f79c98f39632aecbc675d3 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 26 Nov 2024 22:46:12 +0100 Subject: [PATCH 011/197] chore: Improve doc comments --- library/std/src/sys/pal/wasi/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 5c6ddfa559ec..9e233436a844 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -31,7 +31,7 @@ pub struct ReadDir { } enum ReadDirState { - /// Next DirEntry should be read from contents of buf at `offset` + /// Fill `buf` with `buf.len()` bytes starting from `next_read_offset`. FillBuffer { next_read_offset: wasi::Dircookie, buf: Vec, @@ -41,7 +41,8 @@ enum ReadDirState { next_read_offset: Option, offset: usize, }, - /// Do not fetch any more entries, process all entries + /// There is no more data to get in [`Self::FillBuffer`]; keep returning + /// entries via ProcessEntry until `buf` is exhausted. RunUntilExhaustion { buf: Vec, offset: usize, From f3d83ba114d9c84fd190d3ba4ef58fe87afe2bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 28 Nov 2024 16:01:40 +0200 Subject: [PATCH 012/197] Preparing for merge from rust-lang/rust --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 8f41ed9e14f9..945939a2ff47 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f005c7437def424a1c43cbc380352a58d8ac920b +9b4d7c6a40b328d212095c28670c629facf1557d From fa87a3e88942e407a2214728bb466620f538d13d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 28 Nov 2024 23:34:47 +0200 Subject: [PATCH 013/197] Change `GetManyMutError` to match T-libs-api decision That is, differentiate between out-of-bounds and overlapping indices, and remove the generic parameter `N`. I also exported `GetManyMutError` from `alloc` (and `std`), which was apparently forgotten. Changing the error to carry additional details means LLVM no longer generates separate short-circuiting branches for the checks, instead it generates one branch at the end. I therefore changed the code to use early returns to make LLVM generate jumps. Benchmark results between the approaches are somewhat mixed, but I chose this approach because it is significantly faster with ranges and also faster with `unwrap()`. --- library/alloc/src/slice.rs | 2 ++ library/core/src/error.rs | 2 +- library/core/src/slice/mod.rs | 58 +++++++++++++++++++---------------- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index e3c7835f1d10..edc8d99f2f99 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -27,6 +27,8 @@ pub use core::slice::ArrayChunksMut; pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; +#[unstable(feature = "get_many_mut", issue = "104642")] +pub use core::slice::GetManyMutError; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[cfg(not(no_global_oom_handling))] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 95a39cc3aed3..91549f49f9f9 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1076,4 +1076,4 @@ impl Error for crate::time::TryFromFloatSecsError {} impl Error for crate::ffi::FromBytesUntilNulError {} #[unstable(feature = "get_many_mut", issue = "104642")] -impl Error for crate::slice::GetManyMutError {} +impl Error for crate::slice::GetManyMutError {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ee91479bb1a9..40b197f8f18a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4627,13 +4627,11 @@ impl [T] { pub fn get_many_mut( &mut self, indices: [I; N], - ) -> Result<[&mut I::Output; N], GetManyMutError> + ) -> Result<[&mut I::Output; N], GetManyMutError> where I: GetManyMutIndex + SliceIndex, { - if !get_many_check_valid(&indices, self.len()) { - return Err(GetManyMutError { _private: () }); - } + get_many_check_valid(&indices, self.len())?; // SAFETY: The `get_many_check_valid()` call checked that all indices // are disjunct and in bounds. unsafe { Ok(self.get_many_unchecked_mut(indices)) } @@ -4976,53 +4974,59 @@ impl SlicePattern for [T; N] { /// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` /// comparison operations. #[inline] -fn get_many_check_valid(indices: &[I; N], len: usize) -> bool { +fn get_many_check_valid( + indices: &[I; N], + len: usize, +) -> Result<(), GetManyMutError> { // NB: The optimizer should inline the loops into a sequence // of instructions without additional branching. - let mut valid = true; for (i, idx) in indices.iter().enumerate() { - valid &= idx.is_in_bounds(len); + if !idx.is_in_bounds(len) { + return Err(GetManyMutError::IndexOutOfBounds); + } for idx2 in &indices[..i] { - valid &= !idx.is_overlapping(idx2); + if idx.is_overlapping(idx2) { + return Err(GetManyMutError::OverlappingIndices); + } } } - valid + Ok(()) } -/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. +/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. /// /// It indicates one of two possible errors: /// - An index is out-of-bounds. -/// - The same index appeared multiple times in the array. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). /// /// # Examples /// /// ``` /// #![feature(get_many_mut)] +/// use std::slice::GetManyMutError; /// /// let v = &mut [1, 2, 3]; -/// assert!(v.get_many_mut([0, 999]).is_err()); -/// assert!(v.get_many_mut([1, 1]).is_err()); +/// assert_eq!(v.get_many_mut([0, 999]), Err(GetManyMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_many_mut([1, 1]), Err(GetManyMutError::OverlappingIndices)); /// ``` #[unstable(feature = "get_many_mut", issue = "104642")] -// NB: The N here is there to be forward-compatible with adding more details -// to the error type at a later point -#[derive(Clone, PartialEq, Eq)] -pub struct GetManyMutError { - _private: (), +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetManyMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, } #[unstable(feature = "get_many_mut", issue = "104642")] -impl fmt::Debug for GetManyMutError { +impl fmt::Display for GetManyMutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GetManyMutError").finish_non_exhaustive() - } -} - -#[unstable(feature = "get_many_mut", issue = "104642")] -impl fmt::Display for GetManyMutError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) + let msg = match self { + GetManyMutError::IndexOutOfBounds => "an index is out of bounds", + GetManyMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) } } From fb662a2e5c58b25a553e53d5c39e2518fcf90f04 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Nov 2024 03:33:33 +0000 Subject: [PATCH 014/197] Remove redundant associated type bounds from dyn --- src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 54aa18ce2076..4d0539c135ac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -666,7 +666,7 @@ impl<'a> InferenceTable<'a> { highest_known_var: InferenceVar, } impl TypeFolder for VarFudger<'_, '_> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -1004,7 +1004,7 @@ mod resolve { where F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } 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 22e7b1d920f6..975625fdfab7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -646,7 +646,7 @@ pub(crate) fn fold_free_vars + TypeFoldable< F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const, > TypeFolder for FreeVarFolder { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } @@ -697,7 +697,7 @@ pub(crate) fn fold_tys_and_consts + TypeFold impl, DebruijnIndex) -> Either> TypeFolder for TyFolder { - fn as_dyn(&mut self) -> &mut dyn TypeFolder { + fn as_dyn(&mut self) -> &mut dyn TypeFolder { self } From 868668e05dca0a6516f37e6fa2bfab3526f02868 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 25 Nov 2024 15:06:43 +0000 Subject: [PATCH 015/197] Run `cargo update` and update licenses --- Cargo.lock | 590 +++++++++++++++----------- compiler/rustc_codegen_ssa/Cargo.toml | 2 +- library/Cargo.lock | 12 +- src/tools/run-make-support/Cargo.toml | 2 +- src/tools/rustbook/Cargo.lock | 445 ++++++++++++++----- src/tools/tidy/src/deps.rs | 4 +- 6 files changed, 692 insertions(+), 363 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ccf05cc5b84..89e7d70d839a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "ammonia" @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" dependencies = [ "backtrace", ] @@ -255,12 +255,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -269,9 +263,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -291,12 +285,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "serde", ] @@ -356,9 +350,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "camino" @@ -384,9 +378,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -411,9 +405,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -476,9 +470,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -496,9 +490,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -509,9 +503,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -525,14 +519,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clippy" @@ -556,7 +550,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "tempfile", "termize", "tokio", @@ -650,23 +644,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -770,9 +764,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -857,9 +851,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.77+curl-8.10.1" +version = "0.4.78+curl-8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f469e8a5991f277a208224f6c7ad72ecb5f986e36d09ae1f2c1bb9259478a480" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" dependencies = [ "cc", "libc", @@ -891,7 +885,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -902,7 +896,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -939,7 +933,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -960,7 +954,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -970,7 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -982,7 +976,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1060,7 +1054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1142,12 +1136,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1185,9 +1179,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "field-offset" @@ -1213,9 +1207,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1357,7 +1351,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1482,7 +1476,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -1497,11 +1491,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -1522,9 +1517,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash", ] @@ -1590,7 +1585,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1631,6 +1626,18 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + [[package]] name = "icu_list" version = "1.5.0" @@ -1684,6 +1691,51 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + [[package]] name = "icu_provider" version = "1.5.0" @@ -1722,7 +1774,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1739,12 +1791,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1763,7 +1826,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -1777,27 +1840,27 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "rustc-rayon", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width 0.1.14", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -1828,15 +1891,6 @@ dependencies = [ "xz2", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "intl-memoizer" version = "0.5.2" @@ -1873,9 +1927,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jemalloc-sys" @@ -1898,10 +1952,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1924,7 +1979,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustdoc-json-types", "serde", "serde_json", @@ -1967,9 +2022,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -2002,9 +2057,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2022,7 +2077,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "redox_syscall", ] @@ -2064,9 +2119,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lld-wrapper" @@ -2157,9 +2212,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -2317,7 +2372,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -2420,6 +2475,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -2473,7 +2543,7 @@ checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "indexmap", "memchr", "ruzstd", @@ -2621,9 +2691,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2671,7 +2741,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2773,9 +2843,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -2816,18 +2886,18 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" dependencies = [ "cc", ] @@ -2838,7 +2908,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "unicase", ] @@ -2849,7 +2919,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -2861,7 +2931,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.11.0", "unicase", @@ -2965,7 +3035,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -2987,7 +3057,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3011,9 +3081,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3079,9 +3149,9 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3114,7 +3184,7 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser 0.216.0", + "wasmparser 0.219.1", ] [[package]] @@ -3143,9 +3213,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-main" @@ -3210,7 +3280,7 @@ version = "1.0.1" name = "rustc_abi" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rand", "rand_xoshiro", "rustc_data_structures", @@ -3224,11 +3294,11 @@ dependencies = [ [[package]] name = "rustc_apfloat" -version = "0.2.1+llvm-462a31f5a5ab" +version = "0.2.2+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" dependencies = [ - "bitflags 1.3.2", + "bitflags", "smallvec", ] @@ -3243,7 +3313,7 @@ dependencies = [ name = "rustc_ast" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "rustc_ast_ir", "rustc_data_structures", @@ -3406,7 +3476,7 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "itertools", "libc", "measureme", @@ -3444,7 +3514,7 @@ version = "0.0.0" dependencies = [ "ar_archive_writer", "arrayvec", - "bitflags 2.6.0", + "bitflags", "cc", "either", "itertools", @@ -3481,7 +3551,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder 0.216.0", + "wasm-encoder 0.219.1", "windows", ] @@ -3516,7 +3586,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "arrayvec", - "bitflags 2.6.0", + "bitflags", "either", "elsa", "ena", @@ -3527,7 +3597,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3700,7 +3770,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid", ] @@ -3834,7 +3904,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3982,7 +4052,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -3990,7 +4060,7 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "libloading", "odht", @@ -4021,7 +4091,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "either", "field-offset", @@ -4172,7 +4242,7 @@ dependencies = [ name = "rustc_parse" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -4229,7 +4299,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc_abi", "rustc_apfloat", "rustc_arena", @@ -4312,7 +4382,7 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", @@ -4340,7 +4410,7 @@ dependencies = [ name = "rustc_sanitizers" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_abi", "rustc_data_structures", "rustc_hir", @@ -4367,7 +4437,7 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "getopts", "libc", "rustc_abi", @@ -4448,7 +4518,7 @@ dependencies = [ name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "object 0.36.5", "rustc_abi", "rustc_data_structures", @@ -4549,7 +4619,7 @@ dependencies = [ name = "rustc_type_ir" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "indexmap", "rustc-hash 1.1.0", @@ -4571,7 +4641,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -4625,7 +4695,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", ] @@ -4660,7 +4730,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4694,11 +4764,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -4737,9 +4807,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4782,29 +4852,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap", "itoa", @@ -4894,9 +4964,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4914,9 +4984,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2" dependencies = [ "smallvec", ] @@ -5055,9 +5125,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5072,7 +5142,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5109,9 +5179,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -5153,9 +5223,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -5190,22 +5260,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5249,7 +5319,7 @@ dependencies = [ "ignore", "miropt-test-tools", "regex", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "semver", "similar", "termcolor", @@ -5318,9 +5388,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -5390,13 +5460,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5411,9 +5481,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -5567,7 +5637,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid-impl", ] @@ -5577,17 +5647,11 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" @@ -5670,9 +5734,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5685,12 +5749,24 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -5748,9 +5824,9 @@ checksum = "0f76d9fa52234153eeb40b088de91a8c13dc28a912cf6f31cd89ca4bac9024e0" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -5759,24 +5835,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5784,22 +5860,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-component-ld" @@ -5825,15 +5901,6 @@ dependencies = [ "wasm-component-ld", ] -[[package]] -name = "wasm-encoder" -version = "0.216.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" -dependencies = [ - "leb128", -] - [[package]] name = "wasm-encoder" version = "0.219.1" @@ -5844,6 +5911,16 @@ dependencies = [ "wasmparser 0.219.1", ] +[[package]] +name = "wasm-encoder" +version = "0.221.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de35b6c3ef1f53ac7a31b5e69bc00f1542ea337e7e7162dc34c68b537ff82690" +dependencies = [ + "leb128", + "wasmparser 0.221.0", +] + [[package]] name = "wasm-metadata" version = "0.219.1" @@ -5860,23 +5937,13 @@ dependencies = [ "wasmparser 0.219.1", ] -[[package]] -name = "wasmparser" -version = "0.216.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" -dependencies = [ - "bitflags 2.6.0", - "indexmap", -] - [[package]] name = "wasmparser" version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -5886,7 +5953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags", "hashbrown 0.14.5", "indexmap", "semver", @@ -5894,27 +5961,48 @@ dependencies = [ ] [[package]] -name = "wast" -version = "219.0.1" +name = "wasmparser" +version = "0.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f79a9d9df79986a68689a6b40bcc8d5d40d807487b235bebc2ac69a242b54a1" +checksum = "8659e755615170cfe20da468865c989da78c5da16d8652e69a75acda02406a92" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + +[[package]] +name = "wast" +version = "221.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d8eb1933d493dd07484a255c3f52236123333f5befaa3be36182a50d393ec54" dependencies = [ "bumpalo", "leb128", "memchr", - "unicode-width 0.1.14", - "wasm-encoder 0.219.1", + "unicode-width 0.2.0", + "wasm-encoder 0.221.0", ] [[package]] name = "wat" -version = "1.219.1" +version = "1.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc3cf014fb336883a411cd662f987abf6a1d2a27f2f0008616a0070bbf6bd0d" +checksum = "c813fd4e5b2b97242830b56e7b7dc5479bc17aaa8730109be35e61909af83993" dependencies = [ "wast", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -5966,7 +6054,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "windows-metadata", ] @@ -5999,7 +6087,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6010,7 +6098,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6192,7 +6280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags", "indexmap", "log", "serde", @@ -6222,6 +6310,12 @@ dependencies = [ "wasmparser 0.219.1", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.5.5" @@ -6259,9 +6353,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6271,13 +6365,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6299,27 +6393,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6342,5 +6436,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index b898cfec7966..e40a2aa36129 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -42,7 +42,7 @@ tempfile = "3.2" thin-vec = "0.2.12" thorin-dwp = "0.8" tracing = "0.1" -wasm-encoder = "0.216.0" +wasm-encoder = "0.219" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] diff --git a/library/Cargo.lock b/library/Cargo.lock index f9b0af2c6e84..490c989300f5 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" +checksum = "e2c6cb20f236dae10c69b0b45d82ef50af8b7e45c10e429e7901d26b49b4dbf3" dependencies = [ "compiler_builtins", "gimli 0.31.1", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3c172b2d956a..15ed03ad5c23 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bstr = "1.6.0" object = "0.36.2" similar = "2.5.0" -wasmparser = { version = "0.216", default-features = false, features = ["std"] } +wasmparser = { version = "0.219", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" build_helper = { path = "../../build_helper" } diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 400eb7c5e0d7..3d35779be90f 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "autocfg" @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "regex-automata", @@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" @@ -252,9 +252,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -311,6 +311,17 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -360,25 +371,25 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -456,9 +467,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -525,20 +536,149 @@ dependencies = [ ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -552,16 +692,17 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -573,9 +714,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -602,6 +743,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + [[package]] name = "lock_api" version = "0.4.12" @@ -646,9 +793,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -852,9 +999,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -996,9 +1143,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1120,9 +1267,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1150,9 +1297,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -1190,18 +1337,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1210,9 +1357,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1258,6 +1405,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "string_cache" version = "0.8.7" @@ -1292,15 +1445,26 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syntect" version = "5.2.0" @@ -1323,9 +1487,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -1347,9 +1511,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -1363,18 +1527,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -1382,20 +1546,15 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.5.11" @@ -1463,26 +1622,11 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" -[[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -1492,9 +1636,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -1507,6 +1651,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1537,9 +1693,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -1548,9 +1704,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -1563,9 +1719,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1573,9 +1729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -1586,9 +1742,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "winapi" @@ -1721,6 +1877,42 @@ dependencies = [ "memchr", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1741,3 +1933,46 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index e065f01ebba8..493d9f5d5ec4 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -12,7 +12,8 @@ use cargo_metadata::{Metadata, Package, PackageId}; #[rustfmt::skip] const LICENSES: &[&str] = &[ // tidy-alphabetical-start - "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident + "(MIT OR Apache-2.0) AND Unicode-3.0", // unicode_ident (1.0.14) + "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident (1.0.12) "0BSD OR MIT OR Apache-2.0", // adler license "0BSD", "Apache-2.0 / MIT", @@ -94,7 +95,6 @@ const EXCEPTIONS: ExceptionList = &[ ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("foldhash", "Zlib"), // rustc - ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) From 5a52142eeafd00fcda88f60f9fe0aee8f912c625 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Dec 2024 12:58:43 +0100 Subject: [PATCH 016/197] Fix debug configuration querying not inheriting environment --- .../rust-analyzer/editors/code/src/config.ts | 27 +++- .../rust-analyzer/editors/code/src/debug.ts | 12 +- .../rust-analyzer/editors/code/src/run.ts | 35 ++--- .../code/tests/unit/runnable_env.test.ts | 122 ------------------ 4 files changed, 42 insertions(+), 154 deletions(-) delete mode 100644 src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 67bc72f1e126..f979d5454715 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -261,9 +261,9 @@ export class Config { return this.get("testExplorer"); } - get runnablesExtraEnv() { + runnablesExtraEnv(label: string): Record | undefined { const item = this.get("runnables.extraEnv") ?? this.get("runnableEnv"); - if (!item) return item; + if (!item) return undefined; const fixRecord = (r: Record) => { for (const key in r) { if (typeof r[key] !== "string") { @@ -271,11 +271,28 @@ export class Config { } } }; + + const platform = process.platform; + const checkPlatform = (it: RunnableEnvCfgItem) => { + if (it.platform) { + const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; + return platforms.indexOf(platform) >= 0; + } + return true; + }; + if (item instanceof Array) { - item.forEach((x) => fixRecord(x.env)); - } else { - fixRecord(item); + const env = {}; + for (const it of item) { + const masked = !it.mask || new RegExp(it.mask).test(label); + if (masked && checkPlatform(it)) { + Object.assign(env, it.env); + } + } + fixRecord(env); + return env; } + fixRecord(item); return item; } diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 9e2e3d2185bf..f21ca2e8f96f 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -148,8 +148,16 @@ async function getDebugConfiguration( return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`); } - const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv); - const executable = await getDebugExecutable(runnableArgs, env); + const executable = await getDebugExecutable( + runnableArgs, + prepareEnv(true, {}, config.runnablesExtraEnv(runnable.label)), + ); + + const env = prepareEnv( + inheritEnv, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ); let sourceFileMap = debugOptions.sourceFileMap; if (sourceFileMap === "auto") { diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 8a82a5a58cf9..f71ab7ffbd81 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -5,7 +5,7 @@ import * as tasks from "./tasks"; import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; -import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config"; +import type { Config } from "./config"; import type { LanguageClient } from "vscode-languageclient/node"; import { unwrapUndefinable, type RustEditor } from "./util"; @@ -81,32 +81,13 @@ export function prepareBaseEnv( export function prepareEnv( inheritEnv: boolean, - label: string, - runnableArgs: ra.CargoRunnableArgs, - runnableEnvCfg?: RunnableEnvCfg, + runnableEnv?: Record, + runnableEnvCfg?: Record, ): Record { - const env = prepareBaseEnv(inheritEnv, runnableArgs.environment); - const platform = process.platform; - - const checkPlatform = (it: RunnableEnvCfgItem) => { - if (it.platform) { - const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; - return platforms.indexOf(platform) >= 0; - } - return true; - }; + const env = prepareBaseEnv(inheritEnv, runnableEnv); if (runnableEnvCfg) { - if (Array.isArray(runnableEnvCfg)) { - for (const it of runnableEnvCfg) { - const masked = !it.mask || new RegExp(it.mask).test(label); - if (masked && checkPlatform(it)) { - Object.assign(env, it.env); - } - } - } else { - Object.assign(env, runnableEnvCfg); - } + Object.assign(env, runnableEnvCfg); } return env; @@ -140,7 +121,11 @@ export async function createTaskFromRunnable( }; options = { cwd: runnableArgs.workspaceRoot || ".", - env: prepareEnv(true, runnable.label, runnableArgs, config.runnablesExtraEnv), + env: prepareEnv( + true, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ), }; } else { const runnableArgs = runnable.args; 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 deleted file mode 100644 index f0a62a3cce29..000000000000 --- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as assert from "assert"; -import { prepareEnv } from "../../src/run"; -import type { RunnableEnvCfg } from "../../src/config"; -import type { Context } from "."; -import type * as ra from "../../src/lsp_ext"; - -function makeRunnable(label: string): ra.Runnable { - return { - label, - kind: "cargo", - args: { - cargoArgs: [], - cwd: ".", - executableArgs: [], - }, - }; -} - -function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record { - const runnable = makeRunnable(runnableName); - const runnableArgs = runnable.args as ra.CargoRunnableArgs; - return prepareEnv(false, runnable.label, runnableArgs, config); -} - -export async function getTests(ctx: Context) { - await ctx.suite("Runnable env", (suite) => { - suite.addTest("Global config works", async () => { - const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" }); - assert.strictEqual(binEnv["GLOBAL"], "g"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" }); - assert.strictEqual(testEnv["GLOBAL"], "g"); - }); - - suite.addTest("null mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "data"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - }); - - suite.addTest("order works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - env: { DATA: "newdata" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "newdata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "newdata"); - }); - - suite.addTest("mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "^run", - env: { DATA: "rundata" }, - }, - { - mask: "special_test$", - env: { DATA: "special_test" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "rundata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - - const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); - assert.strictEqual(specialTestEnv["DATA"], "special_test"); - }); - - suite.addTest("exact test name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod::test_name", - env: { DATA: "test special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "test special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "data"); - }); - - suite.addTest("test mod name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod", - env: { DATA: "mod special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "mod special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "mod special"); - }); - }); -} From 03ae70dcacf96e50c52b0df20a99d655d33255d4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 2 Dec 2024 13:35:58 +0100 Subject: [PATCH 017/197] fix: Fix syntax fixup inserting unnecessary semicolons --- .../crates/hir-expand/src/fixup.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index b6d5828da964..0af29681a13f 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -110,7 +110,8 @@ pub(crate) fn fixup_syntax( } }, ast::ExprStmt(it) => { - if it.semicolon_token().is_none() { + let needs_semi = it.semicolon_token().is_none() && it.expr().map_or(false, |e| e.syntax().kind() != SyntaxKind::BLOCK_EXPR); + if needs_semi { append.insert(node.clone().into(), vec![ Leaf::Punct(Punct { char: ';', @@ -905,6 +906,21 @@ fn foo() { "#, expect![[r#" fn foo () {|| __ra_fixup} +"#]], + ); + } + + #[test] + fn fixup_regression_() { + check( + r#" +fn foo() { + {} + {} +} +"#, + expect![[r#" +fn foo () {{} {}} "#]], ); } From aede6e136567d25d23c802fa6950a4e2ccca0d45 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 3 Dec 2024 10:41:29 +0200 Subject: [PATCH 018/197] Advertise completions and inlay hints resolve server capabilities based on the client capabilities. --- .../crates/ide-completion/src/lib.rs | 14 +++++++++++- .../crates/ide/src/inlay_hints.rs | 12 +++++++++- .../crates/rust-analyzer/src/config.rs | 22 +++++-------------- .../rust-analyzer/src/lsp/capabilities.rs | 19 ++++++++++++---- 4 files changed, 45 insertions(+), 22 deletions(-) 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 dfee01b187e9..cffdfa29f1a3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -19,7 +19,7 @@ use ide_db::{ }, items_locator, syntax_helpers::tree_diff::diff, - FilePosition, RootDatabase, + FilePosition, FxHashSet, RootDatabase, }; use crate::{ @@ -50,6 +50,18 @@ pub struct CompletionFieldsToResolve { } impl CompletionFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_label_details: client_capability_fields.contains("labelDetails"), + resolve_tags: client_capability_fields.contains("tags"), + resolve_detail: client_capability_fields.contains("detail"), + resolve_documentation: client_capability_fields.contains("documentation"), + resolve_filter_text: client_capability_fields.contains("filterText"), + resolve_text_edit: client_capability_fields.contains("textEdit"), + resolve_command: client_capability_fields.contains("command"), + } + } + pub const fn empty() -> Self { Self { resolve_label_details: false, 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 c58ca0f01cd6..1ae8bfa9b6e1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,8 +8,8 @@ use hir::{ sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics, }; -use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; +use ide_db::{text_edit::TextEdit, FxHashSet}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; use span::{Edition, EditionedFileId}; @@ -289,6 +289,16 @@ pub struct InlayFieldsToResolve { } impl InlayFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_text_edits: client_capability_fields.contains("textEdits"), + resolve_hint_tooltip: client_capability_fields.contains("tooltip"), + resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), + resolve_label_location: client_capability_fields.contains("label.location"), + resolve_label_command: client_capability_fields.contains("label.command"), + } + } + pub const fn empty() -> Self { Self { resolve_text_edits: false, 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 37d45255e29d..152ce2944a0d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1446,15 +1446,9 @@ impl Config { limit: self.completion_limit(source_root).to_owned(), enable_term_search: self.completion_termSearch_enable(source_root).to_owned(), term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64, - fields_to_resolve: CompletionFieldsToResolve { - resolve_label_details: client_capability_fields.contains("labelDetails"), - resolve_tags: client_capability_fields.contains("tags"), - resolve_detail: client_capability_fields.contains("detail"), - resolve_documentation: client_capability_fields.contains("documentation"), - resolve_filter_text: client_capability_fields.contains("filterText"), - resolve_text_edit: client_capability_fields.contains("textEdit"), - resolve_command: client_capability_fields.contains("command"), - }, + fields_to_resolve: CompletionFieldsToResolve::from_client_capabilities( + &client_capability_fields, + ), } } @@ -1614,13 +1608,9 @@ impl Config { } else { None }, - fields_to_resolve: InlayFieldsToResolve { - resolve_text_edits: client_capability_fields.contains("textEdits"), - resolve_hint_tooltip: client_capability_fields.contains("tooltip"), - resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), - resolve_label_location: client_capability_fields.contains("label.location"), - resolve_label_command: client_capability_fields.contains("label.command"), - }, + fields_to_resolve: InlayFieldsToResolve::from_client_capabilities( + &client_capability_fields, + ), implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(), range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(), } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 1db616898e8d..bd496e8ddc36 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -1,4 +1,5 @@ //! Advertises the capabilities of the LSP Server. +use ide::{CompletionFieldsToResolve, InlayFieldsToResolve}; use ide_db::{line_index::WideEncoding, FxHashSet}; use lsp_types::{ CallHierarchyServerCapability, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, @@ -40,7 +41,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { })), hover_provider: Some(HoverProviderCapability::Simple(true)), completion_provider: Some(CompletionOptions { - resolve_provider: config.caps().completions_resolve_provider(), + resolve_provider: Some(config.caps().completions_resolve_provider()), trigger_characters: Some(vec![ ":".to_owned(), ".".to_owned(), @@ -136,7 +137,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( InlayHintOptions { work_done_progress_options: Default::default(), - resolve_provider: Some(true), + resolve_provider: Some(config.caps().inlay_hints_resolve_provider()), }, ))), inline_value_provider: None, @@ -176,8 +177,18 @@ impl ClientCapabilities { Self(caps) } - fn completions_resolve_provider(&self) -> Option { - self.completion_item_edit_resolve().then_some(true) + fn completions_resolve_provider(&self) -> bool { + let client_capabilities = self.completion_resolve_support_properties(); + let fields_to_resolve = + CompletionFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != CompletionFieldsToResolve::empty() + } + + fn inlay_hints_resolve_provider(&self) -> bool { + let client_capabilities = self.inlay_hint_resolve_support_properties(); + let fields_to_resolve = + InlayFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != InlayFieldsToResolve::empty() } fn experimental_bool(&self, index: &'static str) -> bool { From 97feb0334493d870e09f7a5a02c6d320a7e8a4ae Mon Sep 17 00:00:00 2001 From: David Richey Date: Tue, 3 Dec 2024 14:14:53 +0000 Subject: [PATCH 019/197] Only show status bar item in relevant files --- .../rust-analyzer/editors/code/package.json | 35 +++++++++++++++++++ .../rust-analyzer/editors/code/src/config.ts | 4 +++ .../rust-analyzer/editors/code/src/ctx.ts | 18 +++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 82c43b76fdd5..46f7803c8a8b 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -425,6 +425,41 @@ ], "default": "openLogs", "markdownDescription": "Action to run when clicking the extension status bar item." + }, + "rust-analyzer.statusBar.documentSelector": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "language": { + "type": [ + "string", + "null" + ] + }, + "pattern": { + "type": [ + "string", + "null" + ] + } + } + }, + "default": [ + { + "language": "rust" + }, + { + "pattern": "**/Cargo.toml" + }, + { + "pattern": "**/Cargo.lock" + } + ], + "markdownDescription": "Determines when to show the extension status bar item based on the currently open file. Use `{ \"pattern\": \"**\" }` to always show. Use `null` to never show." } } }, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index f979d5454715..f7ef80df2baa 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -348,6 +348,10 @@ export class Config { return this.get("statusBar.clickAction"); } + get statusBarDocumentSelector() { + return this.get("statusBar.documentSelector"); + } + get initializeStopped() { return this.get("initializeStopped"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 234fe6ab0247..4a3f66b00d00 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -88,6 +88,7 @@ export class Ctx implements RustAnalyzerExtensionApi { private _treeView: vscode.TreeView | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; + private statusBarActiveEditorListener: Disposable; get serverPath(): string | undefined { return this._serverPath; @@ -119,6 +120,10 @@ export class Ctx implements RustAnalyzerExtensionApi { this._serverVersion = ""; this.config = new Config(extCtx.subscriptions); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + this.updateStatusBarVisibility(vscode.window.activeTextEditor); + this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) => + this.updateStatusBarVisibility(editor), + ); if (this.config.testExplorer) { this.testController = vscode.tests.createTestController( "rustAnalyzerTestController", @@ -141,6 +146,7 @@ export class Ctx implements RustAnalyzerExtensionApi { dispose() { this.config.dispose(); this.statusBar.dispose(); + this.statusBarActiveEditorListener.dispose(); this.testController?.dispose(); void this.disposeClient(); this.commandDisposables.forEach((disposable) => disposable.dispose()); @@ -404,7 +410,6 @@ export class Ctx implements RustAnalyzerExtensionApi { let icon = ""; const status = this.lastStatus; const statusBar = this.statusBar; - statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -472,6 +477,17 @@ export class Ctx implements RustAnalyzerExtensionApi { statusBar.text = `${icon}rust-analyzer`; } + private updateStatusBarVisibility(editor: vscode.TextEditor | undefined) { + const documentSelector = this.config.statusBarDocumentSelector; + if (documentSelector != null) { + if (editor != null && vscode.languages.match(documentSelector, editor.document) > 0) { + this.statusBar.show(); + return; + } + } + this.statusBar.hide(); + } + pushExtCleanup(d: Disposable) { this.extCtx.subscriptions.push(d); } From 4fe15b06e8f3ea9ebcb916df2fd4b2f0e9537296 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Tue, 3 Dec 2024 16:16:08 +0100 Subject: [PATCH 020/197] Use UNIX thread_local implementation for WASI. --- .../std/src/sys/thread_local/guard/wasi.rs | 71 ------------------- library/std/src/sys/thread_local/key/unix.rs | 20 ++++++ library/std/src/sys/thread_local/mod.rs | 6 +- 3 files changed, 22 insertions(+), 75 deletions(-) delete mode 100644 library/std/src/sys/thread_local/guard/wasi.rs diff --git a/library/std/src/sys/thread_local/guard/wasi.rs b/library/std/src/sys/thread_local/guard/wasi.rs deleted file mode 100644 index dfd1f126aa0f..000000000000 --- a/library/std/src/sys/thread_local/guard/wasi.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! wasm32-wasip1 has pthreads support. - -use crate::cell::Cell; -use crate::sync::atomic::{AtomicBool, Ordering}; -use crate::sys::thread_local::destructors; -use crate::{ffi, ptr}; - -// Add a few symbols not in upstream `libc` just yet. -mod libc { - pub use libc::*; - - use crate::ffi; - - #[allow(non_camel_case_types)] - pub type pthread_key_t = ffi::c_uint; - - extern "C" { - pub fn pthread_key_create( - key: *mut pthread_key_t, - destructor: unsafe extern "C" fn(*mut ffi::c_void), - ) -> ffi::c_int; - - pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; - } -} - -pub fn enable() { - enable_main(); - enable_thread(); -} - -fn enable_main() { - static REGISTERED: AtomicBool = AtomicBool::new(false); - - if !REGISTERED.swap(true, Ordering::AcqRel) { - unsafe { - assert_eq!(libc::atexit(run_main_dtors), 0); - } - } - - extern "C" fn run_main_dtors() { - unsafe { - destructors::run(); - crate::rt::thread_cleanup(); - } - } -} - -fn enable_thread() { - #[thread_local] - static REGISTERED: Cell = Cell::new(false); - - if !REGISTERED.replace(true) { - unsafe { - let mut key: libc::pthread_key_t = 0; - assert_eq!(libc::pthread_key_create(&mut key, run_thread_dtors), 0); - - // We must set the value to a non-NULL pointer value so that - // the destructor is run on thread exit. The pointer is only - // passed to run_dtors and never dereferenced. - assert_eq!(libc::pthread_setspecific(key, ptr::without_provenance(1)), 0); - } - } - - extern "C" fn run_thread_dtors(_: *mut ffi::c_void) { - unsafe { - destructors::run(); - crate::rt::thread_cleanup(); - } - } -} diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 28e48a750b9b..6661e378dbf4 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -1,5 +1,25 @@ use crate::mem; +// For WASI add a few symbols not in upstream `libc` just yet. +#[cfg(target_os = "wasi")] +mod libc { + use crate::ffi; + + #[allow(non_camel_case_types)] + pub type pthread_key_t = ffi::c_uint; + + extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: unsafe extern "C" fn(*mut ffi::c_void), + ) -> ffi::c_int; + #[allow(dead_code)] + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ffi::c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ffi::c_int; + } +} + pub type Key = libc::pthread_key_t; #[inline] diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 042f0f76c9a4..82e1aeabf5ba 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -85,11 +85,8 @@ pub(crate) mod guard { } else if #[cfg(target_os = "windows")] { mod windows; pub(crate) use windows::enable; - } else if #[cfg(all(target_os = "wasi"))] { - mod wasi; - pub(crate) use wasi::enable; } else if #[cfg(any( - target_family = "wasm", + all(target_family = "wasm", not(target_os="wasi")), target_os = "uefi", target_os = "zkvm", ))] { @@ -138,6 +135,7 @@ pub(crate) mod key { target_family = "unix", ), target_os = "teeos", + target_os = "wasi", ))] { mod racy; mod unix; From f4933ffbf1620df78a7ab12972ec3f0ce9dc08c8 Mon Sep 17 00:00:00 2001 From: Henry Jiang Date: Tue, 3 Dec 2024 13:04:52 -0500 Subject: [PATCH 021/197] keep profile-rt symbol alive --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 05dfbd40a0ad..4c5eb98e890e 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1694,6 +1694,8 @@ impl<'a> Linker for AixLinker<'a> { fn pgo_gen(&mut self) { self.link_arg("-bdbg:namedsects:ss"); + self.link_arg("-u"); + self.link_arg("__llvm_profile_runtime"); } fn control_flow_guard(&mut self) {} From 879312ed633a5611748963f0a012d2d03bc9c87b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 3 Dec 2024 20:46:45 +0200 Subject: [PATCH 022/197] Support `AsyncFnX` traits Only in calls, because to support them in bounds we need support from Chalk. However we don't yet report error from bounds anyway, so this is less severe. The returned future is shown in its name within inlay hints instead of as a nicer `impl Future`, but that can wait for another PR. --- .../crates/hir-def/src/lang_item.rs | 3 + .../crates/hir-ty/src/infer/expr.rs | 6 +- .../crates/hir-ty/src/infer/unify.rs | 110 ++++++++-------- .../crates/hir-ty/src/mir/lower.rs | 12 +- .../crates/hir-ty/src/tests/traits.rs | 50 ++++++++ .../rust-analyzer/crates/hir-ty/src/traits.rs | 26 +++- .../src/handlers/expected_function.rs | 21 ++++ .../crates/intern/src/symbol/symbols.rs | 8 ++ .../crates/test-utils/src/minicore.rs | 119 +++++++++++++++++- 9 files changed, 289 insertions(+), 66 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 166c965d14c6..0629d87e5444 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -376,6 +376,9 @@ language_item_table! { Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; 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 32b4ea2f28ba..c21ff19c45dc 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 @@ -1287,8 +1287,8 @@ impl InferenceContext<'_> { tgt_expr: ExprId, ) { match fn_x { - FnTrait::FnOnce => (), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => (), + FnTrait::FnMut | FnTrait::AsyncFnMut => { if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) { if adjustments .last() @@ -1312,7 +1312,7 @@ impl InferenceContext<'_> { )); } } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) { adjustments.push(Adjustment::borrow( Mutability::Not, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 4d0539c135ac..165861c1b172 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -794,69 +794,75 @@ impl<'a> InferenceTable<'a> { ty: &Ty, num_args: usize, ) -> Option<(FnTrait, Vec, Ty)> { - let krate = self.trait_env.krate; - let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; - let trait_data = self.db.trait_data(fn_once_trait); - let output_assoc_type = - trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; + for (fn_trait_name, output_assoc_name, subtraits) in [ + (FnTrait::FnOnce, sym::Output.clone(), &[FnTrait::Fn, FnTrait::FnMut][..]), + (FnTrait::AsyncFnMut, sym::CallRefFuture.clone(), &[FnTrait::AsyncFn]), + (FnTrait::AsyncFnOnce, sym::CallOnceFuture.clone(), &[]), + ] { + let krate = self.trait_env.krate; + let fn_trait = fn_trait_name.get_id(self.db, krate)?; + let trait_data = self.db.trait_data(fn_trait); + let output_assoc_type = + trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; - let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = TyBuilder::tuple(num_args) - .fill(|it| { - let arg = match it { - ParamKind::Type => self.new_type_var(), - ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), - ParamKind::Const(_) => unreachable!("Tuple with const parameter"), - }; - arg_tys.push(arg.clone()); - arg.cast(Interner) - }) - .build(); + let mut arg_tys = Vec::with_capacity(num_args); + let arg_ty = TyBuilder::tuple(num_args) + .fill(|it| { + let arg = match it { + ParamKind::Type => self.new_type_var(), + ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), + ParamKind::Const(_) => unreachable!("Tuple with const parameter"), + }; + arg_tys.push(arg.clone()); + arg.cast(Interner) + }) + .build(); - let b = TyBuilder::trait_ref(self.db, fn_once_trait); - if b.remaining() != 2 { - return None; - } - let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); + let b = TyBuilder::trait_ref(self.db, fn_trait); + if b.remaining() != 2 { + return None; + } + let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); - let projection = { - TyBuilder::assoc_type_projection( + let projection = TyBuilder::assoc_type_projection( self.db, output_assoc_type, Some(trait_ref.substitution.clone()), ) - .build() - }; + .fill_with_unknown() + .build(); - let trait_env = self.trait_env.env.clone(); - let obligation = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() { - self.register_obligation(obligation.goal); - let return_ty = self.normalize_projection_ty(projection); - for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { - let fn_x_trait = fn_x.get_id(self.db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let obligation: chalk_ir::InEnvironment> = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self - .db - .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .is_some() - { - return Some((fn_x, arg_tys, return_ty)); + let trait_env = self.trait_env.env.clone(); + let obligation = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() + { + self.register_obligation(obligation.goal); + let return_ty = self.normalize_projection_ty(projection); + for &fn_x in subtraits { + let fn_x_trait = fn_x.get_id(self.db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment> = + InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self + .db + .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) + .is_some() + { + return Some((fn_x, arg_tys, return_ty)); + } } + return Some((fn_trait_name, arg_tys, return_ty)); } - unreachable!("It should at least implement FnOnce at this point"); - } else { - None } + None } pub(super) fn insert_type_vars(&mut self, ty: T) -> T 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 c4e064005106..1d1044df6e96 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 @@ -2023,11 +2023,11 @@ pub fn mir_body_for_closure_query( ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); let closure_local = ctx.result.locals.alloc(Local { ty: match kind { - FnTrait::FnOnce => infer[expr].clone(), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].clone(), + FnTrait::FnMut | FnTrait::AsyncFnMut => { TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].clone()).intern(Interner) } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].clone()).intern(Interner) } }, @@ -2055,8 +2055,10 @@ pub fn mir_body_for_closure_query( let mut err = None; let closure_local = ctx.result.locals.iter().nth(1).unwrap().0; let closure_projection = match kind { - FnTrait::FnOnce => vec![], - FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], + FnTrait::FnOnce | FnTrait::AsyncFnOnce => vec![], + FnTrait::FnMut | FnTrait::Fn | FnTrait::AsyncFnMut | FnTrait::AsyncFn => { + vec![ProjectionElem::Deref] + } }; ctx.result.walk_places(|p, store| { if let Some(it) = upvar_map.get(&p.local) { 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 624148cab20f..82ff51927e05 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 @@ -4811,3 +4811,53 @@ fn bar(v: *const ()) { "#]], ); } + +#[test] +fn async_fn_traits() { + check_infer( + r#" +//- minicore: async_fn +async fn foo i32>(a: T) { + let fut1 = a(0); + fut1.await; +} +async fn bar i32>(mut b: T) { + let fut2 = b(0); + fut2.await; +} +async fn baz i32>(c: T) { + let fut3 = c(0); + fut3.await; +} + "#, + expect![[r#" + 37..38 'a': T + 43..83 '{ ...ait; }': () + 43..83 '{ ...ait; }': impl Future + 53..57 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 60..61 'a': T + 60..64 'a(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 62..63 '0': u32 + 70..74 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 70..80 'fut1.await': i32 + 124..129 'mut b': T + 134..174 '{ ...ait; }': () + 134..174 '{ ...ait; }': impl Future + 144..148 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 151..152 'b': T + 151..155 'b(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 153..154 '0': u32 + 161..165 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 161..171 'fut2.await': i32 + 216..217 'c': T + 222..262 '{ ...ait; }': () + 222..262 '{ ...ait; }': impl Future + 232..236 'fut3': AsyncFnOnce::CallOnceFuture + 239..240 'c': T + 239..243 'c(0)': AsyncFnOnce::CallOnceFuture + 241..242 '0': u32 + 249..253 'fut3': AsyncFnOnce::CallOnceFuture + 249..259 'fut3.await': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 51ccd4ef293f..8cb7dbf60f37 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -220,6 +220,10 @@ pub enum FnTrait { FnOnce, FnMut, Fn, + + AsyncFnOnce, + AsyncFnMut, + AsyncFn, } impl fmt::Display for FnTrait { @@ -228,6 +232,9 @@ impl fmt::Display for FnTrait { FnTrait::FnOnce => write!(f, "FnOnce"), FnTrait::FnMut => write!(f, "FnMut"), FnTrait::Fn => write!(f, "Fn"), + FnTrait::AsyncFnOnce => write!(f, "AsyncFnOnce"), + FnTrait::AsyncFnMut => write!(f, "AsyncFnMut"), + FnTrait::AsyncFn => write!(f, "AsyncFn"), } } } @@ -238,6 +245,9 @@ impl FnTrait { FnTrait::FnOnce => "call_once", FnTrait::FnMut => "call_mut", FnTrait::Fn => "call", + FnTrait::AsyncFnOnce => "async_call_once", + FnTrait::AsyncFnMut => "async_call_mut", + FnTrait::AsyncFn => "async_call", } } @@ -246,6 +256,9 @@ impl FnTrait { FnTrait::FnOnce => LangItem::FnOnce, FnTrait::FnMut => LangItem::FnMut, FnTrait::Fn => LangItem::Fn, + FnTrait::AsyncFnOnce => LangItem::AsyncFnOnce, + FnTrait::AsyncFnMut => LangItem::AsyncFnMut, + FnTrait::AsyncFn => LangItem::AsyncFn, } } @@ -254,15 +267,19 @@ impl FnTrait { LangItem::FnOnce => Some(FnTrait::FnOnce), LangItem::FnMut => Some(FnTrait::FnMut), LangItem::Fn => Some(FnTrait::Fn), + LangItem::AsyncFnOnce => Some(FnTrait::AsyncFnOnce), + LangItem::AsyncFnMut => Some(FnTrait::AsyncFnMut), + LangItem::AsyncFn => Some(FnTrait::AsyncFn), _ => None, } } pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind { + // Chalk doesn't support async fn traits. match self { - FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, - FnTrait::FnMut => rust_ir::ClosureKind::FnMut, - FnTrait::Fn => rust_ir::ClosureKind::Fn, + FnTrait::AsyncFnOnce | FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, + FnTrait::AsyncFnMut | FnTrait::FnMut => rust_ir::ClosureKind::FnMut, + FnTrait::AsyncFn | FnTrait::Fn => rust_ir::ClosureKind::Fn, } } @@ -271,6 +288,9 @@ impl FnTrait { FnTrait::FnOnce => Name::new_symbol_root(sym::call_once.clone()), FnTrait::FnMut => Name::new_symbol_root(sym::call_mut.clone()), FnTrait::Fn => Name::new_symbol_root(sym::call.clone()), + FnTrait::AsyncFnOnce => Name::new_symbol_root(sym::async_call_once.clone()), + FnTrait::AsyncFnMut => Name::new_symbol_root(sym::async_call_mut.clone()), + FnTrait::AsyncFn => Name::new_symbol_root(sym::async_call.clone()), } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index 02299197b125..e3a1e12e0296 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -37,4 +37,25 @@ fn foo() { "#, ); } + + #[test] + fn no_error_for_async_fn_traits() { + check_diagnostics( + r#" +//- minicore: async_fn +async fn f(it: impl AsyncFn(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn g(mut it: impl AsyncFnMut(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn h(it: impl AsyncFnOnce(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 865518fe941e..ee96eff33097 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -150,6 +150,9 @@ define_symbols! { C, call_mut, call_once, + async_call_once, + async_call_mut, + async_call, call, cdecl, Center, @@ -221,6 +224,9 @@ define_symbols! { fn_mut, fn_once_output, fn_once, + async_fn_once, + async_fn_mut, + async_fn, fn_ptr_addr, fn_ptr_trait, format_alignment, @@ -334,6 +340,8 @@ define_symbols! { Option, Ord, Output, + CallRefFuture, + CallOnceFuture, owned_box, packed, panic_2015, 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 07767d5ae9f6..f5c8466cb9f0 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -12,6 +12,7 @@ //! asm: //! assert: //! as_ref: sized +//! async_fn: fn, tuple, future, copy //! bool_impl: option, fn //! builtin_impls: //! cell: copy, drop @@ -29,7 +30,7 @@ //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fn: +//! fn: tuple //! from: sized //! future: pin //! coroutine: pin @@ -60,6 +61,7 @@ //! sync: sized //! transmute: //! try: infallible +//! tuple: //! unpin: sized //! unsize: sized //! todo: panic @@ -138,10 +140,10 @@ pub mod marker { } // endregion:copy - // region:fn + // region:tuple #[lang = "tuple_trait"] pub trait Tuple {} - // endregion:fn + // endregion:tuple // region:phantom_data #[lang = "phantom_data"] @@ -682,6 +684,116 @@ pub mod ops { } pub use self::function::{Fn, FnMut, FnOnce}; // endregion:fn + + // region:async_fn + mod async_function { + use crate::{future::Future, marker::Tuple}; + + #[lang = "async_fn"] + #[fundamental] + pub trait AsyncFn: AsyncFnMut { + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_mut"] + #[fundamental] + pub trait AsyncFnMut: AsyncFnOnce { + #[lang = "call_ref_future"] + type CallRefFuture<'a>: Future + where + Self: 'a; + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_once"] + #[fundamental] + pub trait AsyncFnOnce { + #[lang = "async_fn_once_output"] + type Output; + #[lang = "call_once_future"] + type CallOnceFuture: Future; + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; + } + + mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::marker::Tuple; + + impl AsyncFn for &F + where + F: AsyncFn, + { + extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl AsyncFnMut for &F + where + F: AsyncFn, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F + where + F: AsyncFn, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call(self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl AsyncFnMut for &mut F + where + F: AsyncFnMut, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call_mut(*self, args) + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F + where + F: AsyncFnMut, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call_mut(self, args) + } + } + } + } + pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + // endregion:async_fn + // region:try mod try_ { use crate::convert::Infallible; @@ -1684,6 +1796,7 @@ pub mod prelude { marker::Sync, // :sync mem::drop, // :drop ops::Drop, // :drop + ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn ops::{Fn, FnMut, FnOnce}, // :fn option::Option::{self, None, Some}, // :option panic, // :panic From b94c5355b207568b4c66852e46f823437455dcf4 Mon Sep 17 00:00:00 2001 From: Tarek Date: Sun, 17 Nov 2024 15:25:23 +0200 Subject: [PATCH 023/197] internal: Make exclude characters for typing assists configurable, default to None Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 6 ++++++ .../crates/rust-analyzer/src/config.rs | 6 ++++++ .../crates/rust-analyzer/src/handlers/request.rs | 9 +++++++-- .../rust-analyzer/docs/user/generated_config.adoc | 5 +++++ src/tools/rust-analyzer/editors/code/package.json | 13 +++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d4ef9570e1a3..b4f3de3b178c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -411,6 +411,7 @@ impl Analysis { position: FilePosition, char_typed: char, autoclose: bool, + chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { @@ -419,6 +420,11 @@ impl Analysis { if char_typed == '<' && !autoclose { return Ok(None); } + if let Some(chars_to_exclude) = chars_to_exclude { + if chars_to_exclude.contains(char_typed) { + return Ok(None); + } + } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) } 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 152ce2944a0d..c2d6196ca415 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -310,6 +310,8 @@ config_data! { /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. typing_autoClosingAngleBrackets_enable: bool = false, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -2160,6 +2162,10 @@ impl Config { *self.typing_autoClosingAngleBrackets_enable() } + pub fn typing_exclude_chars(&self) -> Option { + self.typing_excludeChars().clone() + } + // VSCode is our reference implementation, so we allow ourselves to work around issues by // special casing certain versions pub fn visual_studio_code_version(&self) -> Option<&Version> { 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 4975467ece9b..29820a3e37e2 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 @@ -459,9 +459,14 @@ pub(crate) fn handle_on_type_formatting( if char_typed == '>' { return Ok(None); } + let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = - snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?; + let edit = snap.analysis.on_char_typed( + position, + char_typed, + snap.config.typing_autoclose_angle(), + chars_to_exclude, + )?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 052d0a2a41d0..d0c95912c3db 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -997,6 +997,11 @@ Show documentation. -- Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. -- +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: ++ +-- +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +-- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 46f7803c8a8b..e98205e0eab1 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2612,6 +2612,19 @@ } } }, + { + "title": "typing", + "properties": { + "rust-analyzer.typing.excludeChars": { + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", + "default": null, + "type": [ + "null", + "string" + ] + } + } + }, { "title": "workspace", "properties": { From 68cd57940a2f82ab1bdbc0c799ffecc095c03f88 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 22:38:21 +0200 Subject: [PATCH 024/197] chore: deprecate `typing.autoClosingAngleBrackets` configuration Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 ---- .../rust-analyzer/crates/rust-analyzer/src/config.rs | 6 ------ .../crates/rust-analyzer/src/handlers/request.rs | 7 +------ .../rust-analyzer/docs/user/generated_config.adoc | 5 ----- src/tools/rust-analyzer/editors/code/package.json | 10 ---------- 5 files changed, 1 insertion(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b4f3de3b178c..b43685ffeed2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -410,16 +410,12 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - autoclose: bool, chars_to_exclude: Option, ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if char_typed == '<' && !autoclose { - return Ok(None); - } if let Some(chars_to_exclude) = chars_to_exclude { if chars_to_exclude.contains(char_typed) { return Ok(None); 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 c2d6196ca415..392bfbf15fe1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,6 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = false, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. typing_excludeChars: Option = None, @@ -2158,10 +2156,6 @@ impl Config { } } - pub fn typing_autoclose_angle(&self) -> bool { - *self.typing_autoClosingAngleBrackets_enable() - } - pub fn typing_exclude_chars(&self) -> Option { self.typing_excludeChars().clone() } 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 29820a3e37e2..0fadfa6c420f 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 @@ -461,12 +461,7 @@ pub(crate) fn handle_on_type_formatting( } let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = snap.analysis.on_char_typed( - position, - char_typed, - snap.config.typing_autoclose_angle(), - chars_to_exclude, - )?; + let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index d0c95912c3db..a3172c7ca2c4 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,11 +992,6 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`):: -+ --- -Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. --- [[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index e98205e0eab1..68c61e4bf622 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2602,16 +2602,6 @@ } } }, - { - "title": "typing", - "properties": { - "rust-analyzer.typing.autoClosingAngleBrackets.enable": { - "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", - "default": false, - "type": "boolean" - } - } - }, { "title": "typing", "properties": { From 337725ddc894f312387dbee936d484a09af44162 Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Tue, 3 Dec 2024 17:30:17 -0500 Subject: [PATCH 025/197] Remove references to platform-intrinsic ABI --- src/tools/rust-analyzer/crates/hir-ty/src/lib.rs | 3 --- .../crates/ide-completion/src/completions/extern_abi.rs | 1 - src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs | 1 - 3 files changed, 5 deletions(-) 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 975625fdfab7..fdc657976320 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -385,7 +385,6 @@ pub enum FnAbi { Fastcall, FastcallUnwind, Msp430Interrupt, - PlatformIntrinsic, PtxKernel, RiscvInterruptM, RiscvInterruptS, @@ -444,7 +443,6 @@ impl FnAbi { s if *s == sym::fastcall_dash_unwind => FnAbi::FastcallUnwind, s if *s == sym::fastcall => FnAbi::Fastcall, s if *s == sym::msp430_dash_interrupt => FnAbi::Msp430Interrupt, - s if *s == sym::platform_dash_intrinsic => FnAbi::PlatformIntrinsic, s if *s == sym::ptx_dash_kernel => FnAbi::PtxKernel, s if *s == sym::riscv_dash_interrupt_dash_m => FnAbi::RiscvInterruptM, s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS, @@ -487,7 +485,6 @@ impl FnAbi { FnAbi::Fastcall => "fastcall", FnAbi::FastcallUnwind => "fastcall-unwind", FnAbi::Msp430Interrupt => "msp430-interrupt", - FnAbi::PlatformIntrinsic => "platform-intrinsic", FnAbi::PtxKernel => "ptx-kernel", FnAbi::RiscvInterruptM => "riscv-interrupt-m", FnAbi::RiscvInterruptS => "riscv-interrupt-s", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index b0e417e6b335..847fa4cf889d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -38,7 +38,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "system-unwind", "rust-intrinsic", "rust-call", - "platform-intrinsic", "unadjusted", ]; diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 865518fe941e..8f79cf200790 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -99,7 +99,6 @@ define_symbols! { cdecl_dash_unwind = "cdecl-unwind", fastcall_dash_unwind = "fastcall-unwind", msp430_dash_interrupt = "msp430-interrupt", - platform_dash_intrinsic = "platform-intrinsic", ptx_dash_kernel = "ptx-kernel", riscv_dash_interrupt_dash_m = "riscv-interrupt-m", riscv_dash_interrupt_dash_s = "riscv-interrupt-s", From bc003049cfe3c85bfc3069ae8e76899efa6d08d1 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 03:15:32 +0200 Subject: [PATCH 026/197] Fixed another bug with glob imports When a glob import overriding the visibility of a previous glob import was not properly resolved when the items are only available in the next fixpoint iteration. The bug was hidden until #18390. --- .../crates/hir-def/src/nameres/collector.rs | 9 ++++- .../crates/hir-def/src/nameres/tests/globs.rs | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) 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 a37e3c70e22a..98b08bcf7086 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 @@ -910,8 +910,13 @@ impl DefCollector<'_> { self.update(module_id, &items, vis, Some(ImportType::Glob(id))); // record the glob import in case we add further items let glob = self.glob_imports.entry(m.local_id).or_default(); - if !glob.iter().any(|(mid, _, _)| *mid == module_id) { - glob.push((module_id, vis, id)); + match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) { + None => glob.push((module_id, vis, id)), + Some((_, old_vis, _)) => { + if let Some(new_vis) = old_vis.max(vis, &self.def_map) { + *old_vis = new_vis; + } + } } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs index 543ab41cd59a..8963a5767942 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs @@ -451,3 +451,42 @@ mod glob_target { "#]], ); } + +#[test] +fn regression_18580() { + check( + r#" +pub mod libs { + pub struct Placeholder; +} + +pub mod reexport_2 { + use reexport_1::*; + pub use reexport_1::*; + + pub mod reexport_1 { + pub use crate::libs::*; + } +} + +use reexport_2::*; +"#, + expect![[r#" + crate + Placeholder: t v + libs: t + reexport_1: t + reexport_2: t + + crate::libs + Placeholder: t v + + crate::reexport_2 + Placeholder: t v + reexport_1: t + + crate::reexport_2::reexport_1 + Placeholder: t v + "#]], + ); +} From 0d328a81ec0543ffbe63906f0e0b88bb2179ecc2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 03:38:37 +0200 Subject: [PATCH 027/197] Improve soundness a bit by making `TaggedArcPtr::try_as_arc_owned()` unsafe Since the `ManuallyDrop` it returns can be safely used to consume the `Arc`, which is can cause UB if done incorrectly. See #18499. --- .../rust-analyzer/crates/intern/src/symbol.rs | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index ef76192ba83e..200b14027f80 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -77,8 +77,12 @@ impl TaggedArcPtr { } /// Retrieves the tag. + /// + /// # Safety + /// + /// You can only drop the `Arc` if the instance is dropped. #[inline] - pub(crate) fn try_as_arc_owned(self) -> Option>>> { + pub(crate) unsafe fn try_as_arc_owned(self) -> Option>>> { // Unpack the tag from the alignment niche let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS; if tag != 0 { @@ -245,16 +249,14 @@ impl Symbol { } } - ManuallyDrop::into_inner( - match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { - RawEntryMut::Occupied(occ) => occ.remove_entry(), - RawEntryMut::Vacant(_) => unreachable!(), - } - .0 - .0 - .try_as_arc_owned() - .unwrap(), - ); + let ptr = match shard.raw_entry_mut().from_key_hashed_nocheck::(hash, arc.as_ref()) { + RawEntryMut::Occupied(occ) => occ.remove_entry(), + RawEntryMut::Vacant(_) => unreachable!(), + } + .0 + .0; + // SAFETY: We're dropping, we have ownership. + ManuallyDrop::into_inner(unsafe { ptr.try_as_arc_owned().unwrap() }); debug_assert_eq!(Arc::count(arc), 1); // Shrink the backing storage if the shard is less than 50% occupied. @@ -267,7 +269,8 @@ impl Symbol { impl Drop for Symbol { #[inline] fn drop(&mut self) { - let Some(arc) = self.repr.try_as_arc_owned() else { + // SAFETY: We're dropping, we have ownership. + let Some(arc) = (unsafe { self.repr.try_as_arc_owned() }) else { return; }; // When the last `Ref` is dropped, remove the object from the global map. @@ -288,7 +291,8 @@ impl Clone for Symbol { } fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr { - let Some(arc) = repr.try_as_arc_owned() else { + // SAFETY: We're not dropping the `Arc`. + let Some(arc) = (unsafe { repr.try_as_arc_owned() }) else { return repr; }; // increase the ref count From 45f0e817bbcf36320a90eeb0da212a5c804bcb47 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 04:02:54 +0200 Subject: [PATCH 028/197] Fix shadowing of record enum variant in patterns --- .../crates/hir-def/src/body/lower.rs | 14 +++++------ .../crates/hir-def/src/body/tests.rs | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) 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 1ab49e91569a..3b73d409634b 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 @@ -1510,20 +1510,20 @@ impl ExprCollector<'_> { BuiltinShadowMode::Other, None, ); + // Funnily enough, record structs/variants *can* be shadowed + // by pattern bindings (but unit or tuple structs/variants + // can't). match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), - Some(ModuleDefId::EnumVariantId(_)) => { - // this is only really valid for unit variants, but - // shadowing other enum variants with a pattern is - // an error anyway + Some(ModuleDefId::EnumVariantId(variant)) + if self.db.variant_data(variant.into()).kind() + != StructKind::Record => + { (None, Pat::Path(name.into())) } Some(ModuleDefId::AdtId(AdtId::StructId(s))) if self.db.struct_data(s).variant_data.kind() != StructKind::Record => { - // Funnily enough, record structs *can* be shadowed - // by pattern bindings (but unit or tuple structs - // can't). (None, Pat::Path(name.into())) } // shadowing statics is an error as well, so we just ignore that case here diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 3b29d98d198f..82d46d2e492c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -404,3 +404,26 @@ fn foo() { }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } + +#[test] +fn shadowing_record_variant() { + let (_, body, _) = lower( + r#" +enum A { + B { field: i32 }, +} +fn f() { + use A::*; + match () { + B => {} + }; +} + "#, + ); + assert_eq!(body.bindings.len(), 1, "should have a binding for `B`"); + assert_eq!( + body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(), + "B", + "should have a binding for `B`", + ); +} From 05aac8cd69ff15c6353dab1c27ad47e9def2d96f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 06:27:43 +0100 Subject: [PATCH 029/197] Better parser recovery for incomplete attributes --- .../crates/parser/src/grammar/attributes.rs | 10 ++- .../crates/parser/src/grammar/paths.rs | 19 ++-- .../rust-analyzer/crates/parser/src/parser.rs | 11 ++- .../parser/test_data/generated/runner.rs | 2 + .../parser/err/0004_use_path_bad_segment.rast | 5 +- .../parser/err/0048_double_fish.rast | 10 ++- .../parser/inline/err/meta_recovery.rast | 86 +++++++++++++++++++ .../parser/inline/err/meta_recovery.rs | 6 ++ 8 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs index 82e4d6614880..ccb556b2ccac 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs @@ -36,6 +36,14 @@ fn attr(p: &mut Parser<'_>, inner: bool) { attr.complete(p, ATTR); } +// test_err meta_recovery +// #![] +// #![p = ] +// #![p::] +// #![p:: =] +// #![unsafe] +// #![unsafe =] + // test metas // #![simple_ident] // #![simple::path] @@ -63,7 +71,7 @@ pub(super) fn meta(p: &mut Parser<'_>) { if is_unsafe { p.expect(T!['(']); } - paths::use_path(p); + paths::attr_path(p); match p.current() { T![=] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 09db921803f9..057a691ef033 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -19,6 +19,10 @@ pub(super) fn use_path(p: &mut Parser<'_>) { path(p, Mode::Use); } +pub(super) fn attr_path(p: &mut Parser<'_>) { + path(p, Mode::Attr); +} + pub(crate) fn type_path(p: &mut Parser<'_>) { path(p, Mode::Type); } @@ -37,6 +41,7 @@ pub(crate) fn type_path_for_qualifier( #[derive(Clone, Copy, Eq, PartialEq)] enum Mode { Use, + Attr, Type, Expr, } @@ -93,12 +98,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { p.error("expected `::`"); } } else { - let empty = if first { - p.eat(T![::]); - false - } else { - true - }; + let mut empty = if first { !p.eat(T![::]) } else { true }; match p.current() { IDENT => { name_ref(p); @@ -114,10 +114,13 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { _ => { let recover_set = match mode { Mode::Use => items::ITEM_RECOVERY_SET, + Mode::Attr => { + items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) + } Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, }; - p.err_recover("expected identifier", recover_set); + empty &= p.err_recover("expected identifier", recover_set); if empty { // test_err empty_segment // use crate::; @@ -132,7 +135,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { - Mode::Use => {} + Mode::Use | Mode::Attr => {} Mode::Type => { // test typepathfn_with_coloncolon // type F = Start::(Middle) -> (Middle)::End; diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index f6b3783d1cac..8078532e0bb9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -258,22 +258,25 @@ impl<'t> Parser<'t> { self.err_recover(message, TokenSet::EMPTY); } - /// Create an error node and consume the next token. - pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { + /// Create an error node and consume the next token unless it is in the recovery set. + /// + /// Returns true if recovery kicked in. + pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) -> bool { if matches!(self.current(), T!['{'] | T!['}']) { self.error(message); - return; + return true; } if self.at_ts(recovery) { self.error(message); - return; + return true; } let m = self.start(); self.error(message); self.bump_any(); m.complete(self, ERROR); + false } fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 62b381b6688d..3db8b51a4baf 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -772,6 +772,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/match_arms_recovery.rs"); } #[test] + fn meta_recovery() { run_and_expect_errors("test_data/parser/inline/err/meta_recovery.rs"); } + #[test] fn method_call_missing_argument_list() { run_and_expect_errors("test_data/parser/inline/err/method_call_missing_argument_list.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast index 44e192a5fcbc..cf455934e91d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast @@ -9,7 +9,8 @@ SOURCE_FILE NAME_REF IDENT "foo" COLON2 "::" - ERROR - INT_NUMBER "92" + PATH_SEGMENT + ERROR + INT_NUMBER "92" SEMICOLON ";" error 9: expected identifier diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast index 207a5c24dffd..7ef1eb98fcd9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast @@ -39,8 +39,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" TYPE_ARG PATH_TYPE PATH @@ -91,8 +92,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" EXPR_STMT BIN_EXPR PATH_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast new file mode 100644 index 000000000000..c4bec849e7b9 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -0,0 +1,86 @@ +SOURCE_FILE + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + WHITESPACE " " + EQ "=" + WHITESPACE " " + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + WHITESPACE " " + EQ "=" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + PATH + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + WHITESPACE " " + PATH + EQ "=" + R_BRACK "]" + WHITESPACE "\n" +error 3: expected identifier +error 11: expected expression +error 11: expected expression +error 20: expected identifier +error 28: expected identifier +error 30: expected expression +error 30: expected expression +error 41: expected L_PAREN +error 41: expected identifier +error 41: expected R_PAREN +error 52: expected L_PAREN +error 53: expected identifier +error 54: expected expression +error 54: expected expression +error 54: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs new file mode 100644 index 000000000000..51d30adf8b49 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs @@ -0,0 +1,6 @@ +#![] +#![p = ] +#![p::] +#![p:: =] +#![unsafe] +#![unsafe =] From 7efe7eb3769a88814e9898313757dbd468f22e0f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 06:49:27 +0100 Subject: [PATCH 030/197] fix: Don't create empty path nodes --- .../crates/parser/src/grammar.rs | 4 ++-- .../crates/parser/src/grammar/generic_args.rs | 4 ++-- .../crates/parser/src/grammar/paths.rs | 23 +++++++++++++------ .../rust-analyzer/crates/parser/src/parser.rs | 8 +++---- .../err/crate_visibility_empty_recover.rast | 6 +---- .../parser/inline/err/meta_recovery.rast | 5 +--- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index a50a2182a7b9..c402c498553b 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -242,7 +242,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { // struct MyStruct(pub ()); if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { p.bump(T!['(']); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } } @@ -252,7 +252,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { T![in] => { p.bump(T!['(']); p.bump(T![in]); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } _ => {} diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index c62c8a9d3f92..77379ef14719 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -168,10 +168,10 @@ pub(super) fn const_arg_expr(p: &mut Parser<'_>) { expressions::literal(p); lm.complete(p, PREFIX_EXPR); } - _ if paths::is_use_path_start(p) => { + _ if paths::is_path_start(p) => { // This shouldn't be hit by `const_arg` let lm = p.start(); - paths::use_path(p); + paths::expr_path(p); lm.complete(p, PATH_EXPR); } _ => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 057a691ef033..15b35296423c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -19,6 +19,10 @@ pub(super) fn use_path(p: &mut Parser<'_>) { path(p, Mode::Use); } +pub(super) fn vis_path(p: &mut Parser<'_>) { + path(p, Mode::Vis); +} + pub(super) fn attr_path(p: &mut Parser<'_>) { path(p, Mode::Attr); } @@ -44,13 +48,17 @@ enum Mode { Attr, Type, Expr, + Vis, } -fn path(p: &mut Parser<'_>, mode: Mode) { +fn path(p: &mut Parser<'_>, mode: Mode) -> Option { let path = p.start(); - path_segment(p, mode, true); + if path_segment(p, mode, true).is_none() { + path.abandon(p); + return None; + } let qual = path.complete(p, PATH); - path_for_qualifier(p, mode, qual); + Some(path_for_qualifier(p, mode, qual)) } fn path_for_qualifier( @@ -76,7 +84,7 @@ const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; -fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { +fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { let m = p.start(); // test qual_paths // type X = ::Output; @@ -117,6 +125,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { Mode::Attr => { items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) } + Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, }; @@ -125,17 +134,17 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { // test_err empty_segment // use crate::; m.abandon(p); - return; + return None; } } }; } - m.complete(p, PATH_SEGMENT); + Some(m.complete(p, PATH_SEGMENT)) } fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { - Mode::Use | Mode::Attr => {} + Mode::Use | Mode::Attr | Mode::Vis => {} Mode::Type => { // test typepathfn_with_coloncolon // type F = Start::(Middle) -> (Middle)::End; diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index 8078532e0bb9..75a75f601cf1 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -327,10 +327,10 @@ impl Marker { self.bomb.defuse(); let idx = self.pos as usize; if idx == p.events.len() - 1 { - match p.events.pop() { - Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (), - _ => unreachable!(), - } + assert!(matches!( + p.events.pop(), + Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) + )); } } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 0fe4ca42d79d..681ca6b6e05a 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -3,10 +3,7 @@ SOURCE_FILE VISIBILITY PUB_KW "pub" L_PAREN "(" - PATH - PATH_SEGMENT - ERROR - R_PAREN ")" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -15,4 +12,3 @@ SOURCE_FILE SEMICOLON ";" WHITESPACE "\n" error 4: expected identifier -error 5: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast index c4bec849e7b9..926dd50fc859 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -4,7 +4,6 @@ SOURCE_FILE BANG "!" L_BRACK "[" META - PATH R_BRACK "]" WHITESPACE "\n" ATTR @@ -55,7 +54,6 @@ SOURCE_FILE L_BRACK "[" META UNSAFE_KW "unsafe" - PATH R_BRACK "]" WHITESPACE "\n" ATTR @@ -65,7 +63,6 @@ SOURCE_FILE META UNSAFE_KW "unsafe" WHITESPACE " " - PATH EQ "=" R_BRACK "]" WHITESPACE "\n" @@ -80,7 +77,7 @@ error 41: expected L_PAREN error 41: expected identifier error 41: expected R_PAREN error 52: expected L_PAREN -error 53: expected identifier +error 52: expected identifier error 54: expected expression error 54: expected expression error 54: expected R_PAREN From 1e47f7d073b06910795ed0ce2d5ae8560d2fb6ac Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 07:03:01 +0100 Subject: [PATCH 031/197] Update mbe test output --- .../crates/hir-def/src/macro_expansion_tests/mbe.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index d568f6faa729..5c03fad6131b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1759,8 +1759,9 @@ fn f() { // NAME_REF@6..7 // IDENT@6..7 "K" // COLON2@7..9 "::" -// ERROR@9..10 -// L_PAREN@9..10 "(" +// PATH_SEGMENT@9..10 +// ERROR@9..10 +// L_PAREN@9..10 "(" // EXPR_STMT@10..16 // CALL_EXPR@10..16 // PATH_EXPR@10..11 From d2ee916c3094c100216c93d4ddd8b57519e7c599 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 01:34:52 +0200 Subject: [PATCH 032/197] Complete derive helper attributes Only their names, anything can go inside. --- .../rust-analyzer/crates/hir/src/semantics.rs | 16 +++++ .../src/completions/attribute.rs | 13 +++- .../crates/ide-completion/src/context.rs | 5 +- .../ide-completion/src/context/analysis.rs | 17 ++++- .../ide-completion/src/tests/attribute.rs | 64 +++++++++++++++++++ 5 files changed, 111 insertions(+), 4 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 46766fcc5b10..65470d061b37 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -510,6 +510,22 @@ impl<'db> SemanticsImpl<'db> { self.with_ctx(|ctx| ctx.has_derives(adt)) } + pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option> { + let sa = self.analyze_no_infer(adt.syntax())?; + let id = self.db.ast_id_map(sa.file_id).ast_id(adt); + let result = sa + .resolver + .def_map() + .derive_helpers_in_scope(InFile::new(sa.file_id, id))? + .iter() + .map(|(name, macro_, _)| { + let macro_name = Macro::from(*macro_).name(self.db).symbol().clone(); + (name.symbol().clone(), macro_name) + }) + .collect(); + Some(result) + } + pub fn derive_helper(&self, attr: &ast::Attr) -> Option> { let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it { ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index d0b489c4e836..cf5427bae38d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path( acc: &mut Completions, ctx: &CompletionContext<'_>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &AttrCtx { kind, annotated_item_kind }: &AttrCtx, + &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx, ) { let is_inner = kind == AttrKind::Inner; + for (derive_helper, derive_name) in derive_helpers { + let mut item = CompletionItem::new( + SymbolKind::Attribute, + ctx.source_range(), + derive_helper.as_str(), + ctx.edition, + ); + item.detail(format!("derive helper of `{derive_name}`")); + item.add_to(acc, ctx.db); + } + match qualified { Qualified::With { resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), 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 efbee39a2d49..5b8d1c30a295 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -7,8 +7,8 @@ mod tests; use std::{iter, ops::ControlFlow}; use hir::{ - HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, - TypeInfo, + HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, + Symbol, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition, @@ -133,6 +133,7 @@ pub(crate) type ExistingDerives = FxHashSet; pub(crate) struct AttrCtx { pub(crate) kind: AttrKind, pub(crate) annotated_item_kind: Option, + pub(crate) derive_helpers: Vec<(Symbol, Symbol)>, } #[derive(Debug, PartialEq, Eq)] 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 468ad81ad2f8..a4e018b18000 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 @@ -1129,7 +1129,22 @@ fn classify_name_ref( let is_trailing_outer_attr = kind != AttrKind::Inner && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none(); let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) }; - Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } }) + let derive_helpers = annotated_item_kind + .filter(|kind| { + matches!( + kind, + SyntaxKind::STRUCT + | SyntaxKind::ENUM + | SyntaxKind::UNION + | SyntaxKind::VARIANT + | SyntaxKind::TUPLE_FIELD + | SyntaxKind::RECORD_FIELD + ) + }) + .and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast)) + .and_then(|adt| sema.derive_helpers_in_scope(&adt)) + .unwrap_or_default(); + Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } }) }; // Infer the path kind diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 45679355b427..1443ebc6c0c7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -8,6 +8,70 @@ fn check(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual); } +#[test] +fn derive_helpers() { + check( + r#" +//- /mac.rs crate:mac +#![crate_type = "proc-macro"] + +#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))] +pub fn my_derive() {} + +//- /lib.rs crate:lib deps:mac +#[rustc_builtin_macro] +pub macro derive($item:item) {} + +#[derive(mac::MyDerive)] +pub struct Foo(#[m$0] i32); +"#, + expect![[r#" + at allow(…) + at automatically_derived + at cfg(…) + at cfg_attr(…) + at cold + at deny(…) + at deprecated + at derive macro derive + at derive(…) + at doc = "…" + at doc(alias = "…") + at doc(hidden) + at expect(…) + at export_name = "…" + at forbid(…) + at global_allocator + at ignore = "…" + at inline + at link + at link_name = "…" + at link_section = "…" + at macro_export + at macro_use + at must_use + at my_cool_helper_attribute derive helper of `MyDerive` + at no_mangle + at non_exhaustive + at panic_handler + at path = "…" + at proc_macro + at proc_macro_attribute + at proc_macro_derive(…) + at repr(…) + at should_panic + at target_feature(enable = "…") + at test + at track_caller + at used + at warn(…) + md mac + kw crate:: + kw self:: + "#]], + ) +} + #[test] fn proc_macros() { check( From 9296578960673092625dc4955f153a52a8a93750 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 08:05:23 +0200 Subject: [PATCH 033/197] Extend reported unsafe operations We add union fields access (in both expressions and patterns) and inline assembly. That completes the unsafe check (there are some other unsafe things but they are unstable), and so also opens the door to reporting unused unsafe without annoying people about their not-unused unsafe blocks. --- .../rust-analyzer/crates/hir-def/src/body.rs | 139 +++++++- .../crates/hir-ty/src/diagnostics.rs | 2 +- .../hir-ty/src/diagnostics/unsafe_check.rs | 319 +++++++++++++----- .../crates/hir/src/diagnostics.rs | 7 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 9 +- .../crates/hir/src/source_analyzer.rs | 6 +- .../src/handlers/missing_unsafe.rs | 154 +++++++-- 7 files changed, 511 insertions(+), 125 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 5a386f6cf8d1..d4a1120908f0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -408,7 +408,8 @@ impl Body { f(else_branch); } } - Expr::Let { expr, .. } => { + Expr::Let { expr, pat } => { + self.walk_exprs_in_pat(*pat, &mut f); f(*expr); } Expr::Block { statements, tail, .. } @@ -442,6 +443,137 @@ impl Body { f(*receiver); args.iter().copied().for_each(f); } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().for_each(|arm| { + f(arm.expr); + self.walk_exprs_in_pat(arm.pat, &mut f); + }); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target, value } => { + self.walk_exprs_in_pat(target, &mut f); + f(value); + } + } + } + + pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, .. } => { + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } Expr::Match { expr, arms } => { f(*expr); arms.iter().map(|arm| arm.expr).for_each(f); @@ -498,10 +630,7 @@ impl Body { f(*repeat) } }, - &Expr::Assignment { target, value } => { - self.walk_exprs_in_pat(target, &mut f); - f(value); - } + &Expr::Assignment { target: _, value } => f(value), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index af4d2c9fc046..30c02a2936dd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -9,5 +9,5 @@ pub use crate::diagnostics::{ expr::{ record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, }, - unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, + unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index c7f7fb7ad3d3..193aaa52c26e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -1,12 +1,16 @@ //! Provides validations for unsafe code. Currently checks if unsafe functions are missing //! unsafe blocks. +use std::mem; + +use either::Either; use hir_def::{ body::Body, - hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp}, - resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp}, + path::Path, + resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, type_ref::Rawness, - DefWithBodyId, + AdtId, DefWithBodyId, FieldId, VariantId, }; use crate::{ @@ -16,7 +20,10 @@ use crate::{ /// Returns `(unsafe_exprs, fn_is_unsafe)`. /// /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`. -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec, bool) { +pub fn missing_unsafe( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> (Vec<(ExprOrPatId, UnsafetyReason)>, bool) { let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); @@ -30,111 +37,243 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec { + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + resolver: Resolver, def: DefWithBodyId, - current: ExprId, - inside_unsafe_block: bool, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), -) { - let mut mark_unsafe_path = |path, node| { - let g = resolver.update_to_inner_scope(db.upcast(), def, current); - let hygiene = body.expr_or_pat_path_hygiene(node); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene); - if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - let static_data = db.static_data(id); - if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { - unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block }); - } - } - resolver.reset_to_guard(g); - }; + inside_unsafe_block: InsideUnsafeBlock, + inside_assignment: bool, + inside_union_destructure: bool, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), +} - let expr = &body.exprs[current]; - match expr { - &Expr::Call { callee, .. } => { - if let Some(func) = infer[callee].as_fn_def(db) { - if is_fn_unsafe_to_call(db, func) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); - } - } +impl<'a> UnsafeVisitor<'a> { + fn new( + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + def: DefWithBodyId, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), + ) -> Self { + let resolver = def.resolver(db.upcast()); + Self { + db, + infer, + body, + resolver, + def, + inside_unsafe_block: InsideUnsafeBlock::No, + inside_assignment: false, + inside_union_destructure: false, + unsafe_expr_cb, } - Expr::Path(path) => mark_unsafe_path(path, current.into()), - Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { - if let Expr::Path(_) = body.exprs[*expr] { - // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, - // see https://github.com/rust-lang/rust/pull/125834. - return; - } - } - Expr::MethodCall { .. } => { - if infer - .method_resolution(current) - .map(|(func, _)| is_fn_unsafe_to_call(db, func)) - .unwrap_or(false) - { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); - } - } - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &infer[*expr].kind(Interner) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); - } - } - Expr::Unsafe { .. } => { - return body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb); - }); - } - &Expr::Assignment { target, value: _ } => { - body.walk_pats(target, &mut |pat| { - if let Pat::Path(path) = &body[pat] { - mark_unsafe_path(path, pat.into()); - } - }); - } - _ => {} } - body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb); - }); + fn call_cb(&mut self, node: ExprOrPatId, reason: UnsafetyReason) { + (self.unsafe_expr_cb)(node, self.inside_unsafe_block, reason); + } + + fn walk_pats_top(&mut self, pats: impl Iterator, parent_expr: ExprId) { + let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.def, parent_expr); + pats.for_each(|pat| self.walk_pat(pat)); + self.resolver.reset_to_guard(guard); + } + + fn walk_pat(&mut self, current: PatId) { + let pat = &self.body.pats[current]; + + if self.inside_union_destructure { + match pat { + Pat::Tuple { .. } + | Pat::Record { .. } + | Pat::Range { .. } + | Pat::Slice { .. } + | Pat::Path(..) + | Pat::Lit(..) + | Pat::Bind { .. } + | Pat::TupleStruct { .. } + | Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Expr(..) + | Pat::ConstBlock(..) => self.call_cb(current.into(), UnsafetyReason::UnionField), + // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. + Pat::Missing | Pat::Wild | Pat::Or(_) => {} + } + } + + match pat { + Pat::Record { .. } => { + if let Some((AdtId::UnionId(_), _)) = self.infer[current].as_adt() { + let old_inside_union_destructure = + mem::replace(&mut self.inside_union_destructure, true); + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + self.inside_union_destructure = old_inside_union_destructure; + return; + } + } + Pat::Path(path) => self.mark_unsafe_path(current.into(), path), + &Pat::ConstBlock(expr) => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); + self.walk_expr(expr); + self.inside_assignment = old_inside_assignment; + } + &Pat::Expr(expr) => self.walk_expr(expr), + _ => {} + } + + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + } + + fn walk_expr(&mut self, current: ExprId) { + let expr = &self.body.exprs[current]; + let inside_assignment = mem::replace(&mut self.inside_assignment, false); + match expr { + &Expr::Call { callee, .. } => { + if let Some(func) = self.infer[callee].as_fn_def(self.db) { + if is_fn_unsafe_to_call(self.db, func) { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); + } + } + } + Expr::Path(path) => { + let guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.def, current); + self.mark_unsafe_path(current.into(), path); + self.resolver.reset_to_guard(guard); + } + Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { + if let Expr::Path(_) = self.body.exprs[*expr] { + // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, + // see https://github.com/rust-lang/rust/pull/125834. + return; + } + } + Expr::MethodCall { .. } => { + if self + .infer + .method_resolution(current) + .map(|(func, _)| is_fn_unsafe_to_call(self.db, func)) + .unwrap_or(false) + { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); + } + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let TyKind::Raw(..) = &self.infer[*expr].kind(Interner) { + self.call_cb(current.into(), UnsafetyReason::RawPtrDeref); + } + } + Expr::Unsafe { .. } => { + let old_inside_unsafe_block = + mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes); + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); + self.inside_unsafe_block = old_inside_unsafe_block; + return; + } + &Expr::Assignment { target, value: _ } => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, true); + self.walk_pats_top(std::iter::once(target), current); + self.inside_assignment = old_inside_assignment; + } + Expr::InlineAsm(_) => self.call_cb(current.into(), UnsafetyReason::InlineAsm), + // rustc allows union assignment to propagate through field accesses and casts. + Expr::Cast { .. } => self.inside_assignment = inside_assignment, + Expr::Field { .. } => { + self.inside_assignment = inside_assignment; + if !inside_assignment { + if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) = + self.infer.field_resolution(current) + { + self.call_cb(current.into(), UnsafetyReason::UnionField); + } + } + } + Expr::Block { statements, .. } | Expr::Async { statements, .. } => { + self.walk_pats_top( + statements.iter().filter_map(|statement| match statement { + &Statement::Let { pat, .. } => Some(pat), + _ => None, + }), + current, + ); + } + Expr::Match { arms, .. } => { + self.walk_pats_top(arms.iter().map(|arm| arm.pat), current); + } + &Expr::Let { pat, .. } => { + self.walk_pats_top(std::iter::once(pat), current); + } + Expr::Closure { args, .. } => { + self.walk_pats_top(args.iter().copied(), current); + } + _ => {} + } + + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); + } + + fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) { + let hygiene = self.body.expr_or_pat_path_hygiene(node); + let value_or_partial = + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene); + if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { + let static_data = self.db.static_data(id); + if static_data.mutable { + self.call_cb(node, UnsafetyReason::MutableStatic); + } else if static_data.is_extern && !static_data.has_safe_kw { + self.call_cb(node, UnsafetyReason::ExternStatic); + } + } + } } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 8297acde857d..9ca021027d54 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -5,7 +5,9 @@ //! be expressed in terms of hir types themselves. pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; use hir_ty::{ - db::HirDatabase, diagnostics::BodyValidationDiagnostic, CastError, InferenceDiagnostic, + db::HirDatabase, + diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, + CastError, InferenceDiagnostic, }; use cfg::{CfgExpr, CfgOptions}; @@ -258,9 +260,10 @@ pub struct PrivateField { #[derive(Debug)] pub struct MissingUnsafe { - pub expr: InFile>>, + pub node: InFile>>, /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error. pub only_lint: bool, + pub reason: UnsafetyReason, } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c9498b3aead7..0b2ba56b1ff1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -147,6 +147,7 @@ pub use { }, hir_ty::{ consteval::ConstEvalError, + diagnostics::UnsafetyReason, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, @@ -1890,10 +1891,10 @@ impl DefWithBody { ); } - let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); - for expr in unafe_exprs { - match source_map.expr_or_pat_syntax(expr) { - Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()), + let (unsafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); + for (node, reason) in unsafe_exprs { + match source_map.expr_or_pat_syntax(node) { + Ok(node) => acc.push(MissingUnsafe { node, only_lint, reason }.into()), Err(SyntheticSyntax) => { // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. 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 c16454cff68f..56ed81f053c1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -36,7 +36,7 @@ use hir_expand::{ use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, - UnsafeExpr, + InsideUnsafeBlock, }, lang_items::lang_items_for_bin_op, method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, @@ -939,8 +939,8 @@ impl SourceAnalyzer { *def, body, expr_id, - &mut |UnsafeExpr { inside_unsafe_block, .. }| { - is_unsafe |= !inside_unsafe_block + &mut |_, inside_unsafe_block, _| { + is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No }, ) }; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a630d3c7c36d..2bfdda35659b 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,5 +1,5 @@ use hir::db::ExpandDatabase; -use hir::HirFileIdExt; +use hir::{HirFileIdExt, UnsafetyReason}; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, SyntaxNode}; @@ -16,23 +16,35 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf } else { DiagnosticCode::RustcHardError("E0133") }; + let operation = display_unsafety_reason(d.reason); Diagnostic::new_with_syntax_node_ptr( ctx, code, - "this operation is unsafe and requires an unsafe function or block", - d.expr.map(|it| it.into()), + format!("{operation} is unsafe and requires an unsafe function or block"), + d.node.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } +fn display_unsafety_reason(reason: UnsafetyReason) -> &'static str { + match reason { + UnsafetyReason::UnionField => "access to union field", + UnsafetyReason::UnsafeFnCall => "call to unsafe function", + UnsafetyReason::InlineAsm => "use of inline assembly", + UnsafetyReason::RawPtrDeref => "dereference of raw pointer", + UnsafetyReason::MutableStatic => "use of mutable static", + UnsafetyReason::ExternStatic => "use of extern static", + } +} + fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option> { // The fixit will not work correctly for macro expansions, so we don't offer it in that case. - if d.expr.file_id.is_macro() { + if d.node.file_id.is_macro() { return None; } - let root = ctx.sema.db.parse_or_expand(d.expr.file_id); - let node = d.expr.value.to_node(&root); + let root = ctx.sema.db.parse_or_expand(d.node.file_id); + let node = d.node.value.to_node(&root); let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?; let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; @@ -40,7 +52,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option u8 { fn main() { ed2021::safe(); ed2024::not_safe(); - //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ) @@ -591,7 +603,7 @@ unsafe fn foo(p: *mut i32) { #![warn(unsafe_op_in_unsafe_fn)] unsafe fn foo(p: *mut i32) { *p = 123; - //^^💡 warn: this operation is unsafe and requires an unsafe function or block + //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block } "#, ) @@ -618,17 +630,119 @@ unsafe extern { fn main() { f(); g(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block h(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block let _ = S1; let _ = S2; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _ = S3; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block } "#, ); } + + #[test] + fn no_unsafe_diagnostic_when_destructuring_union_with_wildcard() { + check_diagnostics( + r#" +union Union { field: i32 } +fn foo(v: &Union) { + let Union { field: _ } = v; + let Union { field: _ | _ } = v; + Union { field: _ } = *v; +} +"#, + ); + } + + #[test] + fn union_destructuring() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v @ Union { field: _field }: &Union) { + // ^^^^^^ error: access to union field is unsafe and requires an unsafe function or block + let Union { mut field } = v; + // ^^^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0 + // ^💡 error: access to union field is unsafe and requires an unsafe function or block + | 1..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + Union { field } = *v; + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + match v { + Union { field: _field } => {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + } + if let Union { field: _field } = v {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + (|&Union { field }| { _ = field; })(v); + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn union_field_access() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v: &Union) { + v.field; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn inline_asm() { + check_diagnostics( + r#" +//- minicore: asm +fn foo() { + core::arch::asm!(""); + // ^^^^ error: use of inline assembly is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn unsafe_op_in_unsafe_fn_dismissed_in_signature() { + check_diagnostics( + r#" +#![warn(unsafe_op_in_unsafe_fn)] +union Union { field: u32 } +unsafe fn foo(Union { field: _field }: Union) {} + "#, + ) + } + + #[test] + fn union_assignment_allowed() { + check_diagnostics( + r#" +union Union { field: u32 } +fn foo(mut v: Union) { + v.field = 123; + (v.field,) = (123,); + *&mut v.field = 123; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +struct Struct { field: u32 } +union Union2 { field: Struct } +fn bar(mut v: Union2) { + v.field.field = 123; +} + + "#, + ) + } } From baf4862fb277c06bf7750a09f949ba81500b6497 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 27 Nov 2024 12:08:21 +0200 Subject: [PATCH 034/197] =?UTF-8?q?feat:=20migrate=C2=A0`sort=5Fitems`?= =?UTF-8?q?=C2=A0assist=20to=20use=C2=A0`SyntaxFactory`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tarek --- .../ide-assists/src/handlers/sort_items.rs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 64e30b183452..6a37a72996f6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use syntax::{ ast::{self, HasName}, - ted, AstNode, TextRange, + AstNode, SyntaxNode, }; use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists}; @@ -114,7 +114,7 @@ trait AddRewrite { label: &str, old: Vec, new: Vec, - target: TextRange, + target: SyntaxNode, ) -> Option<()>; } @@ -124,15 +124,24 @@ impl AddRewrite for Assists { label: &str, old: Vec, new: Vec, - target: TextRange, + target: SyntaxNode, ) -> Option<()> { - self.add(AssistId("sort_items", AssistKind::RefactorRewrite), label, target, |builder| { - let mutable: Vec = old.into_iter().map(|it| builder.make_mut(it)).collect(); - mutable - .into_iter() - .zip(new) - .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax())); - }) + let node = old.first().unwrap().syntax().parent().unwrap(); + self.add( + AssistId("sort_items", AssistKind::RefactorRewrite), + label, + target.text_range(), + |builder| { + let mut editor = builder.make_editor(&node); + + old.into_iter().zip(new).for_each(|(old, new)| { + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(old.syntax(), new.clone_for_update().syntax()) + }); + + builder.add_file_edits(builder.file_id, editor) + }, + ) } } @@ -167,7 +176,7 @@ fn add_sort_methods_assist( return None; } - acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().text_range()) + acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().clone()) } fn add_sort_fields_assist( @@ -186,7 +195,7 @@ fn add_sort_fields_assist( "Sort fields alphabetically", fields, sorted, - record_field_list.syntax().text_range(), + record_field_list.syntax().clone(), ) } @@ -199,12 +208,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) - return None; } - acc.add_rewrite( - "Sort variants alphabetically", - variants, - sorted, - variant_list.syntax().text_range(), - ) + acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax().clone()) } fn sort_by_name(initial: &[T]) -> Vec { From a1fa4971a6e71a4011b004024ae85a68d0d550e1 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 12:42:07 +0200 Subject: [PATCH 035/197] refactor: change target parameter to a reference in add_rewrite method Signed-off-by: Tarek --- .../ide-assists/src/handlers/sort_items.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 6a37a72996f6..7307325e496c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -114,7 +114,7 @@ trait AddRewrite { label: &str, old: Vec, new: Vec, - target: SyntaxNode, + target: &SyntaxNode, ) -> Option<()>; } @@ -124,15 +124,14 @@ impl AddRewrite for Assists { label: &str, old: Vec, new: Vec, - target: SyntaxNode, + target: &SyntaxNode, ) -> Option<()> { - let node = old.first().unwrap().syntax().parent().unwrap(); self.add( AssistId("sort_items", AssistKind::RefactorRewrite), label, target.text_range(), |builder| { - let mut editor = builder.make_editor(&node); + let mut editor = builder.make_editor(target); old.into_iter().zip(new).for_each(|(old, new)| { // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us @@ -176,7 +175,7 @@ fn add_sort_methods_assist( return None; } - acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().clone()) + acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax()) } fn add_sort_fields_assist( @@ -191,12 +190,7 @@ fn add_sort_fields_assist( return None; } - acc.add_rewrite( - "Sort fields alphabetically", - fields, - sorted, - record_field_list.syntax().clone(), - ) + acc.add_rewrite("Sort fields alphabetically", fields, sorted, record_field_list.syntax()) } fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -> Option<()> { @@ -208,7 +202,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) - return None; } - acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax().clone()) + acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax()) } fn sort_by_name(initial: &[T]) -> Vec { From 2b4dc9caac1c05ae53e0d09907c40de1b1a75392 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Dec 2024 18:29:00 +0100 Subject: [PATCH 036/197] Fix parsing of parenthesized type args and RTN --- .../crates/hir-def/src/path/lower.rs | 8 +- .../crates/ide-db/src/path_transform.rs | 3 +- .../crates/ide-ssr/src/matching.rs | 4 +- .../crates/ide/src/inlay_hints/lifetime.rs | 94 ++-- .../crates/parser/src/grammar/expressions.rs | 2 +- .../crates/parser/src/grammar/generic_args.rs | 65 +-- .../crates/parser/src/grammar/params.rs | 18 +- .../crates/parser/src/grammar/paths.rs | 104 ++-- .../crates/parser/src/grammar/types.rs | 4 +- .../parser/src/syntax_kind/generated.rs | 1 + .../parser/test_data/generated/runner.rs | 32 +- .../inline/err/generic_arg_list_recover.rast | 33 ++ .../inline/err/generic_arg_list_recover.rs | 1 + .../err/generic_arg_list_recover_expr.rast | 79 +++ .../err/generic_arg_list_recover_expr.rs | 2 + .../parser/inline/ok/assoc_type_bound.rast | 39 ++ .../parser/inline/ok/assoc_type_bound.rs | 1 + .../inline/ok/associated_type_bounds.rast | 111 ----- .../inline/ok/associated_type_bounds.rs | 1 - .../parser/inline/ok/async_trait_bound.rast | 4 +- ..._dyn_types_with_paren_as_generic_args.rast | 175 ------- ...re_dyn_types_with_paren_as_generic_args.rs | 4 - .../parser/inline/ok/generic_arg_bounds.rast | 461 ++++++++++++++++++ .../parser/inline/ok/generic_arg_bounds.rs | 4 + .../inline/ok/param_list_opt_patterns.rast | 48 -- .../inline/ok/param_list_opt_patterns.rs | 1 - .../parser/inline/ok/path_fn_trait_args.rast | 128 ++++- .../parser/inline/ok/path_fn_trait_args.rs | 3 + .../return_type_syntax_assoc_type_bound.rast | 49 -- .../ok/return_type_syntax_assoc_type_bound.rs | 1 - .../inline/ok/return_type_syntax_in_path.rast | 43 ++ .../inline/ok/return_type_syntax_in_path.rs | 2 + .../inline/ok/typepathfn_with_coloncolon.rast | 10 +- .../ok/value_parameters_no_patterns.rast | 60 --- .../inline/ok/value_parameters_no_patterns.rs | 1 - .../parser/inline/ok/where_pred_for.rast | 4 +- .../test_data/parser/ok/0045_block_attrs.rast | 2 +- .../parser/ok/0051_parameter_attrs.rast | 57 --- .../parser/ok/0051_parameter_attrs.rs | 2 - .../parser/ok/0054_qual_path_in_type_arg.rast | 8 +- .../ok/0065_plus_after_fn_trait_bound.rast | 2 +- .../parser/ok/0067_where_for_pred.rast | 8 +- .../rust-analyzer/crates/syntax/rust.ungram | 5 +- .../crates/syntax/src/ast/generated/nodes.rs | 38 +- 44 files changed, 1022 insertions(+), 700 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs 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 553e615b94f3..37c94a5f1188 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 @@ -48,7 +48,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< .or_else(|| { lower_generic_args_from_fn_path( ctx, - segment.param_list(), + segment.parenthesized_arg_list(), segment.ret_type(), ) }); @@ -247,12 +247,12 @@ pub(super) fn lower_generic_args( /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). fn lower_generic_args_from_fn_path( ctx: &mut LowerCtx<'_>, - params: Option, + args: Option, ret_type: Option, ) -> Option { - let params = params?; + let params = args?; let mut param_types = Vec::new(); - for param in params.params() { + for param in params.type_args() { let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); param_types.push(type_ref); } 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 49b3ca290f07..a508f2fedd64 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 @@ -286,7 +286,8 @@ impl Ctx<'_> { return None; } if path.segment().map_or(false, |s| { - s.param_list().is_some() || (s.self_token().is_some() && path.parent_path().is_none()) + s.parenthesized_arg_list().is_some() + || (s.self_token().is_some() && path.parent_path().is_none()) }) { // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway // don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing 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 6569f0f5552f..4edc3633fbe6 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -359,8 +359,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> { )?; self.attempt_match_opt( phase, - pattern_segment.param_list(), - code_segment.param_list(), + pattern_segment.parenthesized_arg_list(), + code_segment.parenthesized_arg_list(), )?; } if matches!(phase, Phase::Second(_)) { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index 2163c959b18a..1fdd69899171 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -41,7 +41,15 @@ pub(super) fn fn_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, self_param, @@ -90,7 +98,15 @@ pub(super) fn fn_ptr_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, None, @@ -148,7 +164,7 @@ pub(super) fn fn_path_hints( fd, config, file_id, - param_list, + param_list.type_args().filter_map(|it| Some((None, it.ty()?))), generic_param_list, ret_type, None, @@ -177,8 +193,8 @@ pub(super) fn fn_path_hints( ) } -fn path_as_fn(path: &ast::Path) -> Option<(ast::ParamList, Option)> { - path.segment().and_then(|it| it.param_list().zip(Some(it.ret_type()))) +fn path_as_fn(path: &ast::Path) -> Option<(ast::ParenthesizedArgList, Option)> { + path.segment().and_then(|it| it.parenthesized_arg_list().zip(Some(it.ret_type()))) } fn hints_( @@ -187,7 +203,7 @@ fn hints_( FamousDefs(_, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, _file_id: EditionedFileId, - param_list: ast::ParamList, + params: impl Iterator, ast::Type)>, generic_param_list: Option, ret_type: Option, self_param: Option, @@ -217,45 +233,34 @@ fn hints_( let is_elided = is_elided(&lifetime); acc.push((None, self_param.amp_token(), lifetime, is_elided)); } - param_list - .params() - .filter_map(|it| { - Some(( - it.pat().and_then(|it| match it { - ast::Pat::IdentPat(p) => p.name(), - _ => None, - }), - it.ty()?, - )) - }) - .for_each(|(name, ty)| { - // FIXME: check path types - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(r) => { - let lifetime = r.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); - false - } - ast::Type::FnPtrType(_) => { + params.for_each(|(name, ty)| { + // FIXME: check path types + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(r) => { + let lifetime = r.lifetime(); + let is_elided = is_elided(&lifetime); + acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() + { is_trivial = false; true + } else { + false } - ast::Type::PathType(t) => { - if t.path() - .and_then(|it| it.segment()) - .and_then(|it| it.param_list()) - .is_some() - { - is_trivial = false; - true - } else { - false - } - } - _ => false, - }) - }); + } + _ => false, + }) + }); acc }; @@ -339,7 +344,10 @@ fn hints_( true } ast::Type::PathType(t) => { - if t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() { is_trivial = false; true diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index e565874a4212..349bce09390e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -525,7 +525,7 @@ fn method_call_expr( p.bump(T![.]); } name_ref(p); - generic_args::opt_generic_arg_list(p, true); + generic_args::opt_generic_arg_list_expr(p); if p.at(T!['(']) { arg_list(p); } else { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index 77379ef14719..737010985b23 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -1,14 +1,13 @@ use super::*; -// test_err generic_arg_list_recover -// type T = T<0, ,T>; -pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) { +// test_err generic_arg_list_recover_expr +// const _: () = T::<0, ,T>; +// const _: () = T::<0, ,T>(); +pub(super) fn opt_generic_arg_list_expr(p: &mut Parser<'_>) { let m; if p.at(T![::]) && p.nth(2) == T![<] { m = p.start(); p.bump(T![::]); - } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] { - m = p.start(); } else { return; } @@ -25,7 +24,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo m.complete(p, GENERIC_ARG_LIST); } -const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ +pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ LIFETIME_IDENT, IDENT, T!['{'], @@ -47,20 +46,23 @@ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); // test generic_arg // type T = S; -fn generic_arg(p: &mut Parser<'_>) -> bool { +pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), T!['{'] | T![true] | T![false] | T![-] => const_arg(p), k if k.is_literal() => const_arg(p), - // test associated_type_bounds - // fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} + // test generic_arg_bounds + // type Plain = Foo; + // type GenericArgs = Foo, Item::, Item: Bound, Item::: Bound, Item = Item, Item:: = Item>; + // type ParenthesizedArgs = Foo; + // type RTN = Foo; // test macro_inside_generic_arg // type A = Foo; - IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => { + IDENT => { let m = p.start(); name_ref(p); - opt_generic_arg_list(p, false); + paths::opt_path_type_args(p); match p.current() { T![=] => { p.bump_any(); @@ -88,45 +90,26 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { } // test assoc_type_bound // type T = StreamingIterator: Clone>; + // type T = StreamingIterator; T![:] if !p.at(T![::]) => { generic_params::bounds(p); m.complete(p, ASSOC_TYPE_ARG); } + // Turned out to be just a normal path type (mirror `path_or_macro_type`) _ => { let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); let m = paths::type_path_for_qualifier(p, m); - m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG); + let m = if p.at(T![!]) && !p.at(T![!=]) { + let m = m.precede(p); + items::macro_call_after_excl(p); + m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_TYPE) + } else { + m.precede(p).complete(p, PATH_TYPE) + }; + types::opt_type_bounds_as_dyn_trait_type(p, m).precede(p).complete(p, TYPE_ARG); } } } - IDENT if p.nth_at(1, T!['(']) => { - let m = p.start(); - name_ref(p); - if p.nth_at(1, T![..]) { - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - // test return_type_syntax_assoc_type_bound - // fn foo>() {} - generic_params::bounds(p); - m.complete(p, ASSOC_TYPE_ARG); - } else { - params::param_list_fn_trait(p); - // test bare_dyn_types_with_paren_as_generic_args - // type A = S; - // type A = S; - // type B = S i32>; - // type C = S i32 + Send>; - opt_ret_type(p); - let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); - let m = paths::type_path_for_qualifier(p, m); - let m = m.precede(p).complete(p, PATH_TYPE); - let m = types::opt_type_bounds_as_dyn_trait_type(p, m); - m.precede(p).complete(p, TYPE_ARG); - } - } _ if p.at_ts(types::TYPE_FIRST) => type_arg(p), _ => return false, } @@ -190,7 +173,7 @@ pub(super) fn const_arg(p: &mut Parser<'_>) { m.complete(p, CONST_ARG); } -fn type_arg(p: &mut Parser<'_>) { +pub(crate) fn type_arg(p: &mut Parser<'_>) { let m = p.start(); types::type_(p); m.complete(p, TYPE_ARG); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs index c535267c1656..51ffcd070694 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs @@ -14,12 +14,6 @@ pub(super) fn param_list_fn_def(p: &mut Parser<'_>) { list_(p, Flavor::FnDef); } -// test param_list_opt_patterns -// fn foo)>(){} -pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) { - list_(p, Flavor::FnTrait); -} - pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { list_(p, Flavor::FnPointer); } @@ -28,10 +22,9 @@ pub(super) fn param_list_closure(p: &mut Parser<'_>) { list_(p, Flavor::Closure); } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Flavor { - FnDef, // Includes trait fn params; omitted param idents are not supported - FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations + FnDef, // Includes trait fn params; omitted param idents are not supported FnPointer, Closure, } @@ -41,7 +34,7 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) { let (bra, ket) = match flavor { Closure => (T![|], T![|]), - FnDef | FnTrait | FnPointer => (T!['('], T![')']), + FnDef | FnPointer => (T!['('], T![')']), }; let list_marker = p.start(); @@ -119,11 +112,6 @@ fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) { } } } - // test value_parameters_no_patterns - // type F = Box; - Flavor::FnTrait => { - types::type_(p); - } // test fn_pointer_param_ident_path // type Foo = fn(Bar::Baz); // type Qux = fn(baz: Bar::Baz); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 15b35296423c..b3652f7cd3f8 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -110,7 +110,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { name_ref(p); - opt_path_type_args(p, mode); + opt_path_args(p, mode); } // test crate_path // use crate::foo; @@ -142,38 +142,74 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option, mode: Mode) { - match mode { - Mode::Use | Mode::Attr | Mode::Vis => {} - Mode::Type => { - // test typepathfn_with_coloncolon - // type F = Start::(Middle) -> (Middle)::End; - // type GenericArg = S; - if p.at(T![::]) && p.nth_at(2, T!['(']) { - p.bump(T![::]); - } - if p.at(T!['(']) { - if p.nth_at(1, T![..]) { - // test return_type_syntax_in_path - // fn foo() - // where - // T::method(..): Send, - // {} - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - } else { - // test path_fn_trait_args - // type F = Box ()>; - params::param_list_fn_trait(p); - opt_ret_type(p); - } - } else { - generic_args::opt_generic_arg_list(p, false); - } - } - Mode::Expr => generic_args::opt_generic_arg_list(p, true), +pub(crate) fn opt_path_type_args(p: &mut Parser<'_>) { + // test typepathfn_with_coloncolon + // type F = Start::(Middle) -> (Middle)::End; + // type GenericArg = S; + let m; + if p.at(T![::]) && matches!(p.nth(2), T![<] | T!['(']) { + m = p.start(); + p.bump(T![::]); + } else if (p.current() == T![<] && p.nth(1) != T![=]) || p.current() == T!['('] { + m = p.start(); + } else { + return; + } + let current = p.current(); + if current == T![<] { + // test_err generic_arg_list_recover + // type T = T<0, ,T>; + // type T = T::<0, ,T>; + delimited( + p, + T![<], + T![>], + T![,], + || "expected generic argument".into(), + generic_args::GENERIC_ARG_FIRST, + generic_args::generic_arg, + ); + m.complete(p, GENERIC_ARG_LIST); + } else if p.nth_at(1, T![..]) { + // test return_type_syntax_in_path + // fn foo() + // where + // T::method(..): Send, + // method(..): Send, + // method::(..): Send, + // {} + p.bump(T!['(']); + p.bump(T![..]); + p.expect(T![')']); + m.complete(p, RETURN_TYPE_SYNTAX); + } else { + // test path_fn_trait_args + // type F = Box ()>; + // type F = Box<::Fn(i32) -> ()>; + // type F = Box ()>; + // type F = Box<::Fn::(i32) -> ()>; + delimited( + p, + T!['('], + T![')'], + T![,], + || "expected type".into(), + types::TYPE_FIRST, + |p| { + let progress = types::TYPE_FIRST.contains(p.current()); + generic_args::type_arg(p); + progress + }, + ); + m.complete(p, PARENTHESIZED_ARG_LIST); + opt_ret_type(p); + } +} + +fn opt_path_args(p: &mut Parser<'_>, mode: Mode) { + match mode { + Mode::Use | Mode::Attr | Mode::Vis => {} + Mode::Type => opt_path_type_args(p), + Mode::Expr => generic_args::opt_generic_arg_list_expr(p), } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index f4e57d3d6f3d..35198ccbe35a 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -50,7 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { // Some path types are not allowed to have bounds (no plus) T![<] => path_type_bounds(p, allow_bounds), T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p), - _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), + _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds), LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), _ => { p.err_recover("expected type", TYPE_RECOVERY_SET); @@ -337,7 +337,7 @@ pub(super) fn path_type(p: &mut Parser<'_>) { // test macro_call_type // type A = foo!(); // type B = crate::foo!(); -fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { +fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); let r = p.start(); let m = p.start(); 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 21730244a339..0c9c6ffd715e 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 @@ -256,6 +256,7 @@ pub enum SyntaxKind { OR_PAT, PARAM, PARAM_LIST, + PARENTHESIZED_ARG_LIST, PAREN_EXPR, PAREN_PAT, PAREN_TYPE, diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 3db8b51a4baf..6d114037bf9b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -39,10 +39,6 @@ mod ok { #[test] fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); } #[test] - fn associated_type_bounds() { - run_and_expect_no_errors("test_data/parser/inline/ok/associated_type_bounds.rs"); - } - #[test] fn async_trait_bound() { run_and_expect_no_errors("test_data/parser/inline/ok/async_trait_bound.rs"); } @@ -59,12 +55,6 @@ mod ok { ); } #[test] - fn bare_dyn_types_with_paren_as_generic_args() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs", - ); - } - #[test] fn become_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/become_expr.rs"); } #[test] fn bind_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/bind_pat.rs"); } @@ -281,6 +271,10 @@ mod ok { #[test] fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); } #[test] + fn generic_arg_bounds() { + run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs"); + } + #[test] fn generic_param_attribute() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs"); } @@ -423,10 +417,6 @@ mod ok { #[test] fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); } #[test] - fn param_list_opt_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/param_list_opt_patterns.rs"); - } - #[test] fn param_list_vararg() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list_vararg.rs"); } @@ -521,12 +511,6 @@ mod ok { #[test] fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); } #[test] - fn return_type_syntax_assoc_type_bound() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs", - ); - } - #[test] fn return_type_syntax_in_path() { run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs"); } @@ -685,10 +669,6 @@ mod ok { #[test] fn use_tree_star() { run_and_expect_no_errors("test_data/parser/inline/ok/use_tree_star.rs"); } #[test] - fn value_parameters_no_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/value_parameters_no_patterns.rs"); - } - #[test] fn variant_discriminant() { run_and_expect_no_errors("test_data/parser/inline/ok/variant_discriminant.rs"); } @@ -754,6 +734,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover.rs"); } #[test] + fn generic_arg_list_recover_expr() { + run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover_expr.rs"); + } + #[test] fn generic_param_list_recover() { run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast index 4cf5a3386b91..16183ce9ef59 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast @@ -30,4 +30,37 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" error 14: expected generic argument +error 35: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs index 7d849aa1bee9..aa65a0673a48 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs @@ -1 +1,2 @@ type T = T<0, ,T>; +type T = T::<0, ,T>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast new file mode 100644 index 000000000000..de403d30494c --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast @@ -0,0 +1,79 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" +error 21: expected generic argument +error 47: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs new file mode 100644 index 000000000000..74cc63ac4a0d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs @@ -0,0 +1,2 @@ +const _: () = T::<0, ,T>; +const _: () = T::<0, ,T>(); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast index f2e4e01069c1..0f62e1dd184c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast @@ -35,3 +35,42 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "StreamingIterator" + GENERIC_ARG_LIST + L_ANGLE "<" + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Clone" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs index daae97e4fd50..83fea1c6c870 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs @@ -1 +1,2 @@ type T = StreamingIterator: Clone>; +type T = StreamingIterator; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast deleted file mode 100644 index 8cbc98c51ca8..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast +++ /dev/null @@ -1,111 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "print_all" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - CONST_ARG - LITERAL - TRUE_KW "true" - R_ANGLE ">" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Display" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "printables" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs deleted file mode 100644 index 0f7a2d160830..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -fn print_all, Item: Display, Item<'a> = Item>>(printables: T) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast index ebf758286a7c..df0ba55d03d6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast @@ -23,9 +23,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast deleted file mode 100644 index d5f97bad898e..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast +++ /dev/null @@ -1,175 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs deleted file mode 100644 index 800002b1b823..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs +++ /dev/null @@ -1,4 +0,0 @@ -type A = S; -type A = S; -type B = S i32>; -type C = S i32 + Send>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast new file mode 100644 index 000000000000..fee5913acaa5 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast @@ -0,0 +1,461 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "Plain" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "GenericArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "ParenthesizedArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "RTN" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs new file mode 100644 index 000000000000..1abd0aeb592f --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs @@ -0,0 +1,4 @@ +type Plain = Foo; +type GenericArgs = Foo, Item::, Item: Bound, Item::: Bound, Item = Item, Item:: = Item>; +type ParenthesizedArgs = Foo; +type RTN = Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast deleted file mode 100644 index e9d93a0d0a4e..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs deleted file mode 100644 index 9b93442c0f21..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo)>(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast index fd83daf841f0..924f7ba2c9db 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast @@ -20,9 +20,133 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs index 17ed20e5b13c..7aa655d7ea9c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs @@ -1 +1,4 @@ type F = Box ()>; +type F = Box<::Fn(i32) -> ()>; +type F = Box ()>; +type F = Box<::Fn::(i32) -> ()>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast deleted file mode 100644 index 30e0e73bbd6c..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "method" - RETURN_TYPE_SYNTAX - L_PAREN "(" - DOT2 ".." - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs deleted file mode 100644 index 8a4cf4c3a07f..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast index 501dccd79db2..15a0558b53d4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast @@ -42,6 +42,49 @@ SOURCE_FILE NAME_REF IDENT "Send" COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + COLON2 "::" + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," WHITESPACE "\n" BLOCK_EXPR STMT_LIST diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs index a9b63fb01c85..64b48c1638e2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs @@ -1,4 +1,6 @@ fn foo() where T::method(..): Send, + method(..): Send, + method::(..): Send, {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast index 67277d0639a8..fb442bfb7390 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast @@ -13,10 +13,10 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - COLON2 "::" - PARAM_LIST + PARENTHESIZED_ARG_LIST + COLON2 "::" L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT @@ -63,9 +63,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast deleted file mode 100644 index 902b06484c81..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs deleted file mode 100644 index 93636e926e16..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -type F = Box; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast index 8407e99f614f..0cc365efbe66 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast index fad574a47695..c22d99f1ae10 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast @@ -180,7 +180,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast index f8b11e7782c9..eafee90db427 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast @@ -138,63 +138,6 @@ SOURCE_FILE WHITESPACE " " R_CURLY "}" WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" TRAIT TRAIT_KW "trait" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs index de350d8587ac..0a0100e5d007 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs @@ -3,8 +3,6 @@ fn g2(#[attr1] x: u8) {} extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } -fn foo)>(){} - trait Foo { fn bar(#[attr] _: u64, # [attr] mut x: i32); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast index 4e1e31f37676..31cca601ca22 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast @@ -58,9 +58,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH @@ -101,9 +101,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast index ba7b6042a9e3..d7ee11077cd4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast @@ -32,7 +32,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast index 136fce93d7ec..cd3b21ae94fd 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME @@ -165,9 +165,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 02c59646a99e..30428329dd96 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -37,7 +37,7 @@ Path = PathSegment = '::'? NameRef | NameRef GenericArgList? -| NameRef ParamList RetType? +| NameRef ParenthesizedArgList RetType? | NameRef ReturnTypeSyntax | '<' Type ('as' PathType)? '>' @@ -49,6 +49,9 @@ ReturnTypeSyntax = // Generics // //*************************// +ParenthesizedArgList = + '::'? '(' (TypeArg (',' TypeArg)* ','?)? ')' + GenericArgList = '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' 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 23d2b355a94f..01dcb646b379 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 @@ -1362,6 +1362,21 @@ impl ParenType { pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParenthesizedArgList { + pub(crate) syntax: SyntaxNode, +} +impl ParenthesizedArgList { + #[inline] + pub fn type_args(&self) -> AstChildren { support::children(&self.syntax) } + #[inline] + pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option { support::token(&self.syntax, T![')']) } + #[inline] + pub fn coloncolon_token(&self) -> Option { support::token(&self.syntax, T![::]) } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub(crate) syntax: SyntaxNode, @@ -1403,7 +1418,9 @@ impl PathSegment { #[inline] pub fn name_ref(&self) -> Option { support::child(&self.syntax) } #[inline] - pub fn param_list(&self) -> Option { support::child(&self.syntax) } + pub fn parenthesized_arg_list(&self) -> Option { + support::child(&self.syntax) + } #[inline] pub fn path_type(&self) -> Option { support::child(&self.syntax) } #[inline] @@ -3760,6 +3777,20 @@ impl AstNode for ParenType { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for ParenthesizedArgList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST } + #[inline] + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for Path { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } @@ -7097,6 +7128,11 @@ impl std::fmt::Display for ParenType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ParenthesizedArgList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Path { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) From 2a949d8725a1027ffe8ef49c1303bc95d6192ce8 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 19 Nov 2024 19:57:07 +0200 Subject: [PATCH 037/197] Store some hir_def Paths in the type ref source maps Most paths are types and therefore already are in the source map, but the trait in impl trait and in bounds are not. We do this by storing them basically as `TypeRef`s. For convenience, I created a wrapper around `TypeRefId` called `PathId` that always stores a path, and implemented indexing from the types map to it. Fortunately, this change impacts memory usage negligibly (adds 2mb to `analysis-stats .`, but that could be just fluff). Probably because there aren't that many trait bounds and impl traits, and this also shrinks `TypeBound` by 8 bytes. I also added an accessor to `TypesSourceMap` to get the source code, which will be needed for diagnostics. --- .../rust-analyzer/crates/hir-def/src/body.rs | 5 +- .../rust-analyzer/crates/hir-def/src/data.rs | 2 +- .../crates/hir-def/src/generics.rs | 24 ++++-- .../crates/hir-def/src/hir/type_ref.rs | 84 ++++++++++++++----- .../crates/hir-def/src/item_tree/lower.rs | 9 +- .../crates/hir-def/src/item_tree/pretty.rs | 2 +- .../rust-analyzer/crates/hir-def/src/lib.rs | 3 + .../rust-analyzer/crates/hir-def/src/lower.rs | 6 +- .../crates/hir-def/src/pretty.rs | 4 +- .../crates/hir-def/src/resolver.rs | 10 ++- .../crates/hir-ty/src/display.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 33 +++++--- .../rust-analyzer/crates/hir-ty/src/tests.rs | 4 +- .../rust-analyzer/crates/hir-ty/src/utils.rs | 2 +- .../crates/hir/src/diagnostics.rs | 2 +- .../rust-analyzer/crates/hir/src/display.rs | 18 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 6 +- .../rust-analyzer/src/cli/analysis_stats.rs | 3 +- 18 files changed, 145 insertions(+), 78 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index d4a1120908f0..908f2050b5fa 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -31,7 +31,7 @@ use crate::{ path::{ModPath, Path}, src::HasSource, type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, - BlockId, DefWithBodyId, HasModule, Lookup, + BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax, }; /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. @@ -160,9 +160,6 @@ pub struct BodySourceMap { diagnostics: Vec, } -#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] -pub struct SyntheticSyntax; - #[derive(Debug, Eq, PartialEq)] pub enum BodyDiagnostic { InactiveCode { node: InFile, cfg: CfgExpr, opts: CfgOptions }, 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 2a13f74aac71..15dd6aba311f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -369,7 +369,7 @@ impl ImplData { let item_tree = tree_id.item_tree(db); let impl_def = &item_tree[tree_id.value]; - let target_trait = impl_def.target_trait.clone(); + let target_trait = impl_def.target_trait; let self_ty = impl_def.self_ty; let is_negative = impl_def.is_negative; let is_unsafe = impl_def.is_unsafe; 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 11e9bb0d886f..fdcb10e9988a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -26,8 +26,8 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, type_ref::{ - ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap, - TypesSourceMap, + ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId, + TypesMap, TypesSourceMap, }, AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, @@ -874,14 +874,20 @@ fn copy_type_bound( to: &mut TypesMap, to_source_map: &mut TypesSourceMap, ) -> TypeBound { - match bound { - TypeBound::Path(path, modifier) => { - TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier) + let mut copy_path_id = |path: PathId| { + let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map); + let new_path_id = to.types.alloc(TypeRef::Path(new_path)); + if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) { + to_source_map.types_map_back.insert(new_path_id, ptr); + } + PathId::from_type_ref_unchecked(new_path_id) + }; + + match bound { + &TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier), + TypeBound::ForLifetime(lifetimes, path) => { + TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path)) } - TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime( - lifetimes.clone(), - copy_path(path, from, from_source_map, to, to_source_map), - ), TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()), TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()), TypeBound::Error => TypeBound::Error, 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 4d83ef99c848..15980ddccaf1 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 @@ -23,6 +23,7 @@ use crate::{ hir::Literal, lower::LowerCtx, path::{GenericArg, Path}, + SyntheticSyntax, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -91,19 +92,37 @@ impl Rawness { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like +/// impl's trait, that are always paths but need to be traced back to source code. +pub struct PathId(TypeRefId); + +impl PathId { + #[inline] + pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self { + Self(type_ref) + } + + #[inline] + pub fn type_ref(self) -> TypeRefId { + self.0 + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct TraitRef { - pub path: Path, + pub path: PathId, } impl TraitRef { /// Converts an `ast::PathType` to a `hir::TraitRef`. pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option { // FIXME: Use `Path::from_src` - match node { - ast::Type::PathType(path) => { - path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) - } + match &node { + ast::Type::PathType(path) => path + .path() + .and_then(|it| ctx.lower_path(it)) + .map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }), _ => None, } } @@ -173,11 +192,24 @@ impl TypesMap { impl Index for TypesMap { type Output = TypeRef; + #[inline] fn index(&self, index: TypeRefId) -> &Self::Output { &self.types[index] } } +impl Index for TypesMap { + type Output = Path; + + #[inline] + fn index(&self, index: PathId) -> &Self::Output { + let TypeRef::Path(path) = &self[index.type_ref()] else { + unreachable!("`PathId` always points to `TypeRef::Path`"); + }; + path + } +} + pub type TypePtr = AstPtr; pub type TypeSource = InFile; @@ -187,6 +219,10 @@ pub struct TypesSourceMap { } impl TypesSourceMap { + pub fn type_syntax(&self, id: TypeRefId) -> Result { + self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax) + } + pub(crate) fn shrink_to_fit(&mut self) { let TypesSourceMap { types_map_back } = self; types_map_back.shrink_to_fit(); @@ -214,15 +250,15 @@ impl LifetimeRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { - Path(Path, TraitBoundModifier), - ForLifetime(Box<[Name]>, Path), + Path(PathId, TraitBoundModifier), + ForLifetime(Box<[Name]>, PathId), Lifetime(LifetimeRef), Use(Box<[UseArgRef]>), Error, } #[cfg(target_pointer_width = "64")] -const _: [(); 32] = [(); ::std::mem::size_of::()]; +const _: [(); 24] = [(); ::std::mem::size_of::()]; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum UseArgRef { @@ -365,8 +401,8 @@ impl TypeRef { TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -397,8 +433,8 @@ impl TypeRef { } for bound in binding.bounds.iter() { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -425,7 +461,7 @@ pub(crate) fn type_bounds_from_ast( impl TypeBound { pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self { - let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?); + let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?); match node.kind() { ast::TypeBoundKind::PathType(path_type) => { @@ -433,8 +469,10 @@ impl TypeBound { Some(_) => TraitBoundModifier::Maybe, None => TraitBoundModifier::None, }; - lower_path_type(path_type) - .map(|p| TypeBound::Path(p, m)) + lower_path_type(&path_type) + .map(|p| { + TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m) + }) .unwrap_or(TypeBound::Error) } ast::TypeBoundKind::ForType(for_type) => { @@ -445,12 +483,14 @@ impl TypeBound { .collect(), None => Box::default(), }; - let path = for_type.ty().and_then(|ty| match ty { - ast::Type::PathType(path_type) => lower_path_type(path_type), + let path = for_type.ty().and_then(|ty| match &ty { + ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)), _ => None, }); match path { - Some(p) => TypeBound::ForLifetime(lt_refs, p), + Some((p, ty)) => { + TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty))) + } None => TypeBound::Error, } } @@ -470,10 +510,10 @@ impl TypeBound { } } - pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> { + pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> { match self { - TypeBound::Path(p, m) => Some((p, m)), - TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), + &TypeBound::Path(p, m) => Some((&map[p], m)), + &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index d519c1708b3d..71848845a84d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -34,7 +34,7 @@ use crate::{ lower::LowerCtx, path::AssociatedTypeBinding, type_ref::{ - LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, + LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, visibility::RawVisibility, @@ -514,7 +514,7 @@ impl<'a> Ctx<'a> { }; let ret_type = if func.async_token().is_some() { - let future_impl = desugar_future_path(ret_type); + let future_impl = desugar_future_path(&mut body_ctx, ret_type); let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None); body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))) } else { @@ -936,7 +936,7 @@ impl<'a> Ctx<'a> { } } -fn desugar_future_path(orig: TypeRefId) -> Path { +fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId { let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); @@ -948,7 +948,8 @@ fn desugar_future_path(orig: TypeRefId) -> Path { }; generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() })); - Path::from_known_path(path, generic_args) + let path = Path::from_known_path(path, generic_args); + PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path))) } enum HasImplicitSelf { 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 b6816a1f9684..0c5e3a3620a4 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 @@ -484,7 +484,7 @@ impl Printer<'_> { w!(self, "!"); } if let Some(tr) = target_trait { - self.print_path(&tr.path, types_map); + self.print_path(&types_map[tr.path], types_map); w!(self, " for "); } self.print_type_ref(*self_ty, types_map); 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 eb55ba1d53d3..8af27513ebc0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1535,3 +1535,6 @@ fn macro_call_as_call_id_with_eager( pub struct UnresolvedMacro { pub path: hir_expand::mod_path::ModPath, } + +#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] +pub struct SyntheticSyntax; 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 350bb8d51724..7cddd48eb174 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -10,7 +10,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, path::Path, - type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, + type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, }; pub struct LowerCtx<'a> { @@ -142,4 +142,8 @@ impl<'a> LowerCtx<'a> { pub(crate) fn alloc_error_type(&mut self) -> TypeRefId { self.types_map.types.alloc(TypeRef::Error) } + + pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId { + PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node)) + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index 9ceb82d5fd6b..eb9488feaa91 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -271,7 +271,7 @@ pub(crate) fn print_type_bounds( TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::ForLifetime(lifetimes, path) => { write!( @@ -279,7 +279,7 @@ pub(crate) fn print_type_bounds( "for<{}> ", lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ") )?; - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?, TypeBound::Use(args) => { 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 26655e40ca79..0ca7070fd05f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -576,10 +576,12 @@ impl Resolver { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::ImplDefScope(impl_) => { - if let Some(target_trait) = &db.impl_data(impl_).target_trait { - if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, &target_trait.path) - { + let impl_data = db.impl_data(impl_); + if let Some(target_trait) = impl_data.target_trait { + if let Some(TypeNs::TraitId(trait_)) = self.resolve_path_in_type_ns_fully( + db, + &impl_data.types_map[target_trait.path], + ) { traits.insert(trait_); } } 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 4e95bdf219fa..94a340fbec2c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -2062,12 +2062,12 @@ impl HirDisplayWithTypesMap for TypeBound { types_map: &TypesMap, ) -> Result<(), HirDisplayError> { match self { - TypeBound::Path(path, modifier) => { + &TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(f, "?")?, } - path.hir_fmt(f, types_map) + types_map[path].hir_fmt(f, types_map) } TypeBound::Lifetime(lifetime) => { write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) @@ -2079,7 +2079,7 @@ impl HirDisplayWithTypesMap for TypeBound { "for<{}> ", lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") )?; - path.hir_fmt(f, types_map) + types_map[*path].hir_fmt(f, types_map) } TypeBound::Use(args) => { let edition = f.edition(); 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 b868ea95f85a..fc0af0cec904 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -33,8 +33,8 @@ use hir_def::{ path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, type_ref::{ - ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, - TypeRefId, TypesMap, TypesSourceMap, + ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, @@ -264,7 +264,8 @@ impl<'a> TyLoweringContext<'a> { .intern(Interner) } TypeRef::Path(path) => { - let (ty, res_) = self.lower_path(path); + let (ty, res_) = + self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id)); res = res_; ty } @@ -677,7 +678,7 @@ impl<'a> TyLoweringContext<'a> { self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) } - pub(crate) fn lower_path(&mut self, path: &Path) -> (Ty, Option) { + pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option) { // Resolve the path (in type namespace) if let Some(type_ref) = path.type_anchor() { let (ty, res) = self.lower_ty_ext(type_ref); @@ -692,7 +693,7 @@ impl<'a> TyLoweringContext<'a> { if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { // trait object type without dyn - let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); + let bound = TypeBound::Path(path_id, TraitBoundModifier::None); let ty = self.lower_dyn_trait(&[bound]); return (ty, None); } @@ -998,7 +999,12 @@ impl<'a> TyLoweringContext<'a> { TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } } - fn lower_trait_ref_from_path(&mut self, path: &Path, explicit_self_ty: Ty) -> Option { + fn lower_trait_ref_from_path( + &mut self, + path_id: PathId, + explicit_self_ty: Ty, + ) -> Option { + let path = &self.types_map[path_id]; let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { // FIXME(trait_alias): We need to handle trait alias here. TypeNs::TraitId(tr) => tr, @@ -1013,7 +1019,7 @@ impl<'a> TyLoweringContext<'a> { trait_ref: &HirTraitRef, explicit_self_ty: Ty, ) -> Option { - self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) + self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty) } fn trait_ref_substs_from_path( @@ -1072,11 +1078,11 @@ impl<'a> TyLoweringContext<'a> { ) -> impl Iterator + use<'b, 'a> { let mut trait_ref = None; let clause = match bound { - TypeBound::Path(path, TraitBoundModifier::None) => { + &TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } - TypeBound::Path(path, TraitBoundModifier::Maybe) => { + &TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self .db .lang_item(self.resolver.krate(), LangItem::Sized) @@ -1092,7 +1098,7 @@ impl<'a> TyLoweringContext<'a> { } None } - TypeBound::ForLifetime(_, path) => { + &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) @@ -1121,8 +1127,8 @@ impl<'a> TyLoweringContext<'a> { trait_ref: TraitRef, ) -> impl Iterator + use<'b, 'a> { let last_segment = match bound { - TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { - path.segments().last() + &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + self.types_map[path].segments().last() } TypeBound::Path(_, TraitBoundModifier::Maybe) | TypeBound::Use(_) @@ -1593,9 +1599,10 @@ pub(crate) fn generic_predicates_for_param_query( } match bound { - TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { + &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { // Only lower the bound if the trait could possibly define the associated // type we're looking for. + let path = &ctx.types_map[path]; let Some(assoc_name) = &assoc_name else { return true }; let Some(TypeNs::TraitId(tr)) = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index bcf9d5ceff0e..cabeeea2bd86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -18,13 +18,13 @@ use std::sync::LazyLock; use base_db::SourceDatabaseFileInputExt as _; use expect_test::Expect; use hir_def::{ - body::{Body, BodySourceMap, SyntheticSyntax}, + body::{Body, BodySourceMap}, db::DefDatabase, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, src::HasSource, - AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, + AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax, }; use hir_expand::{db::ExpandDatabase, FileRange, InFile}; use itertools::Itertools; 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 28bda1e10e58..06719b09f735 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -185,7 +185,7 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut( } }; match is_trait { - true => bound.as_path(), + true => bound.as_path(&generic_params.types_map), false => None, } } diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 9ca021027d54..9df6ca58f56f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -13,7 +13,7 @@ use hir_ty::{ use cfg::{CfgExpr, CfgOptions}; use either::Either; pub use hir_def::VariantId; -use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; +use hir_def::{hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId, SyntheticSyntax}; use hir_expand::{name::Name, HirFileId, InFile}; use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use triomphe::Arc; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 9275f45d881b..959d62d59519 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -132,12 +132,18 @@ impl HirDisplay for Function { } else { match &data.types_map[data.ret_type] { TypeRef::ImplTrait(bounds) => match &bounds[0] { - TypeBound::Path(path, _) => Some( - *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings - [0] - .type_ref - .as_ref() - .unwrap(), + &TypeBound::Path(path, _) => Some( + *data.types_map[path] + .segments() + .iter() + .last() + .unwrap() + .args_and_bindings + .unwrap() + .bindings[0] + .type_ref + .as_ref() + .unwrap(), ), _ => None, }, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 0b2ba56b1ff1..dc1d1efe60c7 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -43,7 +43,7 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin}; use either::Either; use hir_def::{ - body::{BodyDiagnostic, SyntheticSyntax}, + body::BodyDiagnostic, data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, @@ -57,8 +57,8 @@ use hir_def::{ 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, + MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, 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 802d0c69a47a..e3ea441f3abd 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 @@ -13,8 +13,9 @@ use hir::{ ModuleDef, Name, }; use hir_def::{ - body::{BodySourceMap, SyntheticSyntax}, + body::BodySourceMap, hir::{ExprId, PatId}, + SyntheticSyntax, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use ide::{ From 63acf60253262e31d8129c9134b9b4a5aab75453 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 20 Nov 2024 23:05:48 +0200 Subject: [PATCH 038/197] Lay the foundation for diagnostics in ty lowering, and implement a first diagnostic The diagnostic implemented is a simple one (E0109). It serves as a test for the new foundation. This commit only implements diagnostics for type in bodies and body-carrying signatures; the next commit will include diagnostics in the rest of the things. Also fix one weird bug that was detected when implementing this that caused `Fn::(A, B) -> C` (which is a valid, if bizarre, alternative syntax to `Fn(A, B) -> C` to lower incorrectly. And also fix a maybe-bug where parentheses were sneaked into a code string needlessly; this was not detected until now because the parentheses were removed (by the make-AST family API), but with a change in this commit they are now inserted. So fix that too. --- src/tools/rust-analyzer/Cargo.lock | 4 + .../rust-analyzer/crates/hir-def/src/body.rs | 2 +- .../crates/hir-def/src/hir/type_ref.rs | 2 + .../rust-analyzer/crates/hir-def/src/path.rs | 12 +- .../crates/hir-def/src/path/lower.rs | 80 +++++- .../crates/hir-def/src/path/tests.rs | 126 +++++++++ .../crates/hir-expand/src/files.rs | 7 + .../rust-analyzer/crates/hir-ty/src/infer.rs | 96 +++++-- .../crates/hir-ty/src/infer/expr.rs | 2 +- .../crates/hir-ty/src/infer/path.rs | 6 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 7 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 187 +++++++++++--- src/tools/rust-analyzer/crates/hir/Cargo.toml | 8 + .../crates/hir/src/diagnostics.rs | 67 ++++- src/tools/rust-analyzer/crates/hir/src/lib.rs | 33 ++- .../src/handlers/generic_args_prohibited.rs | 242 ++++++++++++++++++ .../src/handlers/unresolved_method.rs | 6 +- .../crates/ide-diagnostics/src/lib.rs | 2 + .../crates/syntax/src/ast/make.rs | 2 +- 19 files changed, 811 insertions(+), 80 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2bd4d17fe222..5861833d53a2 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -509,6 +509,7 @@ dependencies = [ "base-db", "cfg", "either", + "expect-test", "hir-def", "hir-expand", "hir-ty", @@ -519,6 +520,9 @@ dependencies = [ "span", "stdx", "syntax", + "syntax-bridge", + "test-fixture", + "test-utils", "tracing", "triomphe", "tt", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 908f2050b5fa..867bee95bed6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -141,7 +141,7 @@ pub struct BodySourceMap { field_map_back: FxHashMap, pat_field_map_back: FxHashMap, - types: TypesSourceMap, + pub types: TypesSourceMap, // FIXME: Make this a sane struct. template_map: Option< 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 15980ddccaf1..6d4d519cd2b7 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 @@ -219,6 +219,8 @@ pub struct TypesSourceMap { } impl TypesSourceMap { + pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() }; + pub fn type_syntax(&self, id: TypeRefId) -> Result { self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index aa2c4a6f1bc3..44e132061ad4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -1,5 +1,7 @@ //! A desugared representation of paths like `crate::foo` or `::bar`. mod lower; +#[cfg(test)] +mod tests; use std::{ fmt::{self, Display}, @@ -19,6 +21,8 @@ use syntax::ast; pub use hir_expand::mod_path::{path, ModPath, PathKind}; +pub use lower::hir_segment_to_ast_segment; + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportAlias { /// Unnamed alias, as in `use Foo as _;` @@ -230,7 +234,7 @@ impl Path { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PathSegment<'a> { pub name: &'a Name, pub args_and_bindings: Option<&'a GenericArgs>, @@ -274,6 +278,12 @@ impl<'a> PathSegments<'a> { generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)), } } + pub fn strip_last(&self) -> PathSegments<'a> { + PathSegments { + segments: self.segments.split_last().map_or(&[], |it| it.1), + generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)), + } + } pub fn iter(&self) -> impl Iterator> { self.segments .iter() 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 37c94a5f1188..3b7e7653fba5 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 @@ -17,13 +17,31 @@ use crate::{ type_ref::{LifetimeRef, TypeBound, TypeRef}, }; +#[cfg(test)] +thread_local! { + /// This is used to test `hir_segment_to_ast_segment()`. It's a hack, but it makes testing much easier. + pub(super) static SEGMENT_LOWERING_MAP: std::cell::RefCell> = std::cell::RefCell::default(); +} + /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. +// If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()` +// also needs an update. pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option { let mut kind = PathKind::Plain; let mut type_anchor = None; let mut segments = Vec::new(); let mut generic_args = Vec::new(); + #[cfg(test)] + let mut ast_segments = Vec::new(); + #[cfg(test)] + let mut ast_segments_offset = 0; + #[allow(unused_mut)] + let mut push_segment = |_segment: &ast::PathSegment, segments: &mut Vec, name| { + #[cfg(test)] + ast_segments.push(_segment.clone()); + segments.push(name); + }; loop { let segment = path.segment()?; @@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { if name_ref.text() == "$crate" { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } break kind = resolve_crate_root( ctx.db.upcast(), ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx, @@ -56,10 +78,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< generic_args.resize(segments.len(), None); generic_args.push(args); } - segments.push(name); + push_segment(&segment, &mut segments, name); } ast::PathSegmentKind::SelfTypeKw => { - segments.push(Name::new_symbol_root(sym::Self_.clone())); + push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_.clone())); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -81,6 +103,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< kind = mod_path.kind; segments.extend(mod_path.segments().iter().cloned().rev()); + #[cfg(test)] + { + ast_segments_offset = mod_path.segments().len(); + } if let Some(path_generic_args) = path_generic_args { generic_args.resize(segments.len() - num_segments, None); generic_args.extend(Vec::from(path_generic_args).into_iter().rev()); @@ -112,10 +138,18 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } ast::PathSegmentKind::CrateKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } kind = PathKind::Crate; break; } ast::PathSegmentKind::SelfKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } // don't break out if `self` is the last segment of a path, this mean we got a // use tree like `foo::{self}` which we want to resolve as `foo` if !segments.is_empty() { @@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } + #[cfg(test)] + { + ast_segments.reverse(); + SEGMENT_LOWERING_MAP + .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..))); + } + let mod_path = Interned::new(ModPath::from_segments(kind, segments)); if type_anchor.is_none() && generic_args.is_empty() { return Some(Path::BarePath(mod_path)); @@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } +/// This function finds the AST segment that corresponds to the HIR segment +/// with index `segment_idx` on the path that is lowered from `path`. +pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option { + // Too tightly coupled to `lower_path()`, but unfortunately we cannot decouple them, + // as keeping source maps for all paths segments will have a severe impact on memory usage. + + let mut segments = path.segments(); + if let Some(ast::PathSegmentKind::Type { trait_ref: Some(trait_ref), .. }) = + segments.clone().next().and_then(|it| it.kind()) + { + segments.next(); + return find_segment(trait_ref.path()?.segments().chain(segments), segment_idx); + } + return find_segment(segments, segment_idx); + + fn find_segment( + segments: impl Iterator, + segment_idx: u32, + ) -> Option { + segments + .filter(|segment| match segment.kind() { + Some( + ast::PathSegmentKind::CrateKw + | ast::PathSegmentKind::SelfKw + | ast::PathSegmentKind::SuperKw + | ast::PathSegmentKind::Type { .. }, + ) + | None => false, + Some(ast::PathSegmentKind::Name(name)) => name.text() != "$crate", + Some(ast::PathSegmentKind::SelfTypeKw) => true, + }) + .nth(segment_idx as usize) + } +} + pub(super) fn lower_generic_args( lower_ctx: &mut LowerCtx<'_>, node: ast::GenericArgList, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs new file mode 100644 index 000000000000..67a27bf85e89 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs @@ -0,0 +1,126 @@ +use expect_test::{expect, Expect}; +use span::Edition; +use syntax::ast::{self, make}; +use test_fixture::WithFixture; + +use crate::{ + lower::LowerCtx, + path::{ + lower::{hir_segment_to_ast_segment, SEGMENT_LOWERING_MAP}, + Path, + }, + pretty, + test_db::TestDB, + type_ref::{TypesMap, TypesSourceMap}, +}; + +fn lower_path(path: ast::Path) -> (TestDB, TypesMap, Option) { + let (db, file_id) = TestDB::with_single_file(""); + let mut types_map = TypesMap::default(); + let mut types_source_map = TypesSourceMap::default(); + let mut ctx = LowerCtx::new(&db, file_id.into(), &mut types_map, &mut types_source_map); + let lowered_path = ctx.lower_path(path); + (db, types_map, lowered_path) +} + +#[track_caller] +fn check_hir_to_ast(path: &str, ignore_segments: &[&str]) { + let path = make::path_from_text(path); + SEGMENT_LOWERING_MAP.with_borrow_mut(|map| map.clear()); + let _ = lower_path(path.clone()).2.expect("failed to lower path"); + SEGMENT_LOWERING_MAP.with_borrow(|map| { + for (segment, segment_idx) in map { + if ignore_segments.contains(&&*segment.to_string()) { + continue; + } + + let restored_segment = hir_segment_to_ast_segment(&path, *segment_idx as u32) + .unwrap_or_else(|| { + panic!( + "failed to map back segment `{segment}` \ + numbered {segment_idx} in HIR from path `{path}`" + ) + }); + assert_eq!( + segment, &restored_segment, + "mapping back `{segment}` numbered {segment_idx} in HIR \ + from path `{path}` produced incorrect segment `{restored_segment}`" + ); + } + }); +} + +#[test] +fn hir_to_ast_trait_ref() { + check_hir_to_ast("::E::F", &["A"]); +} + +#[test] +fn hir_to_ast_plain_path() { + check_hir_to_ast("A::B::C::D::E::F", &[]); +} + +#[test] +fn hir_to_ast_crate_path() { + check_hir_to_ast("crate::A::B::C", &[]); + check_hir_to_ast("crate::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_self_path() { + check_hir_to_ast("self::A::B::C", &[]); + check_hir_to_ast("self::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_super_path() { + check_hir_to_ast("super::A::B::C", &[]); + check_hir_to_ast("super::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_type_anchor_path() { + check_hir_to_ast("::C::D", &["A", "B"]); +} + +#[test] +fn hir_to_ast_path_super_in_middle() { + check_hir_to_ast("A::super::B::super::super::C::D", &[]); +} + +#[track_caller] +fn check_fail_lowering(path: &str) { + let (_, _, lowered_path) = lower_path(make::path_from_text(path)); + assert!(lowered_path.is_none(), "path `{path}` should fail lowering"); +} + +#[test] +fn keywords_in_middle_fail_lowering1() { + check_fail_lowering("self::A::self::B::super::C::crate::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering2() { + check_fail_lowering("A::super::self::C::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering3() { + check_fail_lowering("A::crate::B::C::D"); +} + +#[track_caller] +fn check_path_lowering(path: &str, expected: Expect) { + let (db, types_map, lowered_path) = lower_path(make::path_from_text(path)); + let lowered_path = lowered_path.expect("failed to lower path"); + let mut buf = String::new(); + pretty::print_path(&db, &lowered_path, &types_map, &mut buf, Edition::CURRENT) + .expect("failed to pretty-print path"); + expected.assert_eq(&buf); +} + +#[test] +fn fn_like_path_with_coloncolon() { + check_path_lowering("Fn::(A, B) -> C", expect![[r#"Fn::<(A, B), Output = C>"#]]); + check_path_lowering("Fn::(A, B)", expect![[r#"Fn::<(A, B), Output = ()>"#]]); +} 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 d41f69812ee6..8c04d054029c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -180,6 +180,13 @@ impl InFileWrapper { } } +#[allow(private_bounds)] +impl InFileWrapper> { + pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { + self.value.to_node(&self.file_syntax(db)) + } +} + impl InFileWrapper { pub fn syntax(&self) -> InFileWrapper { self.with_value(self.value.syntax()) 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 01e0b635b223..dbee5a1a919f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -58,7 +58,7 @@ use crate::{ fold_tys, generics::Generics, infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable}, - lower::ImplTraitLoweringMode, + lower::{ImplTraitLoweringMode, TyLoweringDiagnostic}, mir::MirSpan, to_assoc_type_id, traits::FnTrait, @@ -191,6 +191,14 @@ impl InferOk { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum InferenceTyDiagnosticSource { + /// Diagnostics that come from types in the body. + Body, + /// Diagnostics that come from types in fn parameters/return type, or static & const types. + Signature, +} + #[derive(Debug)] pub(crate) struct TypeError; pub(crate) type InferResult = Result, TypeError>; @@ -264,6 +272,10 @@ pub enum InferenceDiagnostic { expr_ty: Ty, cast_ty: Ty, }, + TyDiagnostic { + source: InferenceTyDiagnosticSource, + diag: TyLoweringDiagnostic, + }, } /// A mismatch between an expected and an inferred type. @@ -858,7 +870,8 @@ impl<'a> InferenceContext<'a> { } fn collect_const(&mut self, data: &ConstData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Constants might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -867,7 +880,8 @@ impl<'a> InferenceContext<'a> { } fn collect_static(&mut self, data: &StaticData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Statics might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -877,11 +891,12 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Param); - data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>() - }); + let mut param_tys = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Param); + data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::>() + }); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { @@ -918,11 +933,12 @@ impl<'a> InferenceContext<'a> { } let return_ty = data.ret_type; - let return_ty = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Opaque) - .lower_ty(return_ty) - }); + let return_ty = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Opaque) + .lower_ty(return_ty) + }); let return_ty = self.insert_type_vars(return_ty); let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { @@ -1226,9 +1242,20 @@ impl<'a> InferenceContext<'a> { self.result.diagnostics.push(diagnostic); } + fn push_ty_diagnostics( + &mut self, + source: InferenceTyDiagnosticSource, + diagnostics: Vec, + ) { + self.result.diagnostics.extend( + diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }), + ); + } + fn with_ty_lowering( - &self, + &mut self, types_map: &TypesMap, + types_source: InferenceTyDiagnosticSource, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { let mut ctx = crate::lower::TyLoweringContext::new( @@ -1237,32 +1264,41 @@ impl<'a> InferenceContext<'a> { types_map, self.owner.into(), ); - f(&mut ctx) + let result = f(&mut ctx); + self.push_ty_diagnostics(types_source, ctx.diagnostics); + result } fn with_body_ty_lowering( - &self, + &mut self, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { - self.with_ty_lowering(&self.body.types, f) + self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f) } - fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty { - let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref)); + fn make_ty( + &mut self, + type_ref: TypeRefId, + types_map: &TypesMap, + type_source: InferenceTyDiagnosticSource, + ) -> Ty { + let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref)); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { - self.make_ty(type_ref, &self.body.types) + self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body) } fn err_ty(&self) -> Ty { self.result.standard_types.unknown.clone() } - fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { - let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref)); + fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { + let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| { + ctx.lower_lifetime(lifetime_ref) + }); self.insert_type_vars(lt) } @@ -1431,12 +1467,20 @@ impl<'a> InferenceContext<'a> { Some(ResolveValueResult::ValueNs(value, _)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(strukt.into())); @@ -1462,18 +1506,21 @@ impl<'a> InferenceContext<'a> { return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } TypeNs::AdtId(AdtId::UnionId(u)) => { let substs = ctx.substs_from_path(path, u.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(u.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(var.into())), unresolved) @@ -1519,6 +1566,9 @@ impl<'a> InferenceContext<'a> { resolved_segment, current_segment, false, + &mut |_, _reason| { + // FIXME: Report an error. + }, ); ty = self.table.insert_type_vars(ty); @@ -1532,6 +1582,7 @@ impl<'a> InferenceContext<'a> { remaining_idx += 1; remaining_segments = remaining_segments.skip(1); } + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let variant = ty.as_adt().and_then(|(id, _)| match id { AdtId::StructId(s) => Some(VariantId::StructId(s)), @@ -1550,6 +1601,7 @@ impl<'a> InferenceContext<'a> { }; let substs = ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(it.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); 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 32b4ea2f28ba..e060b37f1545 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 @@ -2155,7 +2155,7 @@ impl InferenceContext<'_> { DebruijnIndex::INNERMOST, ) }, - |this, lt_ref| this.make_lifetime(lt_ref), + |this, lt_ref| this.make_body_lifetime(lt_ref), ), }; 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 7550d197a3bb..a6296c3af233 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 @@ -19,7 +19,7 @@ use crate::{ TyBuilder, TyExt, TyKind, ValueTyDefId, }; -use super::{ExprOrPatId, InferenceContext}; +use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; impl InferenceContext<'_> { pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option { @@ -163,6 +163,7 @@ impl InferenceContext<'_> { let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? @@ -265,6 +266,9 @@ impl InferenceContext<'_> { resolved_segment, remaining_segments_for_ty, true, + &mut |_, _reason| { + // FIXME: Report an error. + }, ) }); if ty.is_unknown() { 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 fdc657976320..77ae295cee41 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -84,12 +84,13 @@ pub use infer::{ cast::CastError, closure::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode, - InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, + InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, + PointerCast, }; pub use interner::Interner; pub use lower::{ - associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId, - TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, + ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, 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 fc0af0cec904..b73967be7100 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -102,6 +102,31 @@ impl ImplTraitLoweringState { } } +type TypeSource = Either; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TyLoweringDiagnostic { + pub source: TypeSource, + pub kind: TyLoweringDiagnosticKind, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TyLoweringDiagnosticKind { + GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GenericArgsProhibitedReason { + Module, + TyParam, + SelfTy, + PrimitiveTy, + /// When there is a generic enum, within the expression `Enum::Variant`, + /// either `Enum` or `Variant` are allowed to have generic arguments, but not both. + // FIXME: This is not used now but it should be. + EnumVariant, +} + #[derive(Debug)] pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, @@ -125,6 +150,7 @@ pub struct TyLoweringContext<'a> { expander: Option, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet, + pub(crate) diagnostics: Vec, } impl<'a> TyLoweringContext<'a> { @@ -159,6 +185,7 @@ impl<'a> TyLoweringContext<'a> { type_param_mode, expander: None, unsized_types: FxHashSet::default(), + diagnostics: Vec::new(), } } @@ -198,6 +225,20 @@ impl<'a> TyLoweringContext<'a> { self.type_param_mode = type_param_mode; self } + + pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { + let source = match self.types_source_map { + Some(source_map) => { + let Ok(source) = source_map.type_syntax(type_ref) else { + stdx::never!("error in synthetic type"); + return; + }; + Either::Right(source) + } + None => Either::Left(type_ref), + }; + self.diagnostics.push(TyLoweringDiagnostic { source, kind }); + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] @@ -464,6 +505,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode: mem::take(&mut self.impl_trait_mode), expander: self.expander.take(), unsized_types: mem::take(&mut self.unsized_types), + diagnostics: mem::take(&mut self.diagnostics), }; let ty = inner_ctx.lower_ty(type_ref); @@ -471,6 +513,7 @@ impl<'a> TyLoweringContext<'a> { self.impl_trait_mode = inner_ctx.impl_trait_mode; self.expander = inner_ctx.expander; self.unsized_types = inner_ctx.unsized_types; + self.diagnostics = inner_ctx.diagnostics; self.expander.as_mut().unwrap().exit(mark); Some(ty) @@ -542,6 +585,10 @@ impl<'a> TyLoweringContext<'a> { resolved_segment: PathSegment<'_>, remaining_segments: PathSegments<'_>, infer_args: bool, + on_prohibited_generics_for_resolved_segment: &mut dyn FnMut( + &mut Self, + GenericArgsProhibitedReason, + ), ) -> (Ty, Option) { let ty = match resolution { TypeNs::TraitId(trait_) => { @@ -608,28 +655,44 @@ impl<'a> TyLoweringContext<'a> { // FIXME(trait_alias): Implement trait alias. return (TyKind::Error.intern(Interner), None); } - TypeNs::GenericParam(param_id) => match self.type_param_mode { - ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + TypeNs::GenericParam(param_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::TyParam, + ); } - ParamLoweringMode::Variable => { - let idx = match self - .generics() - .expect("generics in scope") - .type_or_const_param_idx(param_id.into()) - { - None => { - never!("no matching generics"); - return (TyKind::Error.intern(Interner), None); - } - Some(idx) => idx, - }; - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + match self.type_param_mode { + ParamLoweringMode::Placeholder => { + TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + } + ParamLoweringMode::Variable => { + let idx = match self + .generics() + .expect("generics in scope") + .type_or_const_param_idx(param_id.into()) + { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; + + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + } } + .intern(Interner) } - .intern(Interner), TypeNs::SelfType(impl_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = self.generics().expect("impl should have generic param scope"); match self.type_param_mode { @@ -655,6 +718,13 @@ impl<'a> TyLoweringContext<'a> { } } TypeNs::AdtSelfType(adt) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = generics(self.db.upcast(), adt.into()); let substs = match self.type_param_mode { ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db), @@ -667,6 +737,12 @@ impl<'a> TyLoweringContext<'a> { TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), TypeNs::BuiltinType(it) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::PrimitiveTy, + ); + } self.lower_path_inner(resolved_segment, it.into(), infer_args) } TypeNs::TypeAliasId(it) => { @@ -698,14 +774,39 @@ impl<'a> TyLoweringContext<'a> { return (ty, None); } - let (resolved_segment, remaining_segments) = match remaining_index { - None => ( - path.segments().last().expect("resolved path has at least one element"), - PathSegments::EMPTY, - ), - Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), - }; - self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false) + let (module_segments, resolved_segment_idx, resolved_segment, remaining_segments) = + match remaining_index { + None => ( + path.segments().strip_last(), + path.segments().len() - 1, + path.segments().last().expect("resolved path has at least one element"), + PathSegments::EMPTY, + ), + Some(i) => ( + path.segments().take(i - 1), + i - 1, + path.segments().get(i - 1).unwrap(), + path.segments().skip(i), + ), + }; + + self.prohibit_generics(path_id, 0, module_segments, GenericArgsProhibitedReason::Module); + + self.lower_partly_resolved_path( + resolution, + resolved_segment, + remaining_segments, + false, + &mut |this, reason| { + this.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { + segment: resolved_segment_idx as u32, + reason, + }, + ) + }, + ) } fn select_associated_type(&mut self, res: Option, segment: PathSegment<'_>) -> Ty { @@ -742,12 +843,8 @@ impl<'a> TyLoweringContext<'a> { // generic params. It's inefficient to splice the `Substitution`s, so we may want // that method to optionally take parent `Substitution` as we already know them at // this point (`t.substitution`). - let substs = self.substs_from_path_segment( - segment.clone(), - Some(associated_ty.into()), - false, - None, - ); + let substs = + self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None); let len_self = crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); @@ -999,6 +1096,23 @@ impl<'a> TyLoweringContext<'a> { TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } } + fn prohibit_generics( + &mut self, + path_id: PathId, + idx: u32, + segments: PathSegments<'_>, + reason: GenericArgsProhibitedReason, + ) { + segments.iter().zip(idx..).for_each(|(segment, idx)| { + if segment.args_and_bindings.is_some() { + self.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason }, + ); + } + }); + } + fn lower_trait_ref_from_path( &mut self, path_id: PathId, @@ -1010,6 +1124,13 @@ impl<'a> TyLoweringContext<'a> { TypeNs::TraitId(tr) => tr, _ => return None, }; + // Do this after we verify it's indeed a trait to not confuse the user if they're not modules. + self.prohibit_generics( + path_id, + 0, + path.segments().strip_last(), + GenericArgsProhibitedReason::Module, + ); let segment = path.segments().last().expect("path should have at least one segment"); Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } @@ -1233,7 +1354,9 @@ impl<'a> TyLoweringContext<'a> { } _ => unreachable!(), } - ext.lower_ty(type_ref) + let ty = ext.lower_ty(type_ref); + self.diagnostics.extend(ext.diagnostics); + ty } else { self.lower_ty(type_ref) }; diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 26666d6feb08..6aadc5c4f7e7 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -33,6 +33,14 @@ syntax.workspace = true tt.workspace = true span.workspace = true +[dev-dependencies] +expect-test.workspace = true + +# local deps +test-utils.workspace = true +test-fixture.workspace = true +syntax-bridge.workspace = true + [features] in-rust-tree = ["hir-expand/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 9df6ca58f56f..3657cf5e162c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -3,23 +3,34 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. -pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; +use cfg::{CfgExpr, CfgOptions}; +use either::Either; +use hir_def::{ + hir::ExprOrPatId, + path::{hir_segment_to_ast_segment, ModPath}, + type_ref::TypesSourceMap, + AssocItemId, DefWithBodyId, SyntheticSyntax, +}; +use hir_expand::{name::Name, HirFileId, InFile}; use hir_ty::{ db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, - CastError, InferenceDiagnostic, + CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind, +}; +use syntax::{ + ast::{self, HasGenericArgs}, + AstPtr, SyntaxError, SyntaxNodePtr, TextRange, }; - -use cfg::{CfgExpr, CfgOptions}; -use either::Either; -pub use hir_def::VariantId; -use hir_def::{hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId, SyntheticSyntax}; -use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{AssocItem, Field, Local, Trait, Type}; +pub use hir_def::VariantId; +pub use hir_ty::{ + diagnostics::{CaseType, IncorrectCase}, + GenericArgsProhibitedReason, +}; + macro_rules! diagnostics { ($($diag:ident,)*) => { #[derive(Debug)] @@ -98,6 +109,7 @@ diagnostics![ UnresolvedIdent, UnusedMut, UnusedVariable, + GenericArgsProhibited, ]; #[derive(Debug)] @@ -388,6 +400,12 @@ pub struct InvalidCast { pub cast_ty: Type, } +#[derive(Debug)] +pub struct GenericArgsProhibited { + pub args: InFile>>, + pub reason: GenericArgsProhibitedReason, +} + impl AnyDiagnostic { pub(crate) fn body_validation_diagnostic( db: &dyn HirDatabase, @@ -527,6 +545,7 @@ impl AnyDiagnostic { db: &dyn HirDatabase, def: DefWithBodyId, d: &InferenceDiagnostic, + outer_types_source_map: &TypesSourceMap, source_map: &hir_def::body::BodySourceMap, ) -> Option { let expr_syntax = |expr| { @@ -640,6 +659,36 @@ impl AnyDiagnostic { let cast_ty = Type::new(db, def, cast_ty.clone()); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } + InferenceDiagnostic::TyDiagnostic { source, diag } => { + let source_map = match source { + InferenceTyDiagnosticSource::Body => &source_map.types, + InferenceTyDiagnosticSource::Signature => outer_types_source_map, + }; + let source = match diag.source { + Either::Left(type_ref_id) => { + let Ok(source) = source_map.type_syntax(type_ref_id) else { + stdx::never!("error on synthetic type syntax"); + return None; + }; + source + } + Either::Right(source) => source, + }; + let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); + match diag.kind { + TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { + let ast::Type::PathType(syntax) = syntax() else { return None }; + let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; + let args = if let Some(generics) = segment.generic_arg_list() { + AstPtr::new(&generics).wrap_left() + } else { + AstPtr::new(&segment.param_list()?).wrap_right() + }; + let args = source.with_value(args); + GenericArgsProhibited { args, reason }.into() + } + } + } }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index dc1d1efe60c7..cd4627674732 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -20,12 +20,11 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] -mod semantics; -mod source_analyzer; - mod attrs; mod from_id; mod has_source; +mod semantics; +mod source_analyzer; pub mod db; pub mod diagnostics; @@ -54,6 +53,7 @@ use hir_def::{ path::ImportAlias, per_ns::PerNs, resolver::{HasResolver, Resolver}, + type_ref::TypesSourceMap, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, @@ -1802,6 +1802,25 @@ impl DefWithBody { let krate = self.module(db).id.krate(); let (body, source_map) = db.body_with_source_map(self.into()); + let item_tree_source_maps; + let outer_types_source_map = match self { + DefWithBody::Function(function) => { + let function = function.id.lookup(db.upcast()).id; + item_tree_source_maps = function.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(function.value).item() + } + DefWithBody::Static(statik) => { + let statik = statik.id.lookup(db.upcast()).id; + item_tree_source_maps = statik.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.statik(statik.value) + } + DefWithBody::Const(konst) => { + let konst = konst.id.lookup(db.upcast()).id; + item_tree_source_maps = konst.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.konst(konst.value) + } + DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => &TypesSourceMap::EMPTY, + }; for (_, def_map) in body.blocks(db.upcast()) { Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); @@ -1861,7 +1880,13 @@ impl DefWithBody { let infer = db.infer(self.into()); for d in &infer.diagnostics { - acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map)); + acc.extend(AnyDiagnostic::inference_diagnostic( + db, + self.into(), + d, + outer_types_source_map, + &source_map, + )); } for (pat_or_expr, mismatch) in infer.type_mismatches() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs new file mode 100644 index 000000000000..c3ad6704b6d6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -0,0 +1,242 @@ +use either::Either; +use hir::GenericArgsProhibitedReason; +use ide_db::assists::Assist; +use ide_db::source_change::SourceChange; +use ide_db::text_edit::TextEdit; +use syntax::{ast, AstNode, TextRange}; + +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: generic-args-prohibited +// +// This diagnostic is shown when generic arguments are provided for a type that does not accept +// generic arguments. +pub(crate) fn generic_args_prohibited( + ctx: &DiagnosticsContext<'_>, + d: &hir::GenericArgsProhibited, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0109"), + describe_reason(d.reason), + d.args.map(Into::into), + ) + .with_fixes(fixes(ctx, d)) +} + +fn describe_reason(reason: GenericArgsProhibitedReason) -> String { + let kind = match reason { + GenericArgsProhibitedReason::Module => "modules", + GenericArgsProhibitedReason::TyParam => "type parameters", + GenericArgsProhibitedReason::SelfTy => "`Self`", + GenericArgsProhibitedReason::PrimitiveTy => "builtin types", + GenericArgsProhibitedReason::EnumVariant => { + return "you can specify generic arguments on either the enum or the variant, but not both" + .to_owned(); + } + }; + format!("generic arguments are not allowed on {kind}") +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option> { + let file_id = d.args.file_id.file_id()?; + let syntax = d.args.to_node(ctx.sema.db); + let range = match &syntax { + Either::Left(_) => syntax.syntax().text_range(), + Either::Right(param_list) => { + let path_segment = ast::PathSegment::cast(param_list.syntax().parent()?)?; + let start = if let Some(coloncolon) = path_segment.coloncolon_token() { + coloncolon.text_range().start() + } else { + param_list.syntax().text_range().start() + }; + let end = if let Some(ret_type) = path_segment.ret_type() { + ret_type.syntax().text_range().end() + } else { + param_list.syntax().text_range().end() + }; + TextRange::new(start, end) + } + }; + Some(vec![fix( + "remove_generic_args", + "Remove these generics", + SourceChange::from_text_edit(file_id, TextEdit::delete(range)), + syntax.syntax().text_range(), + )]) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn primitives() { + check_diagnostics( + r#" +//- /core.rs crate:core library +#![rustc_coherence_is_core] +impl str { + pub fn trim() {} +} + +//- /lib.rs crate:foo deps:core +fn bar() {} + +fn foo() { + let _: (bool<()>, ()); + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + let _ = >::trim; + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + bar::>(); + // ^^^^^^^^^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn modules() { + check_diagnostics( + r#" +pub mod foo { + pub mod bar { + pub struct Baz; + + impl Baz { + pub fn qux() {} + } + } +} + +fn foo() { + let _: foo::<'_>::bar::Baz; + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + let _ = ::Baz>::qux; + // ^^^^ 💡 error: generic arguments are not allowed on modules +} + "#, + ); + } + + #[test] + fn type_parameters() { + check_diagnostics( + r#" +fn foo() { + let _: T<'a>; + // ^^^^ 💡 error: generic arguments are not allowed on type parameters + let _: U::<{ 1 + 2 }>; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on type parameters +} + "#, + ); + } + + #[test] + fn fn_like_generic_args() { + check_diagnostics( + r#" +fn foo() { + let _: bool(bool, i32) -> (); + // ^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn fn_signature() { + check_diagnostics( + r#" +fn foo( + _a: bool<'_>, + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + _b: i32::, + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + _c: &(&str<1>) + // ^^^ 💡 error: generic arguments are not allowed on builtin types +) -> ((), i32) { + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + ((), 0) +} + "#, + ); + } + + #[test] + fn const_static_type() { + check_diagnostics( + r#" +const A: i32 = 0; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +static A: i32::<{ 1 + 3 }> = 0; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn fix() { + check_fix( + r#" +fn foo() { + let _: bool<'_, (), { 1 + 1 }>$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::$0<'_, (), { 1 + 1 }>; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool(i$032); +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool$0(i32) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i$032) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i32)$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 81cb45212186..4ab649cc1628 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -167,9 +167,9 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - } let method_name = call.name_ref()?; - let assoc_func_call = format!("{receiver_type_adt_name}::{method_name}()"); + let assoc_func_path = format!("{receiver_type_adt_name}::{method_name}"); - let assoc_func_call = make::expr_path(make::path_from_text(&assoc_func_call)); + let assoc_func_path = make::expr_path(make::path_from_text(&assoc_func_path)); let args: Vec<_> = if need_to_take_receiver_as_first_arg { std::iter::once(receiver).chain(call.arg_list()?.args()).collect() @@ -178,7 +178,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - }; let args = make::arg_list(args); - let assoc_func_call_expr_string = make::expr_call(assoc_func_call, args).to_string(); + let assoc_func_call_expr_string = make::expr_call(assoc_func_path, args).to_string(); let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id; 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 1f1b6478d360..663fc6a67712 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -27,6 +27,7 @@ mod handlers { pub(crate) mod await_outside_of_async; pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; + pub(crate) mod generic_args_prohibited; pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; @@ -468,6 +469,7 @@ pub fn semantic_diagnostics( Some(it) => it, None => continue, }, + AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d) }; res.push(d) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 2ec83d23b27c..7eb3e08f5410 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -402,7 +402,7 @@ pub fn join_paths(paths: impl IntoIterator) -> ast::Path { // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {text}; }}")) + ast_from_text(&format!("fn main() {{ let test: {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { From 1aae52210a57e48d03dcd9f40b1ba04d20ff4ca7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 21 Nov 2024 02:21:16 +0200 Subject: [PATCH 039/197] Complete diagnostics in ty lowering groundwork Implement diagnostics in all places left: generics (predicates, defaults, const params' types), fields, and type aliases. Unfortunately this results in a 20mb addition in `analysis-stats .` due to many type methods returning an addition diagnostics result now (even if it's `None` in most cases). I'm not sure if this can be improved. An alternative strategy that can prevent the memory usage growth is to never produce diagnostics in hir-ty methods. Instead, lower all types in the hir crate when computing diagnostics from scratch (with diagnostics this time). But this has two serious disadvantages: 1. This can cause code duplication (although it can probably be not that bad, it will still mean a lot more code). 2. I believe we eventually want to compute diagnostics for the *entire* workspace (either on-type or on-save or something alike), so users can know when they have diagnostics even in inactive files. Choosing this approach will mean we lose all precomputed salsa queries. For one file this is fine, for the whole workspace this will be very slow. --- .../crates/hir-def/src/generics.rs | 5 + .../rust-analyzer/crates/hir-ty/src/db.rs | 30 ++- .../crates/hir-ty/src/generics.rs | 16 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 3 +- .../rust-analyzer/crates/hir-ty/src/lower.rs | 213 ++++++++++++------ .../crates/hir/src/diagnostics.rs | 59 +++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 198 +++++++++++++++- .../src/handlers/generic_args_prohibited.rs | 200 ++++++++++++++++ 8 files changed, 621 insertions(+), 103 deletions(-) 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 fdcb10e9988a..7b3f1d06d21b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -224,6 +224,11 @@ impl GenericParams { self.len() == 0 } + #[inline] + pub fn no_predicates(&self) -> bool { + self.where_predicates.is_empty() + } + #[inline] pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { self.where_predicates.iter() 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 3a3a05c369ad..6856eaa3e02f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -22,7 +22,7 @@ use crate::{ consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, - lower::{GenericDefaults, GenericPredicates}, + lower::{Diagnostics, GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, @@ -115,21 +115,35 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders; + #[ra_salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] + fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders, Diagnostics); + /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. #[ra_salsa::invoke(crate::lower::value_ty_query)] fn value_ty(&self, def: ValueTyDefId) -> Option>; + #[ra_salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)] + fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders, Diagnostics); #[ra_salsa::invoke(crate::lower::impl_self_ty_query)] - #[ra_salsa::cycle(crate::lower::impl_self_ty_recover)] fn impl_self_ty(&self, def: ImplId) -> Binders; + #[ra_salsa::invoke(crate::lower::const_param_ty_with_diagnostics_query)] + fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics); #[ra_salsa::invoke(crate::lower::const_param_ty_query)] fn const_param_ty(&self, def: ConstParamId) -> Ty; + #[ra_salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)] + fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders, Diagnostics)>; #[ra_salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option>; + #[ra_salsa::invoke(crate::lower::field_types_with_diagnostics_query)] + fn field_types_with_diagnostics( + &self, + var: VariantId, + ) -> (Arc>>, Diagnostics); #[ra_salsa::invoke(crate::lower::field_types_query)] fn field_types(&self, var: VariantId) -> Arc>>; @@ -154,6 +168,11 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)] + fn generic_predicates_without_parent_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericPredicates, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)] fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; @@ -164,8 +183,13 @@ pub trait HirDatabase: DefDatabase + Upcast { #[ra_salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment(&self, def: GenericDefId) -> Arc; + #[ra_salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)] + fn generic_defaults_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericDefaults, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_defaults_query)] - #[ra_salsa::cycle(crate::lower::generic_defaults_recover)] fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; #[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] 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 c094bc395129..fe7541d23747 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -55,6 +55,10 @@ impl Generics { self.def } + pub(crate) fn self_types_map(&self) -> &TypesMap { + &self.params.types_map + } + pub(crate) fn iter_id(&self) -> impl Iterator + '_ { self.iter_self_id().chain(self.iter_parent_id()) } @@ -86,15 +90,13 @@ impl Generics { self.iter_self().chain(self.iter_parent()) } - pub(crate) fn iter_with_types_map( + pub(crate) fn iter_parents_with_types_map( &self, ) -> impl Iterator), &TypesMap)> + '_ { - self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain( - self.iter_parent().zip( - self.parent_generics() - .into_iter() - .flat_map(|it| std::iter::repeat(&it.params.types_map)), - ), + self.iter_parent().zip( + self.parent_generics() + .into_iter() + .flat_map(|it| std::iter::repeat(&it.params.types_map)), ) } 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 77ae295cee41..8bb90ca31e47 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -90,7 +90,8 @@ pub use infer::{ pub use interner::Interner; pub use lower::{ associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, - ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnosticKind, ValueTyDefId, + ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + 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 b73967be7100..b23f2749ab28 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::{ all_super_traits, @@ -1652,11 +1652,24 @@ fn named_associated_type_shorthand_candidates( } } -/// Build the type of all specific fields of a struct or enum variant. +pub(crate) type Diagnostics = Option>; + +fn create_diagnostics(diagnostics: Vec) -> Diagnostics { + (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) +} + pub(crate) fn field_types_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> Arc>> { + db.field_types_with_diagnostics(variant_id).0 +} + +/// Build the type of all specific fields of a struct or enum variant. +pub(crate) fn field_types_with_diagnostics_query( + db: &dyn HirDatabase, + variant_id: VariantId, +) -> (Arc>>, Diagnostics) { let var_data = variant_id.variant_data(db.upcast()); let (resolver, def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), @@ -1672,7 +1685,7 @@ pub(crate) fn field_types_query( for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } - Arc::new(res) + (Arc::new(res), create_diagnostics(ctx.diagnostics)) } /// This query exists only to be used when resolving short-hand associated types @@ -1873,15 +1886,22 @@ pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { - generic_predicates_filtered_by(db, def, |_, _| true) + generic_predicates_filtered_by(db, def, |_, _| true).0 } -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent pub(crate) fn generic_predicates_without_parent_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { + db.generic_predicates_without_parent_with_diagnostics(def).0 +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericPredicates, Diagnostics) { generic_predicates_filtered_by(db, def, |_, d| *d == def) } @@ -1891,7 +1911,7 @@ fn generic_predicates_filtered_by( db: &dyn HirDatabase, def: GenericDefId, filter: F, -) -> GenericPredicates +) -> (GenericPredicates, Diagnostics) where F: Fn(&WherePredicate, &GenericDefId) -> bool, { @@ -1932,7 +1952,10 @@ where ); }; } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) + ( + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), + create_diagnostics(ctx.diagnostics), + ) } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. @@ -1985,75 +2008,110 @@ impl ops::Deref for GenericDefaults { } } -/// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { + db.generic_defaults_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) - .with_type_param_mode(ParamLoweringMode::Variable); - GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map( - |(idx, ((id, p), types_map))| { - ctx.types_map = types_map; - match p { - GenericParamDataRef::TypeParamData(p) => { - let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) - }); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; + let mut ctx = + TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); + let mut idx = 0; + let mut defaults = generic_params + .iter_self() + .map(|(id, p)| { + let result = + handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + }) + .collect::>(); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| { + ctx.types_map = types_map; + let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + })); + let defaults = GenericDefaults(Some(Arc::from_iter(defaults))); + return (defaults, diagnostics); - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(db.const_param_ty(id)), - |c| { - let param_ty = ctx.lower_ty(p.ty); - let c = ctx.lower_const(c, param_ty); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx, parent_start_idx); - make_binders(db, &generic_params, val) - } - GenericParamDataRef::LifetimeParamData(_) => { - make_binders(db, &generic_params, error_lifetime().cast(Interner)) - } + fn handle_generic_param( + ctx: &mut TyLoweringContext<'_>, + idx: usize, + id: GenericParamId, + p: GenericParamDataRef<'_>, + parent_start_idx: usize, + generic_params: &Generics, + ) -> Binders { + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) + }); + crate::make_binders(ctx.db, generic_params, ty.cast(Interner)) } - }, - )))) + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; + + let mut val = p.default.as_ref().map_or_else( + || unknown_const_as_generic(ctx.db.const_param_ty(id)), + |c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.cast(Interner) + }, + ); + // Each default can only refer to previous parameters, see above. + val = fallback_bound_vars(val, idx, parent_start_idx); + make_binders(ctx.db, generic_params, val) + } + GenericParamDataRef::LifetimeParamData(_) => { + make_binders(ctx.db, generic_params, error_lifetime().cast(Interner)) + } + } + } } -pub(crate) fn generic_defaults_recover( +pub(crate) fn generic_defaults_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, def: &GenericDefId, -) -> GenericDefaults { +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), *def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } // FIXME: this code is not covered in tests. // we still need one default per parameter - GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { + let defaults = GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) - })))) + })))); + (defaults, None) } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { @@ -2196,7 +2254,10 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders { make_binders(db, &generics, ty) } -fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { +pub(crate) fn type_for_type_alias_with_diagnostics_query( + db: &dyn HirDatabase, + t: TypeAliasId, +) -> (Binders, Diagnostics) { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); let type_alias_data = db.type_alias_data(t); @@ -2211,7 +2272,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders { .map(|type_ref| ctx.lower_ty(type_ref)) .unwrap_or_else(|| TyKind::Error.intern(Interner)) }; - make_binders(db, &generics, inner) + (make_binders(db, &generics, inner), create_diagnostics(ctx.diagnostics)) } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -2254,7 +2315,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders { match def { TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), TyDefId::AdtId(it) => type_for_adt(db, it), - TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, } } @@ -2279,47 +2340,73 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option< } pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders { + db.impl_self_ty_with_diagnostics(impl_id).0 +} + +pub(crate) fn impl_self_ty_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> (Binders, Diagnostics) { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let generics = generics(db.upcast(), impl_id.into()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)) + ( + make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)), + create_diagnostics(ctx.diagnostics), + ) +} + +pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { + db.const_param_ty_with_diagnostics(def).0 } // returns None if def is a type arg -pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { +pub(crate) fn const_param_ty_with_diagnostics_query( + db: &dyn HirDatabase, + def: ConstParamId, +) -> (Ty, Diagnostics) { let parent_data = db.generic_params(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into()); - match data { + let ty = match data { TypeOrConstParamData::TypeParamData(_) => { never!(); Ty::new(Interner, TyKind::Error) } TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - } + }; + (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn impl_self_ty_recover( +pub(crate) fn impl_self_ty_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, impl_id: &ImplId, -) -> Binders { +) -> (Binders, Diagnostics) { let generics = generics(db.upcast(), (*impl_id).into()); - make_binders(db, &generics, TyKind::Error.intern(Interner)) + (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option> { + db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) +} + +pub(crate) fn impl_trait_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> Option<(Binders, Diagnostics)> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?)) + let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?); + Some((trait_ref, create_diagnostics(ctx.diagnostics))) } pub(crate) fn return_type_impl_traits( diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 3657cf5e162c..612c6adb2071 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -15,7 +15,8 @@ use hir_expand::{name::Name, HirFileId, InFile}; use hir_ty::{ db::HirDatabase, diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, - CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnosticKind, + CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, + TyLoweringDiagnosticKind, }; use syntax::{ ast::{self, HasGenericArgs}, @@ -402,7 +403,7 @@ pub struct InvalidCast { #[derive(Debug)] pub struct GenericArgsProhibited { - pub args: InFile>>, + pub args: InFile>>, pub reason: GenericArgsProhibitedReason, } @@ -664,30 +665,38 @@ impl AnyDiagnostic { InferenceTyDiagnosticSource::Body => &source_map.types, InferenceTyDiagnosticSource::Signature => outer_types_source_map, }; - let source = match diag.source { - Either::Left(type_ref_id) => { - let Ok(source) = source_map.type_syntax(type_ref_id) else { - stdx::never!("error on synthetic type syntax"); - return None; - }; - source - } - Either::Right(source) => source, + Self::ty_diagnostic(diag, source_map, db)? + } + }) + } + + pub(crate) fn ty_diagnostic( + diag: &TyLoweringDiagnostic, + source_map: &TypesSourceMap, + db: &dyn HirDatabase, + ) -> Option { + let source = match diag.source { + Either::Left(type_ref_id) => { + let Ok(source) = source_map.type_syntax(type_ref_id) else { + stdx::never!("error on synthetic type syntax"); + return None; }; - let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); - match diag.kind { - TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { - let ast::Type::PathType(syntax) = syntax() else { return None }; - let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; - let args = if let Some(generics) = segment.generic_arg_list() { - AstPtr::new(&generics).wrap_left() - } else { - AstPtr::new(&segment.param_list()?).wrap_right() - }; - let args = source.with_value(args); - GenericArgsProhibited { args, reason }.into() - } - } + source + } + Either::Right(source) => source, + }; + let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); + Some(match diag.kind { + TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { + let ast::Type::PathType(syntax) = syntax() else { return None }; + let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; + let args = if let Some(generics) = segment.generic_arg_list() { + AstPtr::new(&generics).wrap_left() + } else { + AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right() + }; + let args = source.with_value(args); + GenericArgsProhibited { args, reason }.into() } }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index cd4627674732..10365ba00287 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -76,8 +76,8 @@ use hir_ty::{ traits::FnTrait, AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, - WhereClause, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic, + ValueTyDefId, WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -89,7 +89,7 @@ use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T, }; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::db::{DefDatabase, HirDatabase}; @@ -411,6 +411,10 @@ impl ModuleDef { } } + if let Some(def) = self.as_self_generic_def() { + def.diagnostics(db, &mut acc); + } + acc } @@ -431,6 +435,23 @@ impl ModuleDef { } } + /// Returns only defs that have generics from themselves, not their parent. + pub fn as_self_generic_def(self) -> Option { + match self { + ModuleDef::Function(it) => Some(it.into()), + ModuleDef::Adt(it) => Some(it.into()), + ModuleDef::Trait(it) => Some(it.into()), + ModuleDef::TraitAlias(it) => Some(it.into()), + ModuleDef::TypeAlias(it) => Some(it.into()), + ModuleDef::Module(_) + | ModuleDef::Variant(_) + | ModuleDef::Static(_) + | ModuleDef::Const(_) + | ModuleDef::BuiltinType(_) + | ModuleDef::Macro(_) => None, + } + } + pub fn attrs(&self, db: &dyn HirDatabase) -> Option { Some(match self { ModuleDef::Module(it) => it.attrs(db), @@ -605,17 +626,42 @@ impl Module { ModuleDef::Adt(adt) => { match adt { Adt::Struct(s) => { + let tree_id = s.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(s.id.into()).1, + tree_source_maps.strukt(tree_id.value).item(), + ); for diag in db.struct_data_with_diagnostics(s.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Union(u) => { + let tree_id = u.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(u.id.into()).1, + tree_source_maps.union(tree_id.value).item(), + ); for diag in db.union_data_with_diagnostics(u.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Enum(e) => { for v in e.variants(db) { + let tree_id = v.id.lookup(db.upcast()).id; + let tree_source_maps = + tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(v.id.into()).1, + tree_source_maps.variant(tree_id.value), + ); acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); @@ -626,6 +672,17 @@ impl Module { acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), + ModuleDef::TypeAlias(type_alias) => { + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); + acc.extend(def.diagnostics(db, style_lints)); + } _ => acc.extend(def.diagnostics(db, style_lints)), } } @@ -635,8 +692,11 @@ impl Module { let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { + GenericDef::Impl(impl_def).diagnostics(db, acc); + let loc = impl_def.id.lookup(db.upcast()); - let tree = loc.id.item_tree(db.upcast()); + let (tree, tree_source_maps) = loc.id.item_tree_with_source_map(db.upcast()); + let source_map = tree_source_maps.impl_(loc.id.value).item(); let node = &tree[loc.id.value]; let file_id = loc.id.file_id(); if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) { @@ -771,6 +831,19 @@ impl Module { impl_assoc_items_scratch.clear(); } + push_ty_diagnostics( + db, + acc, + db.impl_self_ty_with_diagnostics(impl_def.id).1, + source_map, + ); + push_ty_diagnostics( + db, + acc, + db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + source_map, + ); + for &item in db.impl_data(impl_def.id).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } @@ -3350,12 +3423,22 @@ impl AssocItem { ) { match self { AssocItem::Function(func) => { + GenericDef::Function(func).diagnostics(db, acc); DefWithBody::from(func).diagnostics(db, acc, style_lints); } AssocItem::Const(const_) => { DefWithBody::from(const_).diagnostics(db, acc, style_lints); } AssocItem::TypeAlias(type_alias) => { + GenericDef::TypeAlias(type_alias).diagnostics(db, acc); + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); } @@ -3442,6 +3525,97 @@ impl GenericDef { }) .collect() } + + fn id(self) -> GenericDefId { + match self { + GenericDef::Function(it) => it.id.into(), + GenericDef::Adt(it) => it.into(), + GenericDef::Trait(it) => it.id.into(), + GenericDef::TraitAlias(it) => it.id.into(), + GenericDef::TypeAlias(it) => it.id.into(), + GenericDef::Impl(it) => it.id.into(), + GenericDef::Const(it) => it.id.into(), + } + } + + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec) { + let def = self.id(); + + let item_tree_source_maps; + let (generics, generics_source_map) = db.generic_params_with_source_map(def); + + if generics.is_empty() && generics.no_predicates() { + return; + } + + let source_map = match &generics_source_map { + Some(it) => it, + None => match def { + GenericDefId::FunctionId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(id.value).generics() + } + GenericDefId::AdtId(AdtId::EnumId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.enum_generic(id.value) + } + GenericDefId::AdtId(AdtId::StructId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.strukt(id.value).generics() + } + GenericDefId::AdtId(AdtId::UnionId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.union(id.value).generics() + } + GenericDefId::TraitId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_generic(id.value) + } + GenericDefId::TraitAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_alias_generic(id.value) + } + GenericDefId::TypeAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.type_alias(id.value).generics() + } + GenericDefId::ImplId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.impl_(id.value).generics() + } + GenericDefId::ConstId(_) => return, + }, + }; + + push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); + push_ty_diagnostics( + db, + acc, + db.generic_predicates_without_parent_with_diagnostics(def).1, + source_map, + ); + for (param_id, param) in generics.iter_type_or_consts() { + if let TypeOrConstParamData::ConstParamData(_) = param { + push_ty_diagnostics( + db, + acc, + db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( + TypeOrConstParamId { parent: def, local_id: param_id }, + )) + .1, + source_map, + ); + } + } + } } /// A single local definition. @@ -5825,3 +5999,19 @@ pub enum DocLinkDef { Field(Field), SelfType(Trait), } + +fn push_ty_diagnostics( + db: &dyn HirDatabase, + acc: &mut Vec, + diagnostics: Option>, + source_map: &TypesSourceMap, +) { + if let Some(diagnostics) = diagnostics { + acc.extend( + diagnostics + .slice + .iter() + .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs index c3ad6704b6d6..a319a0bcf6d6 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -68,6 +68,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option #[cfg(test)] mod tests { + // This diagnostic was the first to be emitted in ty lowering, so the tests here also test + // diagnostics in ty lowering in general (which is why there are so many of them). + use crate::tests::{check_diagnostics, check_fix}; #[test] @@ -239,4 +242,201 @@ fn foo() { }"#, ); } + + #[test] + fn in_fields() { + check_diagnostics( + r#" +struct A(bool); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +struct B { v: bool<(), 1> } + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +union C { + a: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + b: i32, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + } +enum D { + A(bool), + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B { v: i32 }, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn in_generics() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} + +struct A::Trait>(A) + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +union B::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ a: A } +enum C::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + +trait E::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl::Trait> E for () + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn assoc_items() { + check_diagnostics( + r#" +struct Foo; + +trait Trait { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Trait for Foo { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Foo { + fn f() -> bool { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn const_param_ty() { + check_diagnostics( + r#" +fn foo< + const A: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B, + C, + const D: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + const E: bool, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +>() {} + "#, + ); + } + + #[test] + fn generic_defaults() { + check_diagnostics( + r#" +struct Foo>(A); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_self_ty() { + check_diagnostics( + r#" +struct Foo(A); +trait Trait {} +impl Foo> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for Foo> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_trait() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} +impl foo::<()>::Trait for () {} + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + "#, + ); + } + + #[test] + fn type_alias() { + check_diagnostics( + r#" +pub trait Trait { + type Assoc; +} +type T = bool; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for () { + type Assoc = i32; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } } From 61e8403ee20a3ab7a3b6eec3362b70dabf4911e4 Mon Sep 17 00:00:00 2001 From: Tarek Date: Mon, 28 Oct 2024 20:09:52 +0300 Subject: [PATCH 040/197] feat: migrate introduce_named_generic assist to use SyntaxFactory Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 25 +++++++++++++++---- .../src/ast/syntax_factory/constructors.rs | 21 ++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index bf6ac1719f31..8edcd6db3d16 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,8 +1,11 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams, HasName}, - ted, + ast::{ + self, edit_in_place::GenericParamsOwnerEdit, syntax_factory::SyntaxFactory, AstNode, + HasGenericParams, HasName, + }, + SyntaxElement, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,12 +28,20 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let type_bound_list = impl_trait_type.type_bound_list()?; + // FIXME: Is this node appropriate to use for SyntaxEditor in this case? + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; + let make = SyntaxFactory::new(); + let target = fn_.syntax().text_range(); acc.add( AssistId("introduce_named_generic", AssistKind::RefactorRewrite), "Replace impl trait with generic", target, |edit| { + let mut editor = edit.make_editor(&parent_node); let impl_trait_type = edit.make_mut(impl_trait_type); let fn_ = edit.make_mut(fn_); let fn_generic_param_list = fn_.get_or_create_generic_param_list(); @@ -47,11 +58,12 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> ) .for_impl_trait_as_generic(&impl_trait_type); - let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list)) + let type_param = make + .type_param(make.name(&type_param_name), Some(type_bound_list)) .clone_for_update(); - let new_ty = make::ty(&type_param_name).clone_for_update(); + let new_ty = make.ty(&type_param_name).clone_for_update(); - ted::replace(impl_trait_type.syntax(), new_ty.syntax()); + editor.replace(impl_trait_type.syntax(), new_ty.syntax()); fn_generic_param_list.add_generic_param(type_param.into()); if let Some(cap) = ctx.config.snippet_cap { @@ -61,6 +73,9 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> edit.add_tabstop_before(cap, generic_param); } } + + editor.add_mappings(make.finish_with_mappings()); + edit.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 9f88add0f787..680ba9381dd6 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -14,6 +14,27 @@ impl SyntaxFactory { make::name(name).clone_for_update() } + pub fn ty(&self, text: &str) -> ast::Type { + // FIXME: Is there anything to map here? + make::ty(text).clone_for_update() + } + + pub fn type_param( + &self, + name: ast::Name, + bounds: Option, + ) -> ast::TypeParam { + let ast = make::type_param(name.clone(), bounds.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); From 7fa84a3f4b74b7ab68553b5e441dc951ce9050a5 Mon Sep 17 00:00:00 2001 From: Tarek Date: Mon, 28 Oct 2024 20:45:09 +0300 Subject: [PATCH 041/197] fix: remove make_mut from introduce_named_generic assist Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/introduce_named_generic.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 8edcd6db3d16..cf9d58ca0d24 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -42,8 +42,6 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let impl_trait_type = edit.make_mut(impl_trait_type); - let fn_ = edit.make_mut(fn_); let fn_generic_param_list = fn_.get_or_create_generic_param_list(); let existing_names = fn_generic_param_list From 797eb3ebe8b2fcd41f4b03ae7f8aa72f7a47e1a8 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 30 Oct 2024 17:56:02 +0300 Subject: [PATCH 042/197] define syntax_editor_add_generic_param Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 8 +++---- .../crates/syntax/src/ast/edit_in_place.rs | 24 +++++++++++++++++++ .../src/ast/syntax_factory/constructors.rs | 9 +++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index cf9d58ca0d24..ae30dacfd01f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -56,13 +56,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> ) .for_impl_trait_as_generic(&impl_trait_type); - let type_param = make - .type_param(make.name(&type_param_name), Some(type_bound_list)) - .clone_for_update(); - let new_ty = make.ty(&type_param_name).clone_for_update(); + let type_param = make.type_param(make.name(&type_param_name), Some(type_bound_list)); + let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_generic_param_list.add_generic_param(type_param.into()); + fn_generic_param_list.syntax_editor_add_generic_param(&mut editor, type_param.into()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generic_param) = 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 f1286e7aa213..2b152a45c9a3 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 @@ -7,6 +7,7 @@ use parser::{SyntaxKind, T}; use crate::{ algo::{self, neighbor}, ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams}, + syntax_editor::SyntaxEditor, ted::{self, Position}, AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, @@ -257,6 +258,29 @@ impl ast::GenericParamList { } } + pub fn syntax_editor_add_generic_param( + &self, + editor: &mut SyntaxEditor, + generic_param: ast::GenericParam, + ) { + match self.generic_params().last() { + Some(last_param) => { + let position = crate::syntax_editor::Position::after(last_param.syntax()); + let elements = vec![ + make::token(T![,]).into(), + make::tokens::single_space().into(), + generic_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } + None => { + let after_l_angle = + crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); + editor.insert(after_l_angle, generic_param.syntax()); + } + } + } + /// Removes the existing generic param pub fn remove_generic_param(&self, generic_param: ast::GenericParam) { if let Some(previous) = generic_param.syntax().prev_sibling() { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 680ba9381dd6..35c467a1e8c8 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -2,7 +2,7 @@ use itertools::Itertools; use crate::{ - ast::{self, make, HasName}, + ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, AstNode, }; @@ -15,7 +15,6 @@ impl SyntaxFactory { } pub fn ty(&self, text: &str) -> ast::Type { - // FIXME: Is there anything to map here? make::ty(text).clone_for_update() } @@ -29,6 +28,12 @@ impl SyntaxFactory { if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + if let Some(input) = bounds { + builder.map_node( + input.syntax().clone(), + ast.type_bound_list().unwrap().syntax().clone(), + ); + } builder.finish(&mut mapping); } From 54b597ccf24a67f8f2e82be50b7f47ae737aaa00 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 12 Nov 2024 19:18:26 +0200 Subject: [PATCH 043/197] fix: implement `syntax_editor_create_generic_param_list` Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 8 ++--- .../crates/syntax/src/ast/edit_in_place.rs | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index ae30dacfd01f..c6945d6245e3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,10 +1,7 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; use syntax::{ - ast::{ - self, edit_in_place::GenericParamsOwnerEdit, syntax_factory::SyntaxFactory, AstNode, - HasGenericParams, HasName, - }, + ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}, SyntaxElement, }; @@ -42,7 +39,8 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let fn_generic_param_list = fn_.get_or_create_generic_param_list(); + let fn_generic_param_list = + fn_.syntax_editor_get_or_create_generic_param_list(&mut editor); let existing_names = fn_generic_param_list .generic_params() 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 2b152a45c9a3..61580a5cae66 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 @@ -55,6 +55,29 @@ impl GenericParamsOwnerEdit for ast::Fn { } } +impl ast::Fn { + pub fn syntax_editor_get_or_create_generic_param_list( + &self, + editor: &mut SyntaxEditor, + ) -> ast::GenericParamList { + match self.generic_param_list() { + Some(it) => it, + None => { + let position = if let Some(name) = self.name() { + crate::syntax_editor::Position::after(name.syntax) + } else if let Some(fn_token) = self.fn_token() { + crate::syntax_editor::Position::after(fn_token) + } else if let Some(param_list) = self.param_list() { + crate::syntax_editor::Position::before(param_list.syntax) + } else { + crate::syntax_editor::Position::last_child_of(self.syntax()) + }; + syntax_editor_create_generic_param_list(editor, position) + } + } + } +} + impl GenericParamsOwnerEdit for ast::Impl { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { match self.generic_param_list() { @@ -191,6 +214,15 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList { gpl } +fn syntax_editor_create_generic_param_list( + editor: &mut SyntaxEditor, + position: crate::syntax_editor::Position, +) -> ast::GenericParamList { + let gpl = make::generic_param_list(empty()).clone_for_update(); + editor.insert(position, gpl.syntax()); + gpl +} + pub trait AttrsOwnerEdit: ast::HasAttrs { fn remove_attrs_and_docs(&self) { remove_attrs_and_docs(self.syntax()); From e275203e808353279d50d62ce8f4556acc0fd7ac Mon Sep 17 00:00:00 2001 From: Tarek Date: Fri, 22 Nov 2024 16:26:14 +0200 Subject: [PATCH 044/197] fix: refactor syntax_editor_add_generic_param to handle new generic parameters Signed-off-by: Tarek --- .../crates/syntax/src/ast/edit_in_place.rs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) 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 61580a5cae66..9a5c122e27c4 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 @@ -293,22 +293,21 @@ impl ast::GenericParamList { pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, - generic_param: ast::GenericParam, + new_param: ast::GenericParam, ) { match self.generic_params().last() { - Some(last_param) => { - let position = crate::syntax_editor::Position::after(last_param.syntax()); - let elements = vec![ - make::token(T![,]).into(), - make::tokens::single_space().into(), - generic_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); + Some(_) => { + let mut params = + self.generic_params().map(|param| param.clone()).collect::>(); + params.push(new_param.into()); + let new_param_list = make::generic_param_list(params); + + editor.replace(self.syntax(), new_param_list.syntax()); } None => { - let after_l_angle = - crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); - editor.insert(after_l_angle, generic_param.syntax()); + let position = crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); + let new_param_list = make::generic_param_list(once(new_param.clone())); + editor.insert(position, new_param_list.syntax()); } } } From cfd5f7a40c4eb8b821feca1fd0c8f87c9982c47f Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 27 Nov 2024 14:56:56 +0200 Subject: [PATCH 045/197] fix: refactor `syntax_editor_add_generic_param` to handle adding new generic parameters Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 23 +++---- .../crates/syntax/src/ast/edit_in_place.rs | 65 +++++++++---------- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index c6945d6245e3..25628c1656a6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -39,16 +39,17 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> target, |edit| { let mut editor = edit.make_editor(&parent_node); - let fn_generic_param_list = - fn_.syntax_editor_get_or_create_generic_param_list(&mut editor); - let existing_names = fn_generic_param_list - .generic_params() - .flat_map(|param| match param { - ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), - p => Some(p.to_string()), - }) - .collect_vec(); + let existing_names = match fn_.generic_param_list() { + Some(generic_param_list) => generic_param_list + .generic_params() + .flat_map(|param| match param { + ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), + p => Some(p.to_string()), + }) + .collect_vec(), + None => Vec::new(), + }; let type_param_name = suggest_name::NameGenerator::new_with_names( existing_names.iter().map(|s| s.as_str()), ) @@ -58,13 +59,13 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_generic_param_list.syntax_editor_add_generic_param(&mut editor, type_param.into()); + fn_.syntax_editor_add_generic_param(&mut editor, type_param.into()); if let Some(cap) = ctx.config.snippet_cap { if let Some(generic_param) = fn_.generic_param_list().and_then(|it| it.generic_params().last()) { - edit.add_tabstop_before(cap, generic_param); + editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); } } 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 9a5c122e27c4..360ee14fa289 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 @@ -56,13 +56,37 @@ impl GenericParamsOwnerEdit for ast::Fn { } impl ast::Fn { - pub fn syntax_editor_get_or_create_generic_param_list( + pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, - ) -> ast::GenericParamList { + new_param: GenericParam, + ) { match self.generic_param_list() { - Some(it) => it, + Some(generic_param_list) => match generic_param_list.generic_params().last() { + Some(_last_param) => { + // There exists a generic param list and it's not empty + let mut params = generic_param_list + .generic_params() + .map(|param| param.clone()) + .collect::>(); + params.push(new_param.into()); + let new_param_list = make::generic_param_list(params); + editor.replace( + generic_param_list.syntax(), + new_param_list.syntax().clone_for_update(), + ); + } + None => { + // There exists a generic param list but it's empty + let position = crate::syntax_editor::Position::after( + generic_param_list.l_angle_token().unwrap(), + ); + + editor.insert(position, new_param.syntax()); + } + }, None => { + // There was no generic param list let position = if let Some(name) = self.name() { crate::syntax_editor::Position::after(name.syntax) } else if let Some(fn_token) = self.fn_token() { @@ -72,7 +96,9 @@ impl ast::Fn { } else { crate::syntax_editor::Position::last_child_of(self.syntax()) }; - syntax_editor_create_generic_param_list(editor, position) + + let new_param_list = make::generic_param_list(once(new_param.clone())); + editor.insert(position, new_param_list.syntax().clone_for_update()); } } } @@ -214,15 +240,6 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList { gpl } -fn syntax_editor_create_generic_param_list( - editor: &mut SyntaxEditor, - position: crate::syntax_editor::Position, -) -> ast::GenericParamList { - let gpl = make::generic_param_list(empty()).clone_for_update(); - editor.insert(position, gpl.syntax()); - gpl -} - pub trait AttrsOwnerEdit: ast::HasAttrs { fn remove_attrs_and_docs(&self) { remove_attrs_and_docs(self.syntax()); @@ -290,28 +307,6 @@ impl ast::GenericParamList { } } - pub fn syntax_editor_add_generic_param( - &self, - editor: &mut SyntaxEditor, - new_param: ast::GenericParam, - ) { - match self.generic_params().last() { - Some(_) => { - let mut params = - self.generic_params().map(|param| param.clone()).collect::>(); - params.push(new_param.into()); - let new_param_list = make::generic_param_list(params); - - editor.replace(self.syntax(), new_param_list.syntax()); - } - None => { - let position = crate::syntax_editor::Position::after(self.l_angle_token().unwrap()); - let new_param_list = make::generic_param_list(once(new_param.clone())); - editor.insert(position, new_param_list.syntax()); - } - } - } - /// Removes the existing generic param pub fn remove_generic_param(&self, generic_param: ast::GenericParam) { if let Some(previous) = generic_param.syntax().prev_sibling() { From e7fd49cfb42a75da9be5d4a8f4e674a884d7076c Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 23:47:52 +0200 Subject: [PATCH 046/197] fix: refactor `syntax_editor_add_generic_param` Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 9 ++-- .../crates/syntax/src/ast/edit_in_place.rs | 51 ++++++++++++++----- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 25628c1656a6..4b4433419a0e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -59,14 +59,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_.syntax_editor_add_generic_param(&mut editor, type_param.into()); + let generic_param = syntax::ast::GenericParam::from(type_param); + fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { - if let Some(generic_param) = - fn_.generic_param_list().and_then(|it| it.generic_params().last()) - { - editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); - } + editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); 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 360ee14fa289..22afb8297b18 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 @@ -56,6 +56,7 @@ impl GenericParamsOwnerEdit for ast::Fn { } impl ast::Fn { + /// Adds a new generic param to the function using `SyntaxEditor` pub fn syntax_editor_add_generic_param( &self, editor: &mut SyntaxEditor, @@ -65,23 +66,44 @@ impl ast::Fn { Some(generic_param_list) => match generic_param_list.generic_params().last() { Some(_last_param) => { // There exists a generic param list and it's not empty - let mut params = generic_param_list - .generic_params() - .map(|param| param.clone()) - .collect::>(); - params.push(new_param.into()); - let new_param_list = make::generic_param_list(params); - editor.replace( - generic_param_list.syntax(), - new_param_list.syntax().clone_for_update(), + let position = generic_param_list.r_angle_token().map_or_else( + || crate::syntax_editor::Position::last_child_of(self.syntax()), + crate::syntax_editor::Position::before, ); + + if let Some(last_param) = generic_param_list.generic_params().last() { + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } + }; } None => { // There exists a generic param list but it's empty let position = crate::syntax_editor::Position::after( generic_param_list.l_angle_token().unwrap(), ); - editor.insert(position, new_param.syntax()); } }, @@ -96,9 +118,12 @@ impl ast::Fn { } else { crate::syntax_editor::Position::last_child_of(self.syntax()) }; - - let new_param_list = make::generic_param_list(once(new_param.clone())); - editor.insert(position, new_param_list.syntax().clone_for_update()); + let elements = vec![ + make::token(SyntaxKind::L_ANGLE).into(), + new_param.syntax().clone().into(), + make::token(T![>]).into(), + ]; + editor.insert_all(position, elements); } } } From d453198999ad34232b0d3c9adf4769ae7a417ea2 Mon Sep 17 00:00:00 2001 From: Tarek Date: Tue, 3 Dec 2024 23:57:11 +0200 Subject: [PATCH 047/197] fix: correct token type for closing angle bracket Signed-off-by: Tarek --- src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 22afb8297b18..dcaeed40073c 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 @@ -121,7 +121,7 @@ impl ast::Fn { let elements = vec![ make::token(SyntaxKind::L_ANGLE).into(), new_param.syntax().clone().into(), - make::token(T![>]).into(), + make::token(SyntaxKind::R_ANGLE).into(), ]; editor.insert_all(position, elements); } From b1e0d3122173fff7635e144add3b363578b5c147 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 14:32:48 +0200 Subject: [PATCH 048/197] fix: refactor `introduce_named_generic` assist Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 19 ++----- .../crates/syntax/src/ast/edit_in_place.rs | 54 +++++++++---------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 4b4433419a0e..1edbd01b0200 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,9 +1,6 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; -use syntax::{ - ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}, - SyntaxElement, -}; +use syntax::ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,20 +22,14 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let type_bound_list = impl_trait_type.type_bound_list()?; - // FIXME: Is this node appropriate to use for SyntaxEditor in this case? - let parent_node = match ctx.covering_element() { - SyntaxElement::Node(n) => n, - SyntaxElement::Token(t) => t.parent()?, - }; let make = SyntaxFactory::new(); - let target = fn_.syntax().text_range(); acc.add( AssistId("introduce_named_generic", AssistKind::RefactorRewrite), "Replace impl trait with generic", target, - |edit| { - let mut editor = edit.make_editor(&parent_node); + |builder| { + let mut editor = builder.make_editor(fn_.syntax()); let existing_names = match fn_.generic_param_list() { Some(generic_param_list) => generic_param_list @@ -63,11 +54,11 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { - editor.add_annotation(generic_param.syntax(), edit.make_tabstop_before(cap)); + editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); - edit.add_file_edits(ctx.file_id(), editor); + builder.add_file_edits(ctx.file_id(), editor); }, ) } 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 dcaeed40073c..68447a6a2715 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 @@ -64,40 +64,38 @@ impl ast::Fn { ) { match self.generic_param_list() { Some(generic_param_list) => match generic_param_list.generic_params().last() { - Some(_last_param) => { + Some(last_param) => { // There exists a generic param list and it's not empty let position = generic_param_list.r_angle_token().map_or_else( || crate::syntax_editor::Position::last_child_of(self.syntax()), crate::syntax_editor::Position::before, ); - if let Some(last_param) = generic_param_list.generic_params().last() { - if last_param - .syntax() - .next_sibling_or_token() - .map_or(false, |it| it.kind() == SyntaxKind::COMMA) - { - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - new_param.syntax().clone(), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::WHITESPACE), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::COMMA), - ); - } else { - let elements = vec![ - make::token(SyntaxKind::COMMA).into(), - make::token(SyntaxKind::WHITESPACE).into(), - new_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); - } - }; + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + editor.insert( + crate::syntax_editor::Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + editor.insert_all(position, elements); + } } None => { // There exists a generic param list but it's empty From 60e0e02a21b0a018d4cab937772f657e49afad4e Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 14:51:48 +0200 Subject: [PATCH 049/197] refactor: move editing for ast using `SyntaxEditor` to a separate file Signed-off-by: Tarek --- .../src/handlers/introduce_named_generic.rs | 2 +- .../crates/syntax/src/ast/edit_in_place.rs | 73 ------------------- .../crates/syntax/src/syntax_editor.rs | 1 + .../crates/syntax/src/syntax_editor/edits.rs | 72 ++++++++++++++++++ 4 files changed, 74 insertions(+), 74 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 1edbd01b0200..ecc96f791d4a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -51,7 +51,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> editor.replace(impl_trait_type.syntax(), new_ty.syntax()); let generic_param = syntax::ast::GenericParam::from(type_param); - fn_.syntax_editor_add_generic_param(&mut editor, generic_param.clone()); + editor.syntax_editor_add_generic_param(fn_, generic_param.clone()); if let Some(cap) = ctx.config.snippet_cap { editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); 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 68447a6a2715..f1286e7aa213 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 @@ -7,7 +7,6 @@ use parser::{SyntaxKind, T}; use crate::{ algo::{self, neighbor}, ast::{self, edit::IndentLevel, make, HasGenericArgs, HasGenericParams}, - syntax_editor::SyntaxEditor, ted::{self, Position}, AstNode, AstToken, Direction, SyntaxElement, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, @@ -55,78 +54,6 @@ impl GenericParamsOwnerEdit for ast::Fn { } } -impl ast::Fn { - /// Adds a new generic param to the function using `SyntaxEditor` - pub fn syntax_editor_add_generic_param( - &self, - editor: &mut SyntaxEditor, - new_param: GenericParam, - ) { - match self.generic_param_list() { - Some(generic_param_list) => match generic_param_list.generic_params().last() { - Some(last_param) => { - // There exists a generic param list and it's not empty - let position = generic_param_list.r_angle_token().map_or_else( - || crate::syntax_editor::Position::last_child_of(self.syntax()), - crate::syntax_editor::Position::before, - ); - - if last_param - .syntax() - .next_sibling_or_token() - .map_or(false, |it| it.kind() == SyntaxKind::COMMA) - { - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - new_param.syntax().clone(), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::WHITESPACE), - ); - editor.insert( - crate::syntax_editor::Position::after(last_param.syntax()), - make::token(SyntaxKind::COMMA), - ); - } else { - let elements = vec![ - make::token(SyntaxKind::COMMA).into(), - make::token(SyntaxKind::WHITESPACE).into(), - new_param.syntax().clone().into(), - ]; - editor.insert_all(position, elements); - } - } - None => { - // There exists a generic param list but it's empty - let position = crate::syntax_editor::Position::after( - generic_param_list.l_angle_token().unwrap(), - ); - editor.insert(position, new_param.syntax()); - } - }, - None => { - // There was no generic param list - let position = if let Some(name) = self.name() { - crate::syntax_editor::Position::after(name.syntax) - } else if let Some(fn_token) = self.fn_token() { - crate::syntax_editor::Position::after(fn_token) - } else if let Some(param_list) = self.param_list() { - crate::syntax_editor::Position::before(param_list.syntax) - } else { - crate::syntax_editor::Position::last_child_of(self.syntax()) - }; - let elements = vec![ - make::token(SyntaxKind::L_ANGLE).into(), - new_param.syntax().clone().into(), - make::token(SyntaxKind::R_ANGLE).into(), - ]; - editor.insert_all(position, elements); - } - } - } -} - impl GenericParamsOwnerEdit for ast::Impl { fn get_or_create_generic_param_list(&self) -> ast::GenericParamList { match self.generic_param_list() { diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 714f5a991114..7e5d0f27e0a0 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -16,6 +16,7 @@ use rustc_hash::FxHashMap; use crate::{SyntaxElement, SyntaxNode, SyntaxToken}; mod edit_algo; +mod edits; mod mapping; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs new file mode 100644 index 000000000000..759b46c9c795 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -0,0 +1,72 @@ +//! Structural editing for ast using `SyntaxEditor` + +use crate::{ + ast::make, ast::AstNode, ast::Fn, ast::GenericParam, ast::HasGenericParams, ast::HasName, + syntax_editor::Position, syntax_editor::SyntaxEditor, SyntaxKind, +}; + +impl SyntaxEditor { + /// Adds a new generic param to the function using `SyntaxEditor` + pub fn syntax_editor_add_generic_param(&mut self, function: Fn, new_param: GenericParam) { + match function.generic_param_list() { + Some(generic_param_list) => match generic_param_list.generic_params().last() { + Some(last_param) => { + // There exists a generic param list and it's not empty + let position = generic_param_list.r_angle_token().map_or_else( + || Position::last_child_of(function.syntax()), + Position::before, + ); + + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + self.insert( + Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + self.insert_all(position, elements); + } + } + None => { + // There exists a generic param list but it's empty + let position = Position::after(generic_param_list.l_angle_token().unwrap()); + self.insert(position, new_param.syntax()); + } + }, + None => { + // There was no generic param list + let position = if let Some(name) = function.name() { + Position::after(name.syntax) + } else if let Some(fn_token) = function.fn_token() { + Position::after(fn_token) + } else if let Some(param_list) = function.param_list() { + Position::before(param_list.syntax) + } else { + Position::last_child_of(function.syntax()) + }; + let elements = vec![ + make::token(SyntaxKind::L_ANGLE).into(), + new_param.syntax().clone().into(), + make::token(SyntaxKind::R_ANGLE).into(), + ]; + self.insert_all(position, elements); + } + } + } +} From 30847ebb255abbda590460e86a21b7b1c7c3b273 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Dec 2024 15:58:23 +0300 Subject: [PATCH 050/197] use vendor sources by default on dist tarballs Signed-off-by: onur-ozkan --- src/bootstrap/src/core/config/config.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b06147055f2a..69aa6492eb68 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1632,7 +1632,6 @@ impl Config { set(&mut config.docs_minification, docs_minification); set(&mut config.docs, docs); set(&mut config.locked_deps, locked_deps); - set(&mut config.vendor, vendor); set(&mut config.full_bootstrap, full_bootstrap); set(&mut config.extended, extended); config.tools = tools; @@ -1711,6 +1710,12 @@ impl Config { config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + config.vendor = vendor.unwrap_or( + config.rust_info.is_from_tarball() + && config.src.join("vendor").exists() + && config.src.join(".cargo/config.toml").exists(), + ); + if let Some(rust) = toml.rust { let Rust { optimize: optimize_toml, From a6aaef14e6ea27b2051b2870acb62fd0553be17f Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Dec 2024 16:01:04 +0300 Subject: [PATCH 051/197] update `build.vendor` documentation Signed-off-by: onur-ozkan --- config.example.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config.example.toml b/config.example.toml index 9ec0d77e79b3..5ea6774ce035 100644 --- a/config.example.toml +++ b/config.example.toml @@ -311,9 +311,8 @@ # Indicate whether the vendored sources are used for Rust dependencies or not. # # Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you -# want to use vendoring. See -# https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. -#vendor = false +# want to use vendoring. See https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. +#vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } # Typically the build system will build the Rust compiler twice. The second # compiler, however, will simply use its own libraries to link against. If you From 9ca9b41df2ca682c815b9bb3e580ce93b216a50d Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Dec 2024 16:08:37 +0300 Subject: [PATCH 052/197] add a change entry for new default on `build.vendor` Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 41a541d72694..f4f189c718a3 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -310,4 +310,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Revert `rust.download-rustc` global default to `false` and only use `rust.download-rustc = \"if-unchanged\"` default for library and tools profile. As alt CI rustc is built without debug assertions, `rust.debug-assertions = true` will now inhibit downloading CI rustc.", }, + ChangeInfo { + change_id: 133853, + severity: ChangeSeverity::Info, + summary: "`build.vendor` is now enabled by default for dist/tarball sources when 'vendor' directory and '.cargo/config.toml' file are present.", + }, ]; From d5f3ed89cb0c1fa2164147efff25695be02bc36a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 4 Dec 2024 15:25:01 +0200 Subject: [PATCH 053/197] Do not report warnings from proc macros, ever --- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 7 +++++++ src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs | 6 ++++++ 2 files changed, 13 insertions(+) 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 7d2f556406d4..2ee598dfbfdc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -269,6 +269,13 @@ pub enum MacroDefKind { ProcMacro(AstId, CustomProcMacroExpander, ProcMacroKind), } +impl MacroDefKind { + #[inline] + pub fn is_declarative(&self) -> bool { + matches!(self, MacroDefKind::Declarative(..)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct EagerCallInfo { /// The expanded argument of the eager macro. 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 1f1b6478d360..9fbed7db35bd 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -542,7 +542,13 @@ fn handle_diag_from_macros( sema.db.lookup_intern_syntax_context(span.ctx).outer_expn.is_some_and(|expansion| { let macro_call = sema.db.lookup_intern_macro_call(expansion.as_macro_file().macro_call_id); + // We don't want to show diagnostics for non-local macros at all, but proc macros authors + // seem to rely on being able to emit non-warning-free code, so we don't want to show warnings + // for them even when the proc macro comes from the same workspace (in rustc that's not a + // problem because it doesn't have the concept of workspaces, and proc macros always reside + // in a different crate). !Crate::from(macro_call.def.krate).origin(sema.db).is_local() + || !macro_call.def.kind.is_declarative() }) }) { // Disable suggestions for external macros, they'll change library code and it's just bad. From 6120a8ad0bc93b756fab12e1ae2a9c25700d1d85 Mon Sep 17 00:00:00 2001 From: Tarek Date: Wed, 4 Dec 2024 16:02:03 +0200 Subject: [PATCH 054/197] fix: update `introduce_named_generic` to use `type_param` directly Signed-off-by: Tarek --- .../ide-assists/src/handlers/introduce_named_generic.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index ecc96f791d4a..28023ce5edbf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -50,11 +50,10 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - let generic_param = syntax::ast::GenericParam::from(type_param); - editor.syntax_editor_add_generic_param(fn_, generic_param.clone()); + editor.syntax_editor_add_generic_param(fn_, type_param.clone().into()); if let Some(cap) = ctx.config.snippet_cap { - editor.add_annotation(generic_param.syntax(), builder.make_tabstop_before(cap)); + editor.add_annotation(type_param.syntax(), builder.make_tabstop_before(cap)); } editor.add_mappings(make.finish_with_mappings()); From dff5ce68816edaf8a8740db60a8aa735641939f7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Dec 2024 15:24:11 +1100 Subject: [PATCH 055/197] Move some `BitSet` code blocks to a better place. These blocks are currently interleaved with `ChunkedBitSet` blocks. It makes things hard to find and has annoyed me for a while. --- compiler/rustc_index/src/bit_set.rs | 210 ++++++++++++++-------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index de6fa132ca07..8693c731dd0a 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -296,6 +296,111 @@ impl From> for BitSet { } } +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } + } + + fn clone_from(&mut self, from: &Self) { + self.domain_size = from.domain_size; + self.words.clone_from(&from.words); + } +} + +impl fmt::Debug for BitSet { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + w.debug_list().entries(self.iter()).finish() + } +} + +impl ToString for BitSet { + fn to_string(&self) -> String { + let mut result = String::new(); + let mut sep = '['; + + // Note: this is a little endian printout of bytes. + + // i tracks how many bits we have printed so far. + let mut i = 0; + for word in &self.words { + let mut word = *word; + for _ in 0..WORD_BYTES { + // for each byte in `word`: + let remain = self.domain_size - i; + // If less than a byte remains, then mask just that many bits. + let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; + assert!(mask <= 0xFF); + let byte = word & mask; + + result.push_str(&format!("{sep}{byte:02x}")); + + if remain <= 8 { + break; + } + word >>= 8; + i += 8; + sep = '-'; + } + sep = '|'; + } + result.push(']'); + + result + } +} + +pub struct BitIter<'a, T: Idx> { + /// A copy of the current word, but with any already-visited bits cleared. + /// (This lets us use `trailing_zeros()` to find the next set bit.) When it + /// is reduced to 0, we move onto the next word. + word: Word, + + /// The offset (measured in bits) of the current word. + offset: usize, + + /// Underlying iterator over the words. + iter: slice::Iter<'a, Word>, + + marker: PhantomData, +} + +impl<'a, T: Idx> BitIter<'a, T> { + #[inline] + fn new(words: &'a [Word]) -> BitIter<'a, T> { + // We initialize `word` and `offset` to degenerate values. On the first + // call to `next()` we will fall through to getting the first word from + // `iter`, which sets `word` to the first word (if there is one) and + // `offset` to 0. Doing it this way saves us from having to maintain + // additional state about whether we have started. + BitIter { + word: 0, + offset: usize::MAX - (WORD_BITS - 1), + iter: words.iter(), + marker: PhantomData, + } + } +} + +impl<'a, T: Idx> Iterator for BitIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option { + loop { + if self.word != 0 { + // Get the position of the next set bit in the current word, + // then clear the bit. + let bit_pos = self.word.trailing_zeros() as usize; + self.word ^= 1 << bit_pos; + return Some(T::new(bit_pos + self.offset)); + } + + // Move onto the next word. `wrapping_add()` is needed to handle + // the degenerate initial value given to `offset` in `new()`. + self.word = *self.iter.next()?; + self.offset = self.offset.wrapping_add(WORD_BITS); + } + } +} + /// A fixed-size bitset type with a partially dense, partially sparse /// representation. The bitset is broken into chunks, and chunks that are all /// zeros or all ones are represented and handled very efficiently. @@ -958,117 +1063,12 @@ fn sequential_update( it.fold(false, |changed, elem| self_update(elem) | changed) } -impl Clone for BitSet { - fn clone(&self) -> Self { - BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } - } - - fn clone_from(&mut self, from: &Self) { - self.domain_size = from.domain_size; - self.words.clone_from(&from.words); - } -} - -impl fmt::Debug for BitSet { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - w.debug_list().entries(self.iter()).finish() - } -} - impl fmt::Debug for ChunkedBitSet { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list().entries(self.iter()).finish() } } -impl ToString for BitSet { - fn to_string(&self) -> String { - let mut result = String::new(); - let mut sep = '['; - - // Note: this is a little endian printout of bytes. - - // i tracks how many bits we have printed so far. - let mut i = 0; - for word in &self.words { - let mut word = *word; - for _ in 0..WORD_BYTES { - // for each byte in `word`: - let remain = self.domain_size - i; - // If less than a byte remains, then mask just that many bits. - let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; - assert!(mask <= 0xFF); - let byte = word & mask; - - result.push_str(&format!("{sep}{byte:02x}")); - - if remain <= 8 { - break; - } - word >>= 8; - i += 8; - sep = '-'; - } - sep = '|'; - } - result.push(']'); - - result - } -} - -pub struct BitIter<'a, T: Idx> { - /// A copy of the current word, but with any already-visited bits cleared. - /// (This lets us use `trailing_zeros()` to find the next set bit.) When it - /// is reduced to 0, we move onto the next word. - word: Word, - - /// The offset (measured in bits) of the current word. - offset: usize, - - /// Underlying iterator over the words. - iter: slice::Iter<'a, Word>, - - marker: PhantomData, -} - -impl<'a, T: Idx> BitIter<'a, T> { - #[inline] - fn new(words: &'a [Word]) -> BitIter<'a, T> { - // We initialize `word` and `offset` to degenerate values. On the first - // call to `next()` we will fall through to getting the first word from - // `iter`, which sets `word` to the first word (if there is one) and - // `offset` to 0. Doing it this way saves us from having to maintain - // additional state about whether we have started. - BitIter { - word: 0, - offset: usize::MAX - (WORD_BITS - 1), - iter: words.iter(), - marker: PhantomData, - } - } -} - -impl<'a, T: Idx> Iterator for BitIter<'a, T> { - type Item = T; - fn next(&mut self) -> Option { - loop { - if self.word != 0 { - // Get the position of the next set bit in the current word, - // then clear the bit. - let bit_pos = self.word.trailing_zeros() as usize; - self.word ^= 1 << bit_pos; - return Some(T::new(bit_pos + self.offset)); - } - - // Move onto the next word. `wrapping_add()` is needed to handle - // the degenerate initial value given to `offset` in `new()`. - self.word = *self.iter.next()?; - self.offset = self.offset.wrapping_add(WORD_BITS); - } - } -} - #[inline] fn bitwise(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool where From a9afc99c1347eacdb9495ffa2601bb032997f2ae Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 09:44:17 +0100 Subject: [PATCH 056/197] Disable `<` typing handler again --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- src/tools/rust-analyzer/docs/user/generated_config.adoc | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 392bfbf15fe1..aa9f919679de 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + typing_excludeChars: Option = Some("<".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c4..96a2a5a27d3c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf622..7529651ca7a0 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "default": "<", "type": [ "null", "string" From 6ee1a7aaa02f7e7713c8b60d785610983dc69ee7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Dec 2024 11:15:59 +1100 Subject: [PATCH 057/197] Introduce `MixedBitSet`. It just uses `BitSet` for small/medium sizes (<= 2048 bits) and `ChunkedBitSet` for larger sizes. This is good because `ChunkedBitSet` is slow and memory-hungry at smaller sizes. --- compiler/rustc_index/src/bit_set.rs | 155 ++++++++++++++++++ .../rustc_mir_dataflow/src/framework/fmt.rs | 22 ++- .../src/framework/lattice.rs | 8 +- .../rustc_mir_dataflow/src/framework/mod.rs | 18 +- 4 files changed, 200 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 8693c731dd0a..41bd47ea6d06 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -410,6 +410,9 @@ impl<'a, T: Idx> Iterator for BitIter<'a, T> { /// some stretches with lots of 0s and 1s mixed in a way that causes trouble /// for `IntervalSet`. /// +/// Best used via `MixedBitSet`, rather than directly, because `MixedBitSet` +/// has better performance for small bitsets. +/// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also /// just be `usize`. /// @@ -1106,6 +1109,158 @@ where false } +/// A bitset with a mixed representation, using `BitSet` for small and medium +/// bitsets, and `ChunkedBitSet` for large bitsets, i.e. those with enough bits +/// for at least two chunks. This is a good choice for many bitsets that can +/// have large domain sizes (e.g. 5000+). +/// +/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also +/// just be `usize`. +/// +/// All operations that involve an element will panic if the element is equal +/// to or greater than the domain size. All operations that involve two bitsets +/// will panic if the bitsets have differing domain sizes. +#[derive(PartialEq, Eq)] +pub enum MixedBitSet { + Small(BitSet), + Large(ChunkedBitSet), +} + +impl MixedBitSet { + pub fn domain_size(&self) -> usize { + match self { + MixedBitSet::Small(set) => set.domain_size(), + MixedBitSet::Large(set) => set.domain_size(), + } + } +} + +impl MixedBitSet { + #[inline] + pub fn new_empty(domain_size: usize) -> MixedBitSet { + if domain_size <= CHUNK_BITS { + MixedBitSet::Small(BitSet::new_empty(domain_size)) + } else { + MixedBitSet::Large(ChunkedBitSet::new_empty(domain_size)) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + match self { + MixedBitSet::Small(set) => set.is_empty(), + MixedBitSet::Large(set) => set.is_empty(), + } + } + + #[inline] + pub fn contains(&self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.contains(elem), + MixedBitSet::Large(set) => set.contains(elem), + } + } + + #[inline] + pub fn insert(&mut self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.insert(elem), + MixedBitSet::Large(set) => set.insert(elem), + } + } + + pub fn insert_all(&mut self) { + match self { + MixedBitSet::Small(set) => set.insert_all(), + MixedBitSet::Large(set) => set.insert_all(), + } + } + + #[inline] + pub fn remove(&mut self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.remove(elem), + MixedBitSet::Large(set) => set.remove(elem), + } + } + + pub fn iter(&self) -> MixedBitIter<'_, T> { + match self { + MixedBitSet::Small(set) => MixedBitIter::Small(set.iter()), + MixedBitSet::Large(set) => MixedBitIter::Large(set.iter()), + } + } + + bit_relations_inherent_impls! {} +} + +impl Clone for MixedBitSet { + fn clone(&self) -> Self { + match self { + MixedBitSet::Small(set) => MixedBitSet::Small(set.clone()), + MixedBitSet::Large(set) => MixedBitSet::Large(set.clone()), + } + } + + /// WARNING: this implementation of clone_from may panic if the two + /// bitsets have different domain sizes. This constraint is not inherent to + /// `clone_from`, but it works with the existing call sites and allows a + /// faster implementation, which is important because this function is hot. + fn clone_from(&mut self, from: &Self) { + match (self, from) { + (MixedBitSet::Small(set), MixedBitSet::Small(from)) => set.clone_from(from), + (MixedBitSet::Large(set), MixedBitSet::Large(from)) => set.clone_from(from), + _ => panic!("MixedBitSet size mismatch"), + } + } +} + +impl BitRelations> for MixedBitSet { + fn union(&mut self, other: &MixedBitSet) -> bool { + match (self, other) { + (MixedBitSet::Small(set), MixedBitSet::Small(other)) => set.union(other), + (MixedBitSet::Large(set), MixedBitSet::Large(other)) => set.union(other), + _ => panic!("MixedBitSet size mismatch"), + } + } + + fn subtract(&mut self, other: &MixedBitSet) -> bool { + match (self, other) { + (MixedBitSet::Small(set), MixedBitSet::Small(other)) => set.subtract(other), + (MixedBitSet::Large(set), MixedBitSet::Large(other)) => set.subtract(other), + _ => panic!("MixedBitSet size mismatch"), + } + } + + fn intersect(&mut self, _other: &MixedBitSet) -> bool { + unimplemented!("implement if/when necessary"); + } +} + +impl fmt::Debug for MixedBitSet { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MixedBitSet::Small(set) => set.fmt(w), + MixedBitSet::Large(set) => set.fmt(w), + } + } +} + +pub enum MixedBitIter<'a, T: Idx> { + Small(BitIter<'a, T>), + Large(ChunkedBitIter<'a, T>), +} + +impl<'a, T: Idx> Iterator for MixedBitIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option { + match self { + MixedBitIter::Small(iter) => iter.next(), + MixedBitIter::Large(iter) => iter.next(), + } + } +} + /// A resizable bitset type with a dense representation. /// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index dc176ba2d03e..186172b3b86b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -4,7 +4,7 @@ use std::fmt; use rustc_index::Idx; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet}; use super::lattice::MaybeReachable; @@ -127,6 +127,26 @@ where } } +impl DebugWithContext for MixedBitSet +where + T: Idx + DebugWithContext, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MixedBitSet::Small(set) => set.fmt_with(ctxt, f), + MixedBitSet::Large(set) => set.fmt_with(ctxt, f), + } + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match (self, old) { + (MixedBitSet::Small(set), MixedBitSet::Small(old)) => set.fmt_diff_with(old, ctxt, f), + (MixedBitSet::Large(set), MixedBitSet::Large(old)) => set.fmt_diff_with(old, ctxt, f), + _ => panic!("MixedBitSet size mismatch"), + } + } +} + impl DebugWithContext for MaybeReachable where S: DebugWithContext, diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index e2b56aedca3a..852099e2ac82 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -40,7 +40,7 @@ use std::iter; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; use crate::framework::BitSetExt; @@ -132,6 +132,12 @@ impl JoinSemiLattice for ChunkedBitSet { } } +impl JoinSemiLattice for MixedBitSet { + fn join(&mut self, other: &Self) -> bool { + self.union(other) + } +} + /// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no /// value of `T` is comparable with any other. /// diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index b9407882ec5d..40fb22014e5b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -35,7 +35,7 @@ use std::cmp::Ordering; use rustc_data_structures::work_queue::WorkQueue; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; @@ -77,6 +77,12 @@ impl BitSetExt for ChunkedBitSet { } } +impl BitSetExt for MixedBitSet { + fn contains(&self, elem: T) -> bool { + self.contains(elem) + } +} + /// A dataflow problem with an arbitrarily complex transfer function. /// /// This trait specifies the lattice on which this analysis operates (the domain), its @@ -337,6 +343,16 @@ impl GenKill for ChunkedBitSet { } } +impl GenKill for MixedBitSet { + fn gen_(&mut self, elem: T) { + self.insert(elem); + } + + fn kill(&mut self, elem: T) { + self.remove(elem); + } +} + impl> GenKill for MaybeReachable { fn gen_(&mut self, elem: T) { match self { From a06547508a33e432ed45f814a29a1102d5c6c289 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 5 Dec 2024 14:20:05 +1100 Subject: [PATCH 058/197] Change `ChunkedBitSet`s to `MixedBitSet`. It's a performance win because `MixedBitSet` is faster and uses less memory than `ChunkedBitSet`. Also reflow some overlong comment lines in `lint_tail_expr_drop_order.rs`. --- compiler/rustc_borrowck/src/lib.rs | 4 +- .../src/impls/initialized.rs | 22 ++++---- .../src/lint_tail_expr_drop_order.rs | 51 ++++++++++--------- .../src/remove_uninit_drops.rs | 4 +- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9b7474c22084..d7db92da18f0 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -26,7 +26,7 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, @@ -1797,7 +1797,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - maybe_uninits: &ChunkedBitSet, + maybe_uninits: &MixedBitSet, from: u64, to: u64, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 2c10d4b1cd35..916776576021 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; use rustc_index::Idx; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_middle::bug; use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::{self, TyCtxt}; @@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn is_unwind_dead( &self, place: mir::Place<'tcx>, - state: &MaybeReachable>, + state: &MaybeReachable>, ) -> bool { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { let mut maybe_live = false; @@ -244,8 +244,8 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = MaybeReachable>; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MaybeReachable>; const NAME: &'static str = "maybe_init"; @@ -256,7 +256,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { *state = - MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len())); + MaybeReachable::Reachable(MixedBitSet::new_empty(self.move_data().move_paths.len())); drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| { assert!(s == DropFlagState::Present); state.gen_(path); @@ -371,14 +371,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = ChunkedBitSet; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MixedBitSet; const NAME: &'static str = "maybe_uninit"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = initialized (start_block_effect counters this at outset) - ChunkedBitSet::new_empty(self.move_data().move_paths.len()) + MixedBitSet::new_empty(self.move_data().move_paths.len()) } // sets on_entry bits for Arg places @@ -492,14 +492,14 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { /// There can be many more `InitIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = ChunkedBitSet; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MixedBitSet; const NAME: &'static str = "ever_init"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = no initialized variables by default - ChunkedBitSet::new_empty(self.move_data().inits.len()) + MixedBitSet::new_empty(self.move_data().inits.len()) } fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 732a9cd9890d..7fb421dea0c7 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -7,7 +7,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Subdiagnostic; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::bug; @@ -49,24 +49,24 @@ struct DropsReachable<'a, 'mir, 'tcx> { move_data: &'a MoveData<'tcx>, maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, block_drop_value_info: &'a mut IndexSlice, - collected_drops: &'a mut ChunkedBitSet, - visited: FxHashMap>>>, + collected_drops: &'a mut MixedBitSet, + visited: FxHashMap>>>, } impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { fn visit(&mut self, block: BasicBlock) { let move_set_size = self.move_data.move_paths.len(); - let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size))); + let make_new_path_set = || Rc::new(RefCell::new(MixedBitSet::new_empty(move_set_size))); let data = &self.body.basic_blocks[block]; let Some(terminator) = &data.terminator else { return }; - // Given that we observe these dropped locals here at `block` so far, - // we will try to update the successor blocks. - // An occupied entry at `block` in `self.visited` signals that we have visited `block` before. + // Given that we observe these dropped locals here at `block` so far, we will try to update + // the successor blocks. An occupied entry at `block` in `self.visited` signals that we + // have visited `block` before. let dropped_local_here = Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set)); - // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive. - // Let's cache them in `self.block_drop_value_info`. + // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately + // it is expensive. Let's cache them in `self.block_drop_value_info`. match self.block_drop_value_info[block] { MovePathIndexAtBlock::Some(dropped) => { dropped_local_here.borrow_mut().insert(dropped); @@ -76,23 +76,24 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) = self.move_data.rev_lookup.find(place.as_ref()) { - // Since we are working with MIRs at a very early stage, - // observing a `drop` terminator is not indicative enough that - // the drop will definitely happen. - // That is decided in the drop elaboration pass instead. - // Therefore, we need to consult with the maybe-initialization information. + // Since we are working with MIRs at a very early stage, observing a `drop` + // terminator is not indicative enough that the drop will definitely happen. + // That is decided in the drop elaboration pass instead. Therefore, we need to + // consult with the maybe-initialization information. self.maybe_init.seek_before_primary_effect(Location { block, statement_index: data.statements.len(), }); - // Check if the drop of `place` under inspection is really in effect. - // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today. - // In other words, this is where the drop of `place` will happen in the future instead. + // Check if the drop of `place` under inspection is really in effect. This is + // true only when `place` may have been initialized along a control flow path + // from a BID to the drop program point today. In other words, this is where + // the drop of `place` will happen in the future instead. if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get() && maybe_init.contains(idx) { - // We also cache the drop information, so that we do not need to check on data-flow cursor again + // We also cache the drop information, so that we do not need to check on + // data-flow cursor again. self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx); dropped_local_here.borrow_mut().insert(idx); } else { @@ -139,8 +140,9 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { // Let's check the observed dropped places in. self.collected_drops.union(&*dropped_local_there.borrow()); if self.drop_span.is_none() { - // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky. - // There is a high chance that this span still points to a block rather than a statement semicolon. + // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are + // still a bit wonky. There is a high chance that this span still points to a + // block rather than a statement semicolon. *self.drop_span = Some(terminator.source_info.span); } // Now we have discovered a simple control flow path from a future drop point @@ -394,10 +396,10 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< for (&block, candidates) in &bid_per_block { // We will collect drops on locals on paths between BID points to their actual drop locations // into `all_locals_dropped`. - let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut all_locals_dropped = MixedBitSet::new_empty(move_data.move_paths.len()); let mut drop_span = None; for &(_, place) in candidates.iter() { - let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut collected_drops = MixedBitSet::new_empty(move_data.move_paths.len()); // ## On detecting change in relative drop order ## // Iterate through each BID-containing block `block`. // If the place `P` targeted by the BID is "maybe initialized", @@ -425,8 +427,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // We shall now exclude some local bindings for the following cases. { - let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size()); - // We will now do subtraction from the candidate dropped locals, because of the following reasons. + let mut to_exclude = MixedBitSet::new_empty(all_locals_dropped.domain_size()); + // We will now do subtraction from the candidate dropped locals, because of the + // following reasons. for path_idx in all_locals_dropped.iter() { let move_path = &move_data.move_paths[path_idx]; let dropped_local = move_path.place.local; diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index f786c676e9e4..e955d8277a45 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -1,5 +1,5 @@ use rustc_abi::FieldIdx; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::MixedBitSet; use rustc_middle::mir::{Body, TerminatorKind}; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; @@ -67,7 +67,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn is_needs_drop_and_init<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - maybe_inits: &ChunkedBitSet, + maybe_inits: &MixedBitSet, move_data: &MoveData<'tcx>, ty: Ty<'tcx>, mpi: MovePathIndex, From e4092bd9091a68fcc6ddce0a0a72290003c4d560 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Thu, 5 Dec 2024 12:18:14 +0100 Subject: [PATCH 059/197] Fix compilation for wasm32-wasip1 (without threads). --- library/std/src/sys/thread_local/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 82e1aeabf5ba..f0a13323ec93 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -86,7 +86,9 @@ pub(crate) mod guard { mod windows; pub(crate) use windows::enable; } else if #[cfg(any( - all(target_family = "wasm", not(target_os="wasi")), + all(target_family = "wasm", not( + all(target_os = "wasi", target_env = "p1", target_feature = "atomics") + )), target_os = "uefi", target_os = "zkvm", ))] { @@ -135,7 +137,7 @@ pub(crate) mod key { target_family = "unix", ), target_os = "teeos", - target_os = "wasi", + all(target_os = "wasi", target_env = "p1", target_feature = "atomics"), ))] { mod racy; mod unix; From 4f16640bbf88df43ac34b4c772589931d7d567d2 Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Thu, 5 Dec 2024 12:24:19 +0100 Subject: [PATCH 060/197] Add libc funcitons only for wasm32-wasip1-threads. --- library/std/src/sys/thread_local/key/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 6661e378dbf4..b4b58b347063 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -1,7 +1,7 @@ use crate::mem; // For WASI add a few symbols not in upstream `libc` just yet. -#[cfg(target_os = "wasi")] +#[cfg(all(target_os = "wasi", target_env = "p1", target_feature = "atomics"))] mod libc { use crate::ffi; From 0a99a9f05f3c13fbb4fc972b6d7e6d868af14beb Mon Sep 17 00:00:00 2001 From: Tarek Date: Thu, 5 Dec 2024 13:50:43 +0200 Subject: [PATCH 061/197] fix: rename `syntax_editor_add_generic_param` to `add_generic_param` Signed-off-by: Tarek --- .../crates/ide-assists/src/handlers/introduce_named_generic.rs | 2 +- .../rust-analyzer/crates/syntax/src/syntax_editor/edits.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index 28023ce5edbf..8c276415bb1f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -50,7 +50,7 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let new_ty = make.ty(&type_param_name); editor.replace(impl_trait_type.syntax(), new_ty.syntax()); - editor.syntax_editor_add_generic_param(fn_, type_param.clone().into()); + editor.add_generic_param(&fn_, type_param.clone().into()); if let Some(cap) = ctx.config.snippet_cap { editor.add_annotation(type_param.syntax(), builder.make_tabstop_before(cap)); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 759b46c9c795..73196f5cb1be 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -7,7 +7,7 @@ use crate::{ impl SyntaxEditor { /// Adds a new generic param to the function using `SyntaxEditor` - pub fn syntax_editor_add_generic_param(&mut self, function: Fn, new_param: GenericParam) { + pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) { match function.generic_param_list() { Some(generic_param_list) => match generic_param_list.generic_params().last() { Some(last_param) => { From a19e1dffe5ca8574e58826488351af8c714c9620 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: [PATCH 062/197] fix: Fix parsing of integer/keyword name refs in various places --- .../hir-def/src/macro_expansion_tests/mbe.rs | 2 +- .../crates/parser/src/grammar.rs | 44 ++++++++++- .../crates/parser/src/grammar/expressions.rs | 64 ++++++++------- .../parser/src/grammar/expressions/atom.rs | 12 +-- .../crates/parser/src/grammar/generic_args.rs | 4 +- .../parser/src/grammar/generic_params.rs | 11 ++- .../crates/parser/src/grammar/items.rs | 12 +-- .../crates/parser/src/grammar/paths.rs | 49 ++++++------ .../parser/test_data/generated/runner.rs | 8 +- .../parser/err/0004_use_path_bad_segment.rast | 2 +- .../parser/err/0048_double_fish.rast | 4 +- .../parser/inline/err/arg_list_recovery.rast | 2 +- .../err/crate_visibility_empty_recover.rast | 2 +- .../parser/inline/err/empty_segment.rast | 2 +- .../parser/inline/err/meta_recovery.rast | 10 +-- .../inline/err/precise_capturing_invalid.rast | 28 +++++++ .../inline/err/precise_capturing_invalid.rs | 1 + ...cord_literal_before_ellipsis_recovery.rast | 37 ++++++++- ...record_literal_before_ellipsis_recovery.rs | 1 + .../err/record_literal_field_eq_recovery.rast | 29 ++++++- .../err/record_literal_field_eq_recovery.rs | 1 + ...ord_literal_missing_ellipsis_recovery.rast | 78 ++++++++++++++----- ...ecord_literal_missing_ellipsis_recovery.rs | 3 +- .../parser/inline/ok/extern_crate.rast | 9 +++ .../parser/inline/ok/extern_crate.rs | 1 + .../parser/inline/ok/extern_crate_rename.rast | 15 ++++ .../parser/inline/ok/extern_crate_rename.rs | 1 + .../parser/inline/ok/extern_crate_self.rast | 10 --- .../parser/inline/ok/extern_crate_self.rs | 1 - .../parser/inline/ok/field_expr.rast | 24 ++++++ .../test_data/parser/inline/ok/field_expr.rs | 2 + .../parser/inline/ok/method_call_expr.rast | 14 ++++ .../parser/inline/ok/method_call_expr.rs | 1 + 33 files changed, 351 insertions(+), 133 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast delete mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 5c03fad6131b..511626b5ed91 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1733,7 +1733,7 @@ m!(C("0")); macro_rules! m { ($k:expr) => { fn f() { K::$k; } } } -/* parse error: expected identifier */ +/* parse error: expected identifier, `self`, `super`, `crate`, or `Self` */ /* parse error: expected SEMICOLON */ /* parse error: expected SEMICOLON */ /* parse error: expected expression, item or let statement */ diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index c402c498553b..fe6b904bd889 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -307,13 +307,49 @@ fn name(p: &mut Parser<'_>) { name_r(p, TokenSet::EMPTY); } -fn name_ref(p: &mut Parser<'_>) { - if p.at(IDENT) { +fn name_ref_or_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![self]) { let m = p.start(); - p.bump(IDENT); + p.bump_any(); m.complete(p, NAME_REF); } else { - p.err_and_bump("expected identifier"); + p.err_and_bump("expected identifier or `self`"); + } +} + +fn name_ref_or_upper_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![Self]) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier or `Self`"); + } +} + +const PATH_NAME_REF_KINDS: TokenSet = + TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]); + +fn name_ref_mod_path(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_KINDS) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier, `self`, `super`, `crate`, or `Self`"); + } +} + +const PATH_NAME_REF_OR_INDEX_KINDS: TokenSet = + PATH_NAME_REF_KINDS.union(TokenSet::new(&[INT_NUMBER])); + +fn name_ref_mod_path_or_index(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected integer, identifier, `self`, `super`, `crate`, or `Self`"); } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 349bce09390e..3b3f11be1307 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -449,7 +449,9 @@ fn postfix_dot_expr( let nth1 = if FLOAT_RECOVERY { 0 } else { 1 }; let nth2 = if FLOAT_RECOVERY { 1 } else { 2 }; - if p.nth(nth1) == IDENT && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) { + if PATH_NAME_REF_KINDS.contains(p.nth(nth1)) + && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) + { return Ok(method_call_expr::(p, lhs)); } @@ -510,21 +512,26 @@ fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { // y.bar::(1, 2,); // x.0.0.call(); // x.0. call(); +// x.0() // } fn method_call_expr( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> CompletedMarker { if FLOAT_RECOVERY { - assert!(p.nth(0) == IDENT && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); + assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); } else { - assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); + assert!( + p.at(T![.]) + && PATH_NAME_REF_KINDS.contains(p.nth(1)) + && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) + ); } let m = lhs.precede(p); if !FLOAT_RECOVERY { p.bump(T![.]); } - name_ref(p); + name_ref_mod_path(p); generic_args::opt_generic_arg_list_expr(p); if p.at(T!['(']) { arg_list(p); @@ -543,6 +550,8 @@ fn method_call_expr( // test field_expr // fn foo() { +// x.self; +// x.Self; // x.foo; // x.0.bar; // x.0.1; @@ -560,8 +569,8 @@ fn field_expr( if !FLOAT_RECOVERY { p.bump(T![.]); } - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + name_ref_mod_path_or_index(p); } else if p.at(FLOAT_NUMBER) { return match p.split_float(m) { (true, m) => { @@ -679,34 +688,37 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { IDENT | INT_NUMBER if p.nth_at(1, T![::]) => { // test_err record_literal_missing_ellipsis_recovery // fn main() { - // S { S::default() } + // S { S::default() }; + // S { 0::default() }; // } m.abandon(p); p.expect(T![..]); expr(p); } + IDENT | INT_NUMBER if p.nth_at(1, T![..]) => { + // test_err record_literal_before_ellipsis_recovery + // fn main() { + // S { field ..S::default() } + // S { 0 ..S::default() } + // } + name_ref_or_index(p); + p.error("expected `:`"); + m.complete(p, RECORD_EXPR_FIELD); + } IDENT | INT_NUMBER => { - if p.nth_at(1, T![..]) { - // test_err record_literal_before_ellipsis_recovery - // fn main() { - // S { field ..S::default() } - // } + // test_err record_literal_field_eq_recovery + // fn main() { + // S { field = foo } + // S { 0 = foo } + // } + if p.nth_at(1, T![:]) { name_ref_or_index(p); - p.error("expected `:`"); - } else { - // test_err record_literal_field_eq_recovery - // fn main() { - // S { field = foo } - // } - if p.nth_at(1, T![:]) { - name_ref_or_index(p); - p.bump(T![:]); - } else if p.nth_at(1, T![=]) { - name_ref_or_index(p); - p.err_and_bump("expected `:`"); - } - expr(p); + p.bump(T![:]); + } else if p.nth_at(1, T![=]) { + name_ref_or_index(p); + p.err_and_bump("expected `:`"); } + expr(p); m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 97e0392ce157..cd2ce59f6277 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -259,13 +259,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option { type_(p); p.expect(T![,]); while !p.at(EOF) && !p.at(T![')']) { - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); - // } else if p.at(FLOAT_NUMBER) { - // FIXME: needs float hack - } else { - p.err_and_bump("expected field name or number"); - } + name_ref_mod_path_or_index(p); if !p.at(T![')']) { p.expect(T![.]); } @@ -465,9 +459,9 @@ fn parse_clobber_abi(p: &mut Parser<'_>) { fn parse_reg(p: &mut Parser<'_>) { p.expect(T!['(']); - if p.at(T![ident]) { + if p.at_ts(PATH_NAME_REF_KINDS) { let m = p.start(); - name_ref(p); + name_ref_mod_path(p); m.complete(p, ASM_REG_SPEC); } else if p.at(T![string]) { let m = p.start(); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index 737010985b23..c7d8040b24ee 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -59,9 +59,9 @@ pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { // test macro_inside_generic_arg // type A = Foo; - IDENT => { + k if PATH_NAME_REF_KINDS.contains(k) => { let m = p.start(); - name_ref(p); + name_ref_mod_path(p); paths::opt_path_type_args(p); match p.current() { T![=] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 92311238c23a..08b23cd92a68 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -145,6 +145,9 @@ fn type_bound(p: &mut Parser<'_>) -> bool { T![for] => types::for_type(p, false), // test precise_capturing // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} + + // test_err precise_capturing_invalid + // type T = impl use; T![use] if p.nth_at(1, T![<]) => { p.bump_any(); let m = p.start(); @@ -156,14 +159,10 @@ fn type_bound(p: &mut Parser<'_>) -> bool { || "expected identifier or lifetime".into(), TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]), |p| { - if p.at(T![Self]) { - let m = p.start(); - p.bump(T![Self]); - m.complete(p, NAME_REF); - } else if p.at(LIFETIME_IDENT) { + if p.at(LIFETIME_IDENT) { lifetime(p); } else { - name_ref(p); + name_ref_or_upper_self(p); } true }, 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 7d98499008dd..8ece5af527d9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -254,22 +254,16 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke // test extern_crate // extern crate foo; +// extern crate self; fn extern_crate(p: &mut Parser<'_>, m: Marker) { p.bump(T![extern]); p.bump(T![crate]); - if p.at(T![self]) { - // test extern_crate_self - // extern crate self; - let m = p.start(); - p.bump(T![self]); - m.complete(p, NAME_REF); - } else { - name_ref(p); - } + name_ref_or_self(p); // test extern_crate_rename // extern crate foo as bar; + // extern crate self as bar; opt_rename(p); p.expect(T![;]); m.complete(p, EXTERN_CRATE); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index b3652f7cd3f8..3410505cd46d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -107,37 +107,32 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { - name_ref(p); - opt_path_args(p, mode); - } + if p.at_ts(PATH_NAME_REF_KINDS) { // test crate_path // use crate::foo; - T![self] | T![super] | T![crate] | T![Self] => { - let m = p.start(); - p.bump_any(); - m.complete(p, NAME_REF); - } - _ => { - let recover_set = match mode { - Mode::Use => items::ITEM_RECOVERY_SET, - Mode::Attr => { - items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) - } - Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), - Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, - Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, - }; - empty &= p.err_recover("expected identifier", recover_set); - if empty { - // test_err empty_segment - // use crate::; - m.abandon(p); - return None; + name_ref_mod_path(p); + opt_path_args(p, mode); + } else { + let recover_set = match mode { + Mode::Use => items::ITEM_RECOVERY_SET, + Mode::Attr => { + items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) } + Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), + Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, + Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, + }; + empty &= p.err_recover( + "expected identifier, `self`, `super`, `crate`, or `Self`", + recover_set, + ); + if empty { + // test_err empty_segment + // use crate::; + m.abandon(p); + return None; } - }; + } } Some(m.complete(p, PATH_SEGMENT)) } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 6d114037bf9b..f9486f53c250 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -210,10 +210,6 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_rename.rs"); } #[test] - fn extern_crate_self() { - run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_self.rs"); - } - #[test] fn field_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/field_expr.rs"); } #[test] fn fn_() { run_and_expect_no_errors("test_data/parser/inline/ok/fn_.rs"); } @@ -774,6 +770,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs"); } #[test] + fn precise_capturing_invalid() { + run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs"); + } + #[test] fn pub_expr() { run_and_expect_errors("test_data/parser/inline/err/pub_expr.rs"); } #[test] fn record_literal_before_ellipsis_recovery() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast index cf455934e91d..7273c98456ee 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast @@ -13,4 +13,4 @@ SOURCE_FILE ERROR INT_NUMBER "92" SEMICOLON ";" -error 9: expected identifier +error 9: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast index 7ef1eb98fcd9..47daaf7b3b3e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast @@ -115,10 +115,10 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 30: expected identifier +error 30: expected identifier, `self`, `super`, `crate`, or `Self` error 31: expected COMMA error 37: expected expression -error 75: expected identifier +error 75: expected identifier, `self`, `super`, `crate`, or `Self` error 76: expected SEMICOLON error 82: expected expression error 83: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast index cd5aa680c656..755b20bb271f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast @@ -98,7 +98,7 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 25: expected identifier +error 25: expected identifier, `self`, `super`, `crate`, or `Self` error 39: expected COMMA error 39: expected expression error 55: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 681ca6b6e05a..172bc099b58d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -11,4 +11,4 @@ SOURCE_FILE IDENT "S" SEMICOLON ";" WHITESPACE "\n" -error 4: expected identifier +error 4: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast index b03f5ad9f7ea..7f256218eff3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast @@ -11,4 +11,4 @@ SOURCE_FILE COLON2 "::" SEMICOLON ";" WHITESPACE "\n" -error 11: expected identifier +error 11: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast index 926dd50fc859..b5c16e0798cc 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -66,18 +66,18 @@ SOURCE_FILE EQ "=" R_BRACK "]" WHITESPACE "\n" -error 3: expected identifier +error 3: expected identifier, `self`, `super`, `crate`, or `Self` error 11: expected expression error 11: expected expression -error 20: expected identifier -error 28: expected identifier +error 20: expected identifier, `self`, `super`, `crate`, or `Self` +error 28: expected identifier, `self`, `super`, `crate`, or `Self` error 30: expected expression error 30: expected expression error 41: expected L_PAREN -error 41: expected identifier +error 41: expected identifier, `self`, `super`, `crate`, or `Self` error 41: expected R_PAREN error 52: expected L_PAREN -error 52: expected identifier +error 52: expected identifier, `self`, `super`, `crate`, or `Self` error 54: expected expression error 54: expected expression error 54: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast new file mode 100644 index 000000000000..5ae184c5febc --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast @@ -0,0 +1,28 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + IMPL_TRAIT_TYPE + IMPL_KW "impl" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + USE_KW "use" + USE_BOUND_GENERIC_ARGS + L_ANGLE "<" + ERROR + SELF_KW "self" + COMMA "," + WHITESPACE " " + ERROR + INT_NUMBER "1" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" +error 18: expected identifier or `Self` +error 24: expected identifier or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs new file mode 100644 index 000000000000..3180338d33f9 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs @@ -0,0 +1 @@ +type T = impl use; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast index 741b7845e7f1..08ae906421c3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast @@ -12,6 +12,38 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + DOT2 ".." + CALL_EXPR + PATH_EXPR + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +55,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " DOT2 ".." CALL_EXPR @@ -47,3 +79,6 @@ SOURCE_FILE WHITESPACE "\n" error 25: expected `:` error 25: expected COMMA +error 42: expected SEMICOLON +error 52: expected `:` +error 52: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs index a4e5b2f69336..65398ccb88e5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field ..S::default() } + S { 0 ..S::default() } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast index ad4deeb0b67c..ad3b6f208e66 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast @@ -12,6 +12,31 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + ERROR + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +48,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " ERROR EQ "=" @@ -39,3 +64,5 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 26: expected `:` +error 33: expected SEMICOLON +error 44: expected `:` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs index 1eb1aa9b9264..9ddc46e0dafc 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field = foo } + S { 0 = foo } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast index 0c5b618e6f05..9cd07d2ea389 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast @@ -12,32 +12,70 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + CALL_EXPR + PATH_EXPR PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" PATH_SEGMENT NAME_REF - IDENT "S" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - R_CURLY "}" + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + ERROR + COLON ":" + ERROR + COLON ":" + RECORD_EXPR_FIELD + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" error 19: expected DOT2 +error 43: expected DOT2 +error 45: expected COMMA +error 45: expected identifier +error 46: expected COMMA +error 46: expected identifier +error 47: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs index 1b594e8ab962..a63c3c9e7c2b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { - S { S::default() } + S { S::default() }; + S { 0::default() }; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast index 0a660957d152..aa555ed2293b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast @@ -8,3 +8,12 @@ SOURCE_FILE IDENT "foo" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs index 49af74e1b748..3c498c8738f8 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs @@ -1 +1,2 @@ extern crate foo; +extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast index 5a5aca96f914..5f0a5b5bb051 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast @@ -14,3 +14,18 @@ SOURCE_FILE IDENT "bar" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + WHITESPACE " " + RENAME + AS_KW "as" + WHITESPACE " " + NAME + IDENT "bar" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs index fc76e17dda47..6d1873d659eb 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs @@ -1 +1,2 @@ extern crate foo as bar; +extern crate self as bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast deleted file mode 100644 index edea4245f20e..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast +++ /dev/null @@ -1,10 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - SELF_KW "self" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs deleted file mode 100644 index c969ed109361..000000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast index dd27dc489642..3bac226d3430 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast @@ -12,6 +12,30 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + SELF_TYPE_KW "Self" + SEMICOLON ";" + WHITESPACE "\n " EXPR_STMT FIELD_EXPR PATH_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs index 98dbe45a7ec9..b156d6f7d88f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs @@ -1,4 +1,6 @@ fn foo() { + x.self; + x.Self; x.foo; x.0.bar; x.0.1; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast index b28b8eb673a7..3245042cf245 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast @@ -101,6 +101,20 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + CALL_EXPR + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + INT_NUMBER "0" + ARG_LIST + L_PAREN "(" + R_PAREN ")" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs index 48bb6381e80b..bb54d75c19be 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs @@ -3,4 +3,5 @@ fn foo() { y.bar::(1, 2,); x.0.0.call(); x.0. call(); + x.0() } From 70380736bc8e899d012011089fdd20d3faf6f70e Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Fri, 6 Dec 2024 01:10:46 +0900 Subject: [PATCH 063/197] fix: Panic when displaying generic params with defaults --- .../crates/hir-ty/src/display.rs | 6 ++- .../crates/ide/src/hover/tests.rs | 50 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) 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 94a340fbec2c..3dfa0e97cec6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1047,10 +1047,14 @@ impl HirDisplay for Ty { ); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? if parameters.len() - impl_ > 0 { + let params_len = parameters.len(); // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes let parameters = generic_args_sans_defaults(f, Some(generic_def_id), parameters); - let without_impl = self_param as usize + type_ + const_ + lifetime; + assert!(params_len >= parameters.len()); + let defaults = params_len - parameters.len(); + let without_impl = + self_param as usize + type_ + const_ + lifetime - defaults; // parent's params (those from enclosing impl or trait, if any). let (fn_params, parent_params) = parameters.split_at(without_impl + impl_); 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 0986d5542cd4..1c08514a6721 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -9416,3 +9416,53 @@ fn f "#]], ); } + +#[test] +fn issue_18613() { + check( + r#" +fn main() { + struct S(); + let x$0 = S::<()>; +}"#, + expect![[r#" + *x* + + ```rust + let x: fn S<()>() -> S<()> + ``` + + --- + + size = 0, align = 1 + "#]], + ); + + check( + r#" +pub struct Global; +pub struct Box(T, A); + +impl Box { + pub fn new(x: T) -> Self { loop {} } +} + +pub struct String; + +fn main() { + let box_value$0 = Box::new(); +} +"#, + expect![[r#" + *box_value* + + ```rust + let box_value: fn Box(String, Global) -> Box + ``` + + --- + + size = 0, align = 1 + "#]], + ); +} From 085ea34357f27b3ed8d94deb0555416e95aca8d6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: [PATCH 064/197] Parse lifetime bounds in lifetime param into TypeBoundList This mainly aids in error recovery but also makes it a bit easier to handle lifetime resolution. While doing so it also came apparent that we were not actually lowering lifetime outlives relationships within lifetime parameter declaration bounds, so this fixes that. --- .../crates/hir-def/src/item_tree/pretty.rs | 4 +- .../crates/hir-def/src/item_tree/tests.rs | 6 ++- .../crates/hir-ty/src/tests/traits.rs | 23 +++++++++ .../rust-analyzer/crates/hir/src/semantics.rs | 4 ++ .../src/completions/lifetime.rs | 36 ++++++-------- .../crates/ide-completion/src/context.rs | 5 +- .../ide-completion/src/context/analysis.rs | 17 +++---- .../rust-analyzer/crates/ide-db/src/defs.rs | 10 ---- .../crates/intern/src/symbol/symbols.rs | 1 + .../parser/src/grammar/generic_params.rs | 15 ++++-- .../parser/inline/ok/lifetime_param.rast | 6 ++- .../parser/inline/ok/precise_capturing.rast | 12 +++-- .../parser/ok/0018_struct_type_params.rast | 48 ++++++++++++------- .../parser/ok/0020_type_param_bounds.rast | 23 +++++---- 14 files changed, 125 insertions(+), 85 deletions(-) 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 0c5e3a3620a4..70bf2f13c88a 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 @@ -648,9 +648,9 @@ impl Printer<'_> { let (target, bound) = match pred { WherePredicate::TypeBound { target, bound } => (target, bound), WherePredicate::Lifetime { target, bound } => { - wln!( + w!( this, - "{}: {},", + "{}: {}", target.name.display(self.db.upcast(), edition), bound.name.display(self.db.upcast(), edition) ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 5c07369f4b5b..0f53969d6c70 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { pub(self) field: &'a &'b T, } @@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { // AstId: 9 pub(self) fn f( 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 624148cab20f..b62672d21e8e 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 @@ -1630,6 +1630,29 @@ fn test<'lifetime>( ); } +#[test] +fn lifetime_bounds() { + check_infer( + r#" +//- minicore: sized, coerce_unsized +trait Trait<'a>: Sized { + fn f(&'a self) {} +} +fn test<'a, 'b: 'a>(it: impl Trait<'a>){ + it.f(); +} +"#, + expect![[r#" + 38..42 'self': &'a Self + 44..46 '{}': () + 69..71 'it': impl Trait<'a> + 88..103 '{ it.f(); }': () + 94..96 'it': impl Trait<'a> + 94..100 'it.f()': () + "#]], + ); +} + #[test] fn error_bound_chalk() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 65470d061b37..0b09cf279269 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -2026,6 +2026,10 @@ impl SemanticsScope<'_> { ) } + pub fn generic_def(&self) -> Option { + self.resolver.generic_def().map(|id| id.into()) + } + pub fn extern_crates(&self) -> impl Iterator + '_ { self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id })) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 9efc52428eff..0692446381be 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -8,7 +8,6 @@ //! show up for normal completions, or they won't show completions other than lifetimes depending //! on the fixture input. use hir::{sym, Name, ScopeDef}; -use syntax::{ast, ToSmolStr, TokenText}; use crate::{ completions::Completions, @@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime( ctx: &CompletionContext<'_>, lifetime_ctx: &LifetimeContext, ) { - let (lp, lifetime) = match lifetime_ctx { - LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime), - LifetimeContext { - kind: LifetimeKind::LifetimeParam { is_decl: false, param }, - lifetime, - } => (Some(param), lifetime), - _ => return, + let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } = + lifetime_ctx + else { + return; }; - let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) { - (Some(lt), Some(lp)) if lp == lt.clone() => return, - (Some(_), Some(lp)) => Some(lp), - _ => None, - }; - let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text); - let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str); ctx.process_all_names_raw(&mut |name, res| { - if matches!( - res, - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) - if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr()) - ) { + if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) { acc.add_lifetime(ctx, name); } }); - if param_lifetime.is_none() { - acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + if !in_lifetime_param_bound + && def.is_some_and(|def| { + !matches!(def, hir::GenericDef::Function(_) | hir::GenericDef::Impl(_)) + }) + { + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_underscore.clone())); } } @@ -222,6 +212,8 @@ fn foo<'footime, 'lifetime: 'a$0>() {} "#, expect![[r#" lt 'footime + lt 'lifetime + lt 'static "#]], ); } 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 5b8d1c30a295..3a6617063369 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -290,15 +290,14 @@ pub(crate) struct ParamContext { /// The state of the lifetime we are completing. #[derive(Debug)] pub(crate) struct LifetimeContext { - pub(crate) lifetime: Option, pub(crate) kind: LifetimeKind, } /// The kind of lifetime we are completing. #[derive(Debug)] pub(crate) enum LifetimeKind { - LifetimeParam { is_decl: bool, param: ast::LifetimeParam }, - Lifetime, + LifetimeParam, + Lifetime { in_lifetime_param_bound: bool, def: Option }, LabelRef, LabelDef, } 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 a4e018b18000..4a678963b93c 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 @@ -562,7 +562,7 @@ fn expected_type_and_name( } fn classify_lifetime( - _sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'_, RootDatabase>, original_file: &SyntaxNode, lifetime: ast::Lifetime, ) -> Option { @@ -571,21 +571,22 @@ fn classify_lifetime( return None; } + let lifetime = + find_node_at_offset::(original_file, lifetime.syntax().text_range().start()); let kind = match_ast! { match parent { - ast::LifetimeParam(param) => LifetimeKind::LifetimeParam { - is_decl: param.lifetime().as_ref() == Some(&lifetime), - param - }, + ast::LifetimeParam(_) => LifetimeKind::LifetimeParam, ast::BreakExpr(_) => LifetimeKind::LabelRef, ast::ContinueExpr(_) => LifetimeKind::LabelRef, ast::Label(_) => LifetimeKind::LabelDef, - _ => LifetimeKind::Lifetime, + _ => { + let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def()); + LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def } + }, } }; - let lifetime = find_node_at_offset(original_file, lifetime.syntax().text_range().start()); - Some(LifetimeContext { lifetime, kind }) + Some(LifetimeContext { kind }) } fn classify_name( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index fdac4dd2efb8..5eec33636bec 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -772,16 +772,6 @@ impl NameRefClass { .map(GenericParam::LifetimeParam) .map(Definition::GenericParam) .map(NameRefClass::Definition), - // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check - // if our lifetime is in a LifetimeParam without being the constrained lifetime - _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref() - != Some(lifetime) => - { - sema.resolve_lifetime_param(lifetime) - .map(GenericParam::LifetimeParam) - .map(Definition::GenericParam) - .map(NameRefClass::Definition) - } _ => None, } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 8f79cf200790..ebc9c14059dd 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -80,6 +80,7 @@ define_symbols! { self_ = "self", Self_ = "Self", tick_static = "'static", + tick_underscore = "'_", dollar_crate = "$crate", MISSING_NAME = "[missing name]", fn_ = "fn", diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 08b23cd92a68..9d4fdbfaf2ef 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool { fn lifetime_param(p: &mut Parser<'_>, m: Marker) { assert!(p.at(LIFETIME_IDENT)); lifetime(p); - if p.at(T![:]) { + if p.eat(T![:]) { lifetime_bounds(p); } m.complete(p, LIFETIME_PARAM); @@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) { } fn lifetime_bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - while p.at(LIFETIME_IDENT) { - lifetime(p); + let marker = p.start(); + while { + if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) { + p.error("expected lifetime"); + } + + type_bound(p) + } { if !p.eat(T![+]) { break; } } + marker.complete(p, TYPE_BOUND_LIST); } // test type_param_bounds diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast index c595031f3586..315200aca21c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" PARAM_LIST L_PAREN "(" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast index f9c0a245af86..5a67cc21766c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -20,8 +22,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast index 11ebc7efb9f3..1e4eb1560954 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast @@ -96,6 +96,7 @@ SOURCE_FILE LIFETIME LIFETIME_IDENT "'a" COLON ":" + TYPE_BOUND_LIST R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -111,8 +112,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -128,10 +131,12 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" WHITESPACE " " R_ANGLE ">" SEMICOLON ";" @@ -148,13 +153,16 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -202,9 +210,11 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + PLUS "+" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -212,8 +222,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" COMMA "," R_ANGLE ">" SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast index 043a966ff978..448cf49446e4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast @@ -237,8 +237,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'d" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'d" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -246,13 +248,16 @@ SOURCE_FILE LIFETIME_IDENT "'d" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM From 64832b0ddb274bc752b1627c95fa0558d847e27d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 14:37:38 +0100 Subject: [PATCH 065/197] fix: Resolve generic parameters within use captures --- .../crates/hir-def/src/resolver.rs | 4 +- .../rust-analyzer/crates/hir/src/semantics.rs | 4 ++ .../crates/hir/src/source_analyzer.rs | 8 +++ .../rust-analyzer/crates/ide-db/src/defs.rs | 7 ++ .../rust-analyzer/crates/ide/src/rename.rs | 69 +++++++++++++++++++ 5 files changed, 90 insertions(+), 2 deletions(-) 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 0ca7070fd05f..316406c151f9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -642,9 +642,9 @@ impl Resolver { }) } - pub fn generic_params(&self) -> Option<&Arc> { + pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), + Scope::GenericParams { params, .. } => Some(&**params), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 0b09cf279269..f9d3f9d07e65 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1517,6 +1517,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax())?.resolve_path(self.db, path) } + pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { + self.analyze(name.syntax())?.resolve_use_type_arg(name) + } + pub fn resolve_mod_path( &self, scope: &SyntaxNode, 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 56ed81f053c1..4329a888b392 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -642,6 +642,14 @@ impl SourceAnalyzer { } } + pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option { + let name = name.as_name(); + self.resolver + .all_generic_params() + .find_map(|(params, parent)| params.find_type_by_name(&name, *parent)) + .map(crate::TypeParam::from) + } + pub(crate) fn resolve_path( &self, db: &dyn HirDatabase, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 5eec33636bec..932ca373020d 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -733,6 +733,12 @@ impl NameRefClass { } None }, + ast::UseBoundGenericArgs(_) => { + sema.resolve_use_type_arg(name_ref) + .map(GenericParam::TypeParam) + .map(Definition::GenericParam) + .map(NameRefClass::Definition) + }, ast::ExternCrate(extern_crate_ast) => { let extern_crate = sema.to_def(&extern_crate_ast)?; let krate = extern_crate.resolved_crate(sema.db)?; @@ -764,6 +770,7 @@ impl NameRefClass { sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition) } SyntaxKind::LIFETIME_ARG + | SyntaxKind::USE_BOUND_GENERIC_ARGS | SyntaxKind::SELF_PARAM | SyntaxKind::TYPE_BOUND | SyntaxKind::WHERE_PRED diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 665fc954d239..a9519c03b322 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -3102,6 +3102,75 @@ fn main() { let _: S; } r#" use lib::S as Baz; fn main() { let _: Baz; } +"#, + ); + } + + #[test] + fn rename_type_param_ref_in_use_bound() { + check( + "U", + r#" +fn foo() -> impl use Trait {} +"#, + r#" +fn foo() -> impl use Trait {} +"#, + ); + } + + #[test] + fn rename_type_param_in_use_bound() { + check( + "U", + r#" +fn foo() -> impl use Trait {} +"#, + r#" +fn foo() -> impl use Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_ref_in_use_bound() { + check( + "u", + r#" +fn foo<'t>() -> impl use<'t$0> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_in_use_bound() { + check( + "u", + r#" +fn foo<'t$0>() -> impl use<'t> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_parent_type_param_in_use_bound() { + check( + "U", + r#" +trait Trait { + fn foo() -> impl use Trait {} +} +"#, + r#" +trait Trait { + fn foo() -> impl use Trait {} +} "#, ); } From 59a5b38bf4ebf74be954c8804789ef2cf35350e9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 5 Dec 2024 20:25:05 +0100 Subject: [PATCH 066/197] fix: Fix parsing of dyn T in generic arg on 2015 edition --- .../crates/parser/src/grammar/generic_args.rs | 5 ++- .../crates/parser/src/grammar/types.rs | 2 +- .../parser/test_data/generated/runner.rs | 7 ++++ ...on_2015_dyn_prefix_inside_generic_arg.rast | 32 +++++++++++++++++++ ...tion_2015_dyn_prefix_inside_generic_arg.rs | 2 ++ .../parser/inline/ok/generic_arg.rast | 21 ++++++++++++ .../test_data/parser/inline/ok/generic_arg.rs | 2 +- 7 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index c7d8040b24ee..b9d5bff66301 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -45,7 +45,7 @@ pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); // test generic_arg -// type T = S; +// type T = S; pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), @@ -57,6 +57,9 @@ pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { // type ParenthesizedArgs = Foo; // type RTN = Foo; + // test edition_2015_dyn_prefix_inside_generic_arg 2015 + // type A = Foo; + T![ident] if !p.edition().at_least_2018() && types::is_dyn_weak(p) => type_arg(p), // test macro_inside_generic_arg // type A = Foo; k if PATH_NAME_REF_KINDS.contains(k) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 35198ccbe35a..0133b7d5d820 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -58,7 +58,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { } } -fn is_dyn_weak(p: &Parser<'_>) -> bool { +pub(crate) fn is_dyn_weak(p: &Parser<'_>) -> bool { const WEAK_DYN_PATH_FIRST: TokenSet = TokenSet::new(&[ IDENT, T![self], diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index f9486f53c250..0beaf1ae3a50 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -190,6 +190,13 @@ mod ok { ); } #[test] + fn edition_2015_dyn_prefix_inside_generic_arg() { + run_and_expect_no_errors_with_edition( + "test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs", + crate::Edition::Edition2015, + ); + } + #[test] fn effect_blocks() { run_and_expect_no_errors("test_data/parser/inline/ok/effect_blocks.rs"); } #[test] fn exclusive_range_pat() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast new file mode 100644 index 000000000000..24e671b34388 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast @@ -0,0 +1,32 @@ +SOURCE_FILE + TYPE_ALIAS + COMMENT "// 2015" + WHITESPACE "\n" + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs new file mode 100644 index 000000000000..84cece5748da --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs @@ -0,0 +1,2 @@ +// 2015 +type A = Foo; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast index 5a01f154bad4..e32cf085657f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast @@ -20,6 +20,27 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "i32" + COMMA "," + WHITESPACE " " + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + COMMA "," + WHITESPACE " " + TYPE_ARG + FN_PTR_TYPE + FN_KW "fn" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs index f2ccc558bb5d..cf991b5b366a 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs @@ -1 +1 @@ -type T = S; +type T = S; From 3db9b1d943f7a665ea98a6dab40ece33375f4f99 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 05:53:44 +0100 Subject: [PATCH 067/197] fix: Fix parser getting stuck for bad asm expressions --- .../parser/src/grammar/expressions/atom.rs | 18 +++++-- .../parser/test_data/generated/runner.rs | 2 + .../parser/inline/err/bad_asm_expr.rast | 50 +++++++++++++++++++ .../parser/inline/err/bad_asm_expr.rs | 5 ++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index cd2ce59f6277..407320e1d082 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -345,10 +345,7 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { name(p); p.bump(T![=]); allow_templates = false; - true - } else { - false - }; + } let op = p.start(); let dir_spec = p.start(); @@ -399,6 +396,19 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option { op.abandon(p); op_n.abandon(p); p.err_and_bump("expected asm operand"); + + // improves error recovery and handles err_and_bump recovering from `{` which gets + // the parser stuck here + if p.at(T!['{']) { + // test_err bad_asm_expr + // fn foo() { + // builtin#asm( + // label crashy = { return; } + // ); + // } + expr(p); + } + if p.at(T!['}']) { break; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index f9486f53c250..c4ffc6cadc82 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -704,6 +704,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/async_without_semicolon.rs"); } #[test] + fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); } + #[test] fn comma_after_functional_update_syntax() { run_and_expect_errors( "test_data/parser/inline/err/comma_after_functional_update_syntax.rs", diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast new file mode 100644 index 000000000000..306446e64dd4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast @@ -0,0 +1,50 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + WHITESPACE "\n " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "label" + WHITESPACE " " + NAME + IDENT "crashy" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 41: expected COMMA +error 50: expected asm operand diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs new file mode 100644 index 000000000000..6056f925e339 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs @@ -0,0 +1,5 @@ +fn foo() { + builtin#asm( + label crashy = { return; } + ); +} From 069fb0f475c6e7398e4ef75c3f765415197707aa Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 4 Nov 2024 11:03:36 +0100 Subject: [PATCH 068/197] Make bracket typing handler work on more things --- .../rust-analyzer/crates/ide/src/typing.rs | 323 +++++++++++------- .../crates/rust-analyzer/src/config.rs | 2 +- .../docs/user/generated_config.adoc | 2 +- .../rust-analyzer/editors/code/package.json | 2 +- .../rust-analyzer/editors/code/src/client.ts | 2 +- 5 files changed, 200 insertions(+), 131 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 9bb5de9f2e3f..5840719ff68e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -16,11 +16,11 @@ mod on_enter; use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use syntax::{ algo::{ancestors_at_offset, find_node_at_offset}, ast::{self, edit::IndentLevel, AstToken}, - AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, + AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, }; use ide_db::text_edit::TextEdit; @@ -47,6 +47,7 @@ struct ExtendedTextEdit { // - typing `.` in a chain method call auto-indents // - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression // - typing `{` in a use item adds a closing `}` in the right place +// - typing `>` to complete a return type `->` will insert a whitespace after it // // VS Code:: // @@ -66,55 +67,65 @@ pub(crate) fn on_char_typed( if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { return None; } - let file = &db.parse(EditionedFileId::current_edition(position.file_id)); - if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) { + // FIXME: We need to figure out the edition of the file here, but that means hitting the + // database for more than just parsing the file which is bad. + // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily + // causing the editor to feel sluggish! + let edition = Edition::CURRENT_FIXME; + let file = &db.parse(EditionedFileId::new(position.file_id, edition)); + let char_matches_position = + file.tree().syntax().text().char_at(position.offset) == Some(char_typed); + if !stdx::always!(char_matches_position) { return None; } - let edit = on_char_typed_inner(file, position.offset, char_typed)?; + + let edit = on_char_typed_(file, position.offset, char_typed, edition)?; + let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); sc.is_snippet = edit.is_snippet; Some(sc) } -fn on_char_typed_inner( +fn on_char_typed_( file: &Parse, offset: TextSize, char_typed: char, + edition: Edition, ) -> Option { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - let conv = |text_edit: Option| { - Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) - }; match char_typed { - '.' => conv(on_dot_typed(&file.tree(), offset)), - '=' => conv(on_eq_typed(&file.tree(), offset)), - '<' => on_left_angle_typed(&file.tree(), offset), - '>' => conv(on_right_angle_typed(&file.tree(), offset)), - '{' => conv(on_opening_bracket_typed(file, offset, '{')), - '(' => conv(on_opening_bracket_typed(file, offset, '(')), + '.' => on_dot_typed(&file.tree(), offset), + '=' => on_eq_typed(&file.tree(), offset), + '>' => on_right_angle_typed(&file.tree(), offset), + '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), _ => None, } + .map(conv) } -/// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a +fn conv(edit: TextEdit) -> ExtendedTextEdit { + ExtendedTextEdit { edit, is_snippet: false } +} + +/// Inserts a closing delimiter when the user types an opening bracket, wrapping an existing expression in a /// block, or a part of a `use` item (for `{`). -fn on_opening_bracket_typed( +fn on_opening_delimiter_typed( file: &Parse, offset: TextSize, opening_bracket: char, + edition: Edition, ) -> Option { - let (closing_bracket, expected_ast_bracket) = match opening_bracket { - '{' => ('}', SyntaxKind::L_CURLY), - '(' => (')', SyntaxKind::L_PAREN), + type FilterFn = fn(SyntaxKind) -> bool; + let (closing_bracket, expected_ast_bracket, allowed_kinds) = match opening_bracket { + '{' => ('}', SyntaxKind::L_CURLY, &[ast::Expr::can_cast as FilterFn] as &[FilterFn]), + '(' => ( + ')', + SyntaxKind::L_PAREN, + &[ast::Expr::can_cast, ast::Pat::can_cast, ast::Type::can_cast] as &[FilterFn], + ), + '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, }; - if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some(opening_bracket)) { - return None; - } - let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; if brace_token.kind() != expected_ast_bracket { return None; @@ -125,58 +136,53 @@ fn on_opening_bracket_typed( if !stdx::always!(range.len() == TextSize::of(opening_bracket)) { return None; } - // FIXME: Edition - let file = file.reparse(range, "", span::Edition::CURRENT_FIXME); + let reparsed = file.reparse(range, "", edition).tree(); - if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) { + if let Some(edit) = + on_delimited_node_typed(&reparsed, offset, opening_bracket, closing_bracket, allowed_kinds) + { return Some(edit); } - if closing_bracket == '}' { - if let Some(edit) = brace_use_path(&file.tree(), offset) { - return Some(edit); - } + match opening_bracket { + '{' => on_left_brace_typed(&reparsed, offset), + '<' => on_left_angle_typed(&file.tree(), &reparsed, offset), + _ => None, + } +} + +fn on_left_brace_typed(reparsed: &SourceFile, offset: TextSize) -> Option { + let segment: ast::PathSegment = find_node_at_offset(reparsed.syntax(), offset)?; + if segment.syntax().text_range().start() != offset { + return None; } - return None; + let tree: ast::UseTree = find_node_at_offset(reparsed.syntax(), offset)?; - fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option { - let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; - if segment.syntax().text_range().start() != offset { - return None; - } + Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +} - let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; +fn on_delimited_node_typed( + reparsed: &SourceFile, + offset: TextSize, + opening_bracket: char, + closing_bracket: char, + kinds: &[fn(SyntaxKind) -> bool], +) -> Option { + let t = reparsed.syntax().token_at_offset(offset).right_biased()?; + let (filter, node) = t + .parent_ancestors() + .take_while(|n| n.text_range().start() == offset) + .find_map(|n| kinds.iter().find(|&kind_filter| kind_filter(n.kind())).zip(Some(n)))?; + let mut node = node + .ancestors() + .take_while(|n| n.text_range().start() == offset && filter(n.kind())) + .last()?; - Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) - } - - fn bracket_expr( - file: &SourceFile, - offset: TextSize, - opening_bracket: char, - closing_bracket: char, - ) -> Option { - let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; - if expr.syntax().text_range().start() != offset { - return None; - } - - // Enclose the outermost expression starting at `offset` - while let Some(parent) = expr.syntax().parent() { - if parent.text_range().start() != expr.syntax().text_range().start() { - break; - } - - match ast::Expr::cast(parent) { - Some(parent) => expr = parent, - None => break, - } - } - - if let Some(parent) = expr.syntax().parent().and_then(ast::Expr::cast) { - let mut node = expr.syntax().clone(); - let all_prev_sib_attr = loop { + if let Some(parent) = node.parent().filter(|it| filter(it.kind())) { + let all_prev_sib_attr = { + let mut node = node.clone(); + loop { match node.prev_sibling() { Some(sib) if sib.kind().is_trivia() || sib.kind() == SyntaxKind::ATTR => { node = sib @@ -184,21 +190,20 @@ fn on_opening_bracket_typed( Some(_) => break false, None => break true, }; - }; - - if all_prev_sib_attr { - expr = parent; } + }; + + if all_prev_sib_attr { + node = parent; } - - // Insert the closing bracket right after the expression. - Some(TextEdit::insert( - expr.syntax().text_range().end() + TextSize::of(opening_bracket), - closing_bracket.to_string(), - )) } -} + // Insert the closing bracket right after the node. + Some(TextEdit::insert( + node.text_range().end() + TextSize::of(opening_bracket), + closing_bracket.to_string(), + )) +} /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. @@ -342,14 +347,15 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { } /// Add closing `>` for generic arguments/parameters. -fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('<')) { - return None; - } +fn on_left_angle_typed( + file: &SourceFile, + reparsed: &SourceFile, + offset: TextSize, +) -> Option { + let file_text = reparsed.syntax().text(); - // Find the next non-whitespace char in the line. - let mut next_offset = offset + TextSize::of('<'); + // Find the next non-whitespace char in the line, check if its a `>` + let mut next_offset = offset; while file_text.char_at(next_offset) == Some(' ') { next_offset += TextSize::of(' ') } @@ -357,23 +363,14 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option".to_owned()), - is_snippet: true, - }); - } - } - - if ancestors_at_offset(file.syntax(), offset).any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) - }) { - Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_owned()), - is_snippet: true, + if ancestors_at_offset(file.syntax(), offset) + .take_while(|n| !ast::Item::can_cast(n.kind())) + .any(|n| { + ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) }) + { + // Insert the closing bracket right after + Some(TextEdit::insert(offset + TextSize::of('<'), '>'.to_string())) } else { None } @@ -411,7 +408,7 @@ mod tests { let edit = TextEdit::insert(offset, char_typed.to_string()); edit.apply(&mut before); let parse = SourceFile::parse(&before, span::Edition::CURRENT_FIXME); - on_char_typed_inner(&parse, offset, char_typed).map(|it| { + on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT_FIXME).map(|it| { it.apply(&mut before); before.to_string() }) @@ -426,7 +423,7 @@ mod tests { fn type_char_noop(char_typed: char, ra_fixture_before: &str) { let file_change = do_type_char(char_typed, ra_fixture_before); - assert!(file_change.is_none()) + assert_eq!(file_change, None) } #[test] @@ -1066,6 +1063,81 @@ fn f() { ); } + #[test] + fn adds_closing_parenthesis_for_pat() { + type_char( + '(', + r#" +fn f() { match () { $0() => () } } +"#, + r#" +fn f() { match () { (()) => () } } +"#, + ); + type_char( + '(', + r#" +fn f($0n: ()) {} +"#, + r#" +fn f((n): ()) {} +"#, + ); + } + + #[test] + fn adds_closing_parenthesis_for_ty() { + type_char( + '(', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: (())) {} +"#, + ); + type_char( + '(', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: (a::b::::c)) {} +"#, + ); + } + + #[test] + fn adds_closing_angles_for_ty() { + type_char( + '<', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: <()>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: $0a::b::::c) {} +"#, + r#" +fn f(n: ::c>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: a$0b::::c) {} +"#, + r#" +fn f(n: a<>b::::c) {} +"#, + ); + } + #[test] fn parenthesis_noop_in_string_literal() { // Regression test for #9351 @@ -1154,6 +1226,12 @@ use $0Thing as _; type_char_noop( '(', r#" +use some::pa$0th::to::Item; + "#, + ); + type_char_noop( + '<', + r#" use some::pa$0th::to::Item; "#, ); @@ -1170,7 +1248,7 @@ fn foo() { "#, r#" fn foo() { - bar::<$0> + bar::<> } "#, ); @@ -1184,7 +1262,7 @@ fn foo(bar: &[u64]) { "#, r#" fn foo(bar: &[u64]) { - bar.iter().collect::<$0>(); + bar.iter().collect::<>(); } "#, ); @@ -1198,7 +1276,7 @@ fn foo(bar: &[u64]) { fn foo$0() {} "#, r#" -fn foo<$0>() {} +fn foo<>() {} "#, ); type_char( @@ -1207,7 +1285,7 @@ fn foo<$0>() {} fn foo$0 "#, r#" -fn foo<$0> +fn foo<> "#, ); type_char( @@ -1216,7 +1294,7 @@ fn foo<$0> struct Foo$0 {} "#, r#" -struct Foo<$0> {} +struct Foo<> {} "#, ); type_char( @@ -1225,7 +1303,7 @@ struct Foo<$0> {} struct Foo$0(); "#, r#" -struct Foo<$0>(); +struct Foo<>(); "#, ); type_char( @@ -1234,7 +1312,7 @@ struct Foo<$0>(); struct Foo$0 "#, r#" -struct Foo<$0> +struct Foo<> "#, ); type_char( @@ -1243,7 +1321,7 @@ struct Foo<$0> enum Foo$0 "#, r#" -enum Foo<$0> +enum Foo<> "#, ); type_char( @@ -1252,7 +1330,7 @@ enum Foo<$0> trait Foo$0 "#, r#" -trait Foo<$0> +trait Foo<> "#, ); type_char( @@ -1261,16 +1339,7 @@ trait Foo<$0> type Foo$0 = Bar; "#, r#" -type Foo<$0> = Bar; - "#, - ); - type_char( - '<', - r#" -impl$0 Foo {} - "#, - r#" -impl<$0> Foo {} +type Foo<> = Bar; "#, ); type_char( @@ -1279,7 +1348,7 @@ impl<$0> Foo {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); type_char( @@ -1288,7 +1357,7 @@ impl Foo<$0> {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); } 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 aa9f919679de..392bfbf15fe1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -309,7 +309,7 @@ config_data! { signatureInfo_documentation_enable: bool = true, /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = Some("<".to_owned()), + typing_excludeChars: Option = None, /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 96a2a5a27d3c..a3172c7ca2c4 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: + -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 7529651ca7a0..68c61e4bf622 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2607,7 +2607,7 @@ "properties": { "rust-analyzer.typing.excludeChars": { "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": "<", + "default": null, "type": [ "null", "string" diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index eac7b849fdb9..4ce19f5c6650 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -324,7 +324,7 @@ class ExperimentalFeatures implements lc.StaticFeature { } fillClientCapabilities(capabilities: lc.ClientCapabilities): void { capabilities.experimental = { - snippetTextEdit: true, + snippetTextEdit: false, codeActionGroup: true, hoverActions: true, serverStatusNotification: true, From 2c91563eb5f0556696f6cf3192c9757474723a3e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 4 Dec 2024 09:00:08 +0100 Subject: [PATCH 069/197] Add implict unsafety inlay hints for extern blocks --- .../crates/ide/src/inlay_hints.rs | 21 ++- .../ide/src/inlay_hints/extern_block.rs | 138 ++++++++++++++++++ 2 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs 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 1ae8bfa9b6e1..aa99ba49bc83 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 closing_brace; mod closure_captures; mod closure_ret; mod discriminant; +mod extern_block; mod generic_param; mod implicit_drop; mod implicit_static; @@ -116,6 +117,7 @@ pub(crate) fn inlay_hints( #[derive(Default)] struct InlayHintCtx { lifetime_stacks: Vec>, + extern_block_parent: Option, } pub(crate) fn inlay_hints_resolve( @@ -174,12 +176,18 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent) -> Option { if ast::AnyHasGenericParams::can_cast(n.kind()) { ctx.lifetime_stacks.pop(); } + if ast::ExternBlock::can_cast(n.kind()) { + ctx.extern_block_parent = None; + } None } } @@ -234,12 +242,20 @@ fn hints( ast::Item(it) => match it { ast::Item::Fn(it) => { implicit_drop::hints(hints, famous_defs, config, file_id, &it); + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block); + } lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it) }, - // static type elisions - ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)), + ast::Item::Static(it) => { + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block); + } + implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)) + }, ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)), ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), + ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it), _ => None, }, // FIXME: trait object type elisions @@ -368,6 +384,7 @@ pub enum InlayKind { Type, Drop, RangeExclusive, + ExternUnsafety, } #[derive(Debug, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs new file mode 100644 index 000000000000..4cc4925cda6f --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -0,0 +1,138 @@ +//! Extern block hints +use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; +use span::EditionedFileId; +use syntax::{ast, AstNode, SyntaxToken}; + +use crate::{InlayHint, InlayHintsConfig}; + +pub(super) fn extern_block_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + extern_block: ast::ExternBlock, +) -> Option<()> { + if extern_block.unsafe_token().is_some() { + return None; + } + let abi = extern_block.abi()?; + acc.push(InlayHint { + range: abi.syntax().text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())), + resolve_parent: Some(extern_block.syntax().text_range()), + }); + Some(()) +} + +pub(super) fn fn_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + fn_: &ast::Fn, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = fn_.safe_token().is_none() && fn_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let fn_ = fn_.fn_token()?; + acc.push(item_hint(extern_block, fn_)); + Some(()) +} + +pub(super) fn static_hints( + acc: &mut Vec, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + static_: &ast::Static, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = static_.safe_token().is_none() && static_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let static_ = static_.static_token()?; + acc.push(item_hint(extern_block, static_)); + Some(()) +} + +fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { + InlayHint { + range: token.text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: { + let mut builder = TextEdit::builder(); + builder.insert(token.text_range().start(), "unsafe ".to_owned()); + if extern_block.unsafe_token().is_none() { + if let Some(abi) = extern_block.abi() { + builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); + } + } + Some(builder.finish()) + }, + resolve_parent: Some(extern_block.syntax().text_range()), + } +} + +#[cfg(test)] +mod tests { + use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG}; + + #[test] + fn unadorned() { + check_with_config( + DISABLED_CONFIG, + r#" + extern "C" { +//^^^^^^^^^^ unsafe + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } + + #[test] + fn adorned() { + check_with_config( + DISABLED_CONFIG, + r#" +unsafe extern "C" { + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } +} From a086560b23fd1523bbb88a33b66a95a1f04b9c3c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 15:00:09 +0100 Subject: [PATCH 070/197] Improve heuristics for on typing semicolon insertion --- .../rust-analyzer/crates/ide/src/typing.rs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 5840719ff68e..cfa1d6ff0319 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -15,6 +15,8 @@ mod on_enter; +use std::iter; + use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; use span::{Edition, EditionedFileId}; use syntax::{ @@ -120,7 +122,8 @@ fn on_opening_delimiter_typed( '(' => ( ')', SyntaxKind::L_PAREN, - &[ast::Expr::can_cast, ast::Pat::can_cast, ast::Type::can_cast] as &[FilterFn], + &[ast::Expr::can_cast as FilterFn, ast::Pat::can_cast, ast::Type::can_cast] + as &[FilterFn], ), '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, @@ -208,7 +211,18 @@ fn on_delimited_node_typed( /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) { + let text = file.syntax().text(); + if !stdx::always!(text.char_at(offset) == Some('=')) { + return None; + } + + let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) + .filter_map(|offset| text.char_at(offset)) + .find(|&c| !c.is_whitespace() || c == '\n') + == Some('n'); + // don't attempt to add `;` if there is a newline after the `=`, the intent is likely to write + // out the expression afterwards! + if has_newline { return None; } @@ -466,6 +480,15 @@ fn foo() { let foo =$0 let bar = 1; } +", + ); + type_char_noop( + '=', + r" +fn foo() { + let foo =$0 + 1 + 1 +} ", ); } From a5855516f44e494e0e21af3fb43a25ba04e75f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 5 Dec 2024 10:33:49 +0100 Subject: [PATCH 071/197] CI: move `dist-arm-linux` to an ARM runner --- .../{host-x86_64 => host-aarch64}/dist-arm-linux/Dockerfile | 2 +- .../dist-arm-linux/arm-linux-gnueabi.defconfig | 0 src/ci/github-actions/jobs.yml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/ci/docker/{host-x86_64 => host-aarch64}/dist-arm-linux/Dockerfile (94%) rename src/ci/docker/{host-x86_64 => host-aarch64}/dist-arm-linux/arm-linux-gnueabi.defconfig (100%) diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-arm-linux/Dockerfile similarity index 94% rename from src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile rename to src/ci/docker/host-aarch64/dist-arm-linux/Dockerfile index 420c42bc9d80..4a749473004e 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-arm-linux/Dockerfile @@ -19,7 +19,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig +COPY host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig b/src/ci/docker/host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig similarity index 100% rename from src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig rename to src/ci/docker/host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 2ea37c168dd3..897fdb1df4e5 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -143,7 +143,7 @@ auto: <<: *job-linux-4c - image: dist-arm-linux - <<: *job-linux-8c + <<: *job-aarch64-linux - image: dist-armhf-linux <<: *job-linux-4c From 949029753872fb411adc70a38642e33cdb9636cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 5 Dec 2024 12:41:22 +0100 Subject: [PATCH 072/197] Rename the ARM runner YAML anchor To make it more consistent with the rest of the anchors. --- src/ci/github-actions/jobs.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 897fdb1df4e5..5c3d5c5e107d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -43,7 +43,7 @@ runners: os: windows-2022-16core-64gb <<: *base-job - - &job-aarch64-linux + - &job-linux-8c-aarch64 os: ubuntu-22.04-arm64-8core-32gb envs: @@ -123,10 +123,10 @@ auto: ############################# - image: aarch64-gnu - <<: *job-aarch64-linux + <<: *job-linux-8c-aarch64 - image: aarch64-gnu-debug - <<: *job-aarch64-linux + <<: *job-linux-8c-aarch64 - image: arm-android <<: *job-linux-4c @@ -143,7 +143,7 @@ auto: <<: *job-linux-4c - image: dist-arm-linux - <<: *job-aarch64-linux + <<: *job-linux-8c-aarch64 - image: dist-armhf-linux <<: *job-linux-4c From 3fe75c7d90e9e42dbbc7c6542337a68ff9b817cf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 15:35:13 +0100 Subject: [PATCH 073/197] Add typing handler for param list pipe --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 2 + .../rust-analyzer/crates/ide/src/typing.rs | 67 +++++++++++++++---- .../crates/rust-analyzer/src/config.rs | 4 +- .../rust-analyzer/src/lsp/capabilities.rs | 17 ++--- .../docs/user/generated_config.adoc | 4 +- .../rust-analyzer/editors/code/package.json | 4 +- 6 files changed, 69 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index b43685ffeed2..c960b88a3e9d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -402,6 +402,8 @@ impl Analysis { self.with_db(|db| typing::on_enter(db, position)) } + pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS; + /// Returns an edit which should be applied after a character was typed. /// /// This is useful for some on-the-fly fixups, like adding `;` to `let =` diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index cfa1d6ff0319..3d9146cc4c7f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -32,7 +32,7 @@ use crate::SourceChange; pub(crate) use on_enter::on_enter; // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{("; +pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|"; struct ExtendedTextEdit { edit: TextEdit, @@ -99,6 +99,7 @@ fn on_char_typed_( '=' => on_eq_typed(&file.tree(), offset), '>' => on_right_angle_typed(&file.tree(), offset), '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), + '|' => on_pipe_typed(&file.tree(), offset), _ => None, } .map(conv) @@ -212,10 +213,6 @@ fn on_delimited_node_typed( // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { let text = file.syntax().text(); - if !stdx::always!(text.char_at(offset) == Some('=')) { - return None; - } - let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) .filter_map(|offset| text.char_at(offset)) .find(|&c| !c.is_whitespace() || c == '\n') @@ -308,9 +305,6 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option { /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) { - return None; - } let whitespace = file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; @@ -380,7 +374,9 @@ fn on_left_angle_typed( if ancestors_at_offset(file.syntax(), offset) .take_while(|n| !ast::Item::can_cast(n.kind())) .any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) + ast::GenericParamList::can_cast(n.kind()) + || ast::GenericArgList::can_cast(n.kind()) + || ast::UseBoundGenericArgs::can_cast(n.kind()) }) { // Insert the closing bracket right after @@ -390,12 +386,21 @@ fn on_left_angle_typed( } } +fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option { + let pipe_token = file.syntax().token_at_offset(offset).right_biased()?; + if pipe_token.kind() != SyntaxKind::PIPE { + return None; + } + if pipe_token.parent().and_then(ast::ParamList::cast)?.r_paren_token().is_some() { + return None; + } + let after_lpipe = offset + TextSize::of('|'); + Some(TextEdit::insert(after_lpipe, "|".to_owned())) +} + /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option { let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('>')) { - return None; - } let after_arrow = offset + TextSize::of('>'); if file_text.char_at(after_arrow) != Some('{') { return None; @@ -1527,6 +1532,44 @@ fn foo() { ) $0 } +"#, + ); + } + + #[test] + fn completes_pipe_param_list() { + type_char( + '|', + r#" +fn foo() { + $0 +} +"#, + r#" +fn foo() { + || +} +"#, + ); + type_char( + '|', + r#" +fn foo() { + $0 a +} +"#, + r#" +fn foo() { + || a +} +"#, + ); + type_char_noop( + '|', + r#" +fn foo() { + let $0 +} "#, ); } 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 392bfbf15fe1..0fdc48a0e7a2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -308,8 +308,8 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. - typing_excludeChars: Option = None, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. + typing_excludeChars: Option = Some('<'.to_string()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index bd496e8ddc36..82e6ae2b49c1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -72,9 +72,12 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { 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)), + document_on_type_formatting_provider: Some({ + let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars(); + DocumentOnTypeFormattingOptions { + first_trigger_character: chars.next().unwrap().to_string(), + more_trigger_character: Some(chars.map(|c| c.to_string()).collect()), + } }), selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), @@ -528,11 +531,3 @@ impl ClientCapabilities { .unwrap_or_default() } } - -fn more_trigger_character(config: &Config) -> Vec { - 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/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index a3172c7ca2c4..715f8d43adc4 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,10 +992,10 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `null`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`):: + -- -Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters. +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. -- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 68c61e4bf622..70d26c97078c 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2606,8 +2606,8 @@ "title": "typing", "properties": { "rust-analyzer.typing.excludeChars": { - "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. Setting this to a string will disable typing assists for the specified characters.", - "default": null, + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", + "default": "<", "type": [ "null", "string" From fbd671373b39918b4714dcb154748471fe559eeb Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 16 Nov 2024 20:01:05 -0500 Subject: [PATCH 074/197] fix: Properly determine `SyntaxEditor` replacement intersection Bordering replacements should not be considered intersecting --- .../rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index b769c941105b..44a1fae23beb 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -73,7 +73,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { }) .all(|(l, r)| { get_node_depth(l.target_parent()) != get_node_depth(r.target_parent()) - || l.target_range().intersect(r.target_range()).is_none() + || (l.target_range().end() <= r.target_range().start()) }); if stdx::never!( From 25c0a002ea10cec7076656547dccb8df700f3b6d Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sun, 17 Nov 2024 15:36:57 -0500 Subject: [PATCH 075/197] fix: Don't produce `ChangedAncestor` for `SyntaxToken`s --- .../crates/syntax/src/syntax_editor.rs | 48 ++++++++++++++++++- .../syntax/src/syntax_editor/edit_algo.rs | 14 ++---- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 7e5d0f27e0a0..992a847663af 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -327,7 +327,7 @@ mod tests { use crate::{ ast::{self, make, syntax_factory::SyntaxFactory}, - AstNode, + AstNode, SyntaxKind, }; use super::*; @@ -540,4 +540,50 @@ mod tests { }"#]]; expect.assert_eq(&edit.new_root.to_string()); } + + #[test] + fn test_replace_token_in_parent() { + let parent_fn = make::fn_( + None, + make::name("it"), + None, + None, + make::param_list(None, []), + make::block_expr([], Some(make::expr_unit())), + Some(make::ret_type(make::ty_unit())), + false, + false, + false, + false, + ); + + let mut editor = SyntaxEditor::new(parent_fn.syntax().clone()); + + if let Some(ret_ty) = parent_fn.ret_type() { + editor.delete(ret_ty.syntax().clone()); + + if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token() { + if token.kind().is_trivia() { + editor.delete(token); + } + } + } + + if let Some(tail) = parent_fn.body().unwrap().tail_expr() { + // FIXME: We do this because `xtask tidy` will not allow us to have trailing whitespace in the expect string. + if let Some(SyntaxElement::Token(token)) = tail.syntax().prev_sibling_or_token() { + if let SyntaxKind::WHITESPACE = token.kind() { + editor.delete(token); + } + } + editor.delete(tail.syntax().clone()); + } + + let edit = editor.finish(); + + let expect = expect![[r#" +fn it() { +}"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index 44a1fae23beb..71b69dbec1d6 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -128,13 +128,14 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { // Add to changed ancestors, if applicable match change { - Change::Insert(_, _) | Change::InsertAll(_, _) => {} - Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + Change::Replace(SyntaxElement::Node(target), _) + | Change::ReplaceWithMany(SyntaxElement::Node(target), _) => { changed_ancestors.push_back(ChangedAncestor::single(target, change_index)) } Change::ReplaceAll(range, _) => { changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index)) } + _ => (), } } @@ -304,13 +305,8 @@ enum ChangedAncestorKind { } impl ChangedAncestor { - fn single(element: &SyntaxElement, change_index: usize) -> Self { - let kind = match element { - SyntaxElement::Node(node) => ChangedAncestorKind::Single { node: node.clone() }, - SyntaxElement::Token(token) => { - ChangedAncestorKind::Single { node: token.parent().unwrap() } - } - }; + fn single(node: &SyntaxNode, change_index: usize) -> Self { + let kind = ChangedAncestorKind::Single { node: node.clone() }; Self { kind, change_index } } From 8877598a1d6fd44f569daf80444a6918012c003a Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:34:12 -0500 Subject: [PATCH 076/197] minor: Add `token` constructor to `SyntaxFactory` --- .../crates/syntax/src/ast/syntax_factory/constructors.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 8b0610940730..0d8fe4cd23ad 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, - AstNode, + AstNode, SyntaxKind, SyntaxToken, }; use super::SyntaxFactory; @@ -151,4 +151,8 @@ impl SyntaxFactory { ast } + + pub fn token(&self, kind: SyntaxKind) -> SyntaxToken { + make::token(kind) + } } From 0eed1970144b5333b7b4bc997a41e33a226a1fdd Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:16:06 -0500 Subject: [PATCH 077/197] minor: Add `expr_bin` constructor to `SyntaxFactory` --- .../src/ast/syntax_factory/constructors.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 0d8fe4cd23ad..944724ff05c1 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -80,6 +80,23 @@ impl SyntaxFactory { ast } + pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr { + let ast::Expr::BinExpr(ast) = + make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lhs.syntax().clone(), ast.lhs().unwrap().syntax().clone()); + builder.map_node(rhs.syntax().clone(), ast.rhs().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_path(&self, path: ast::Path) -> ast::Expr { let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else { unreachable!() From ff6b0205123fef6c5c73fd068576d7ac30fafb16 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:23:27 -0500 Subject: [PATCH 078/197] feat: Migrate `flip_binexpr` assist to `SyntaxEditor` --- .../ide-assists/src/handlers/flip_binexpr.rs | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs index 8b46a23f9a64..601fd29f8e7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs @@ -1,4 +1,7 @@ -use syntax::ast::{self, AstNode, BinExpr}; +use syntax::{ + ast::{self, syntax_factory::SyntaxFactory, AstNode, BinExpr}, + SyntaxKind, T, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -19,22 +22,17 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let expr = ctx.find_node_at_offset::()?; - let rhs = expr.rhs()?.syntax().clone(); - let lhs = expr.lhs()?.syntax().clone(); + let lhs = expr.lhs()?; + let rhs = expr.rhs()?; - let lhs = if let Some(bin_expr) = BinExpr::cast(lhs.clone()) { - if bin_expr.op_kind() == expr.op_kind() { - bin_expr.rhs()?.syntax().clone() - } else { - lhs - } - } else { - lhs + let lhs = match &lhs { + ast::Expr::BinExpr(bin_expr) if bin_expr.op_kind() == expr.op_kind() => bin_expr.rhs()?, + _ => lhs, }; - let op_range = expr.op_token()?.text_range(); + let op_token = expr.op_token()?; // The assist should be applied only if the cursor is on the operator - let cursor_in_range = op_range.contains_range(ctx.selection_trimmed()); + let cursor_in_range = op_token.text_range().contains_range(ctx.selection_trimmed()); if !cursor_in_range { return None; } @@ -47,13 +45,18 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add( AssistId("flip_binexpr", AssistKind::RefactorRewrite), "Flip binary expression", - op_range, - |edit| { - if let FlipAction::FlipAndReplaceOp(new_op) = action { - edit.replace(op_range, new_op); - } - edit.replace(lhs.text_range(), rhs.text()); - edit.replace(rhs.text_range(), lhs.text()); + op_token.text_range(), + |builder| { + let mut editor = builder.make_editor(&expr.syntax().parent().unwrap()); + let make = SyntaxFactory::new(); + if let FlipAction::FlipAndReplaceOp(binary_op) = action { + editor.replace(op_token, make.token(binary_op)) + }; + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + editor.replace(lhs.syntax(), rhs.syntax().clone_for_update()); + editor.replace(rhs.syntax(), lhs.syntax().clone_for_update()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } @@ -62,7 +65,7 @@ enum FlipAction { // Flip the expression Flip, // Flip the expression and replace the operator with this string - FlipAndReplaceOp(&'static str), + FlipAndReplaceOp(SyntaxKind), // Do not flip the expression DontFlip, } @@ -73,10 +76,10 @@ impl From for FlipAction { ast::BinaryOp::Assignment { .. } => FlipAction::DontFlip, ast::BinaryOp::CmpOp(ast::CmpOp::Ord { ordering, strict }) => { let rev_op = match (ordering, strict) { - (ast::Ordering::Less, true) => ">", - (ast::Ordering::Less, false) => ">=", - (ast::Ordering::Greater, true) => "<", - (ast::Ordering::Greater, false) => "<=", + (ast::Ordering::Less, true) => T![>], + (ast::Ordering::Less, false) => T![>=], + (ast::Ordering::Greater, true) => T![<], + (ast::Ordering::Greater, false) => T![<=], }; FlipAction::FlipAndReplaceOp(rev_op) } From 418ad88045b0a7862508293662eb30f5aeff4b75 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:49:19 -0500 Subject: [PATCH 079/197] feat: Migrate `flip_trait_bound` assist to `SyntaxEditor` --- .../ide-assists/src/handlers/flip_trait_bound.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs index 70b5efcb645a..03366bd8616c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs @@ -23,11 +23,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let plus = ctx.find_token_syntax_at_offset(T![+])?; // Make sure we're in a `TypeBoundList` - ast::TypeBoundList::cast(plus.parent()?)?; + let parent = ast::TypeBoundList::cast(plus.parent()?)?; let (before, after) = ( - non_trivia_sibling(plus.clone().into(), Direction::Prev)?, - non_trivia_sibling(plus.clone().into(), Direction::Next)?, + non_trivia_sibling(plus.clone().into(), Direction::Prev)?.into_node()?, + non_trivia_sibling(plus.clone().into(), Direction::Next)?.into_node()?, ); let target = plus.text_range(); @@ -35,9 +35,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op AssistId("flip_trait_bound", AssistKind::RefactorRewrite), "Flip trait bounds", target, - |edit| { - edit.replace(before.text_range(), after.to_string()); - edit.replace(after.text_range(), before.to_string()); + |builder| { + let mut editor = builder.make_editor(parent.syntax()); + editor.replace(before.clone(), after.clone_for_update()); + editor.replace(after.clone(), before.clone_for_update()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } From 806ffb7dbaa1067b6a62a98c3b239ba29fe4e9a4 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 23 Nov 2024 12:41:48 -0500 Subject: [PATCH 080/197] minor: Add `token_tree` constructor to `SyntaxFactory` --- .../src/ast/syntax_factory/constructors.rs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 944724ff05c1..54f17bd721d5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::{ ast::{self, make, HasName, HasTypeBounds}, syntax_editor::SyntaxMappingBuilder, - AstNode, SyntaxKind, SyntaxToken, + AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; use super::SyntaxFactory; @@ -169,6 +169,32 @@ impl SyntaxFactory { ast } + pub fn token_tree( + &self, + delimiter: SyntaxKind, + tt: Vec>, + ) -> ast::TokenTree { + let tt: Vec<_> = tt.into_iter().collect(); + let input: Vec<_> = tt.iter().cloned().filter_map(only_nodes).collect(); + + let ast = make::token_tree(delimiter, tt).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + input.into_iter(), + ast.token_trees_and_tokens().filter_map(only_nodes), + ); + builder.finish(&mut mapping); + } + + return ast; + + fn only_nodes(element: NodeOrToken) -> Option { + element.as_node().map(|it| it.syntax().clone()) + } + } + pub fn token(&self, kind: SyntaxKind) -> SyntaxToken { make::token(kind) } From 254198c340ba3efc0d0f2daa99af49d3582fd533 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 23 Nov 2024 12:42:49 -0500 Subject: [PATCH 081/197] feat: Migrate `flip_comma` assist to `SyntaxEditor` --- .../ide-assists/src/handlers/flip_comma.rs | 120 ++++++++++++------ 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs index af2c2c759ec7..490a9ee3c04d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs @@ -1,7 +1,8 @@ -use ide_db::base_db::SourceDatabase; -use syntax::TextSize; use syntax::{ - algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, SyntaxToken, TextRange, T, + algo::non_trivia_sibling, + ast::{self, syntax_factory::SyntaxFactory}, + syntax_editor::{Element, SyntaxMapping}, + AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxToken, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,8 +26,6 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let comma = ctx.find_token_syntax_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; - let (mut prev_text, mut next_text) = (prev.to_string(), next.to_string()); - let (mut prev_range, mut next_range) = (prev.text_range(), next.text_range()); // Don't apply a "flip" in case of a last comma // that typically comes before punctuation @@ -40,53 +39,85 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( return None; } - if let Some(parent) = comma.parent().and_then(ast::TokenTree::cast) { - // An attribute. It often contains a path followed by a token tree (e.g. `align(2)`), so we have - // to be smarter. - let prev_start = - match comma.siblings_with_tokens(Direction::Prev).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_after_token(it.as_token().unwrap()), - None => position_after_token(&parent.left_delimiter_token()?), - }; - let prev_end = prev.text_range().end(); - let next_start = next.text_range().start(); - let next_end = - match comma.siblings_with_tokens(Direction::Next).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_before_token(it.as_token().unwrap()), - None => position_before_token(&parent.right_delimiter_token()?), - }; - prev_range = TextRange::new(prev_start, prev_end); - next_range = TextRange::new(next_start, next_end); - let file_text = ctx.db().file_text(ctx.file_id().file_id()); - prev_text = file_text[prev_range].to_owned(); - next_text = file_text[next_range].to_owned(); - } + // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us + let prev = match prev { + SyntaxElement::Node(node) => node.clone_for_update().syntax_element(), + _ => prev, + }; + let next = match next { + SyntaxElement::Node(node) => node.clone_for_update().syntax_element(), + _ => next, + }; acc.add( AssistId("flip_comma", AssistKind::RefactorRewrite), "Flip comma", comma.text_range(), - |edit| { - edit.replace(prev_range, next_text); - edit.replace(next_range, prev_text); + |builder| { + let parent = comma.parent().unwrap(); + let mut editor = builder.make_editor(&parent); + + if let Some(parent) = ast::TokenTree::cast(parent) { + // An attribute. It often contains a path followed by a + // token tree (e.g. `align(2)`), so we have to be smarter. + let (new_tree, mapping) = flip_tree(parent.clone(), comma); + editor.replace(parent.syntax(), new_tree.syntax()); + editor.add_mappings(mapping); + } else { + editor.replace(prev.clone(), next.clone()); + editor.replace(next.clone(), prev.clone()); + } + + builder.add_file_edits(ctx.file_id(), editor); }, ) } -fn position_before_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Prev) { - Some(prev_token) => prev_token.text_range().end(), - None => token.text_range().start(), - } -} +fn flip_tree(tree: ast::TokenTree, comma: SyntaxToken) -> (ast::TokenTree, SyntaxMapping) { + let mut tree_iter = tree.token_trees_and_tokens(); + let before: Vec<_> = + tree_iter.by_ref().take_while(|it| it.as_token() != Some(&comma)).collect(); + let after: Vec<_> = tree_iter.collect(); -fn position_after_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Next) { - Some(prev_token) => prev_token.text_range().start(), - None => token.text_range().end(), - } + let not_ws = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() != SyntaxKind::WHITESPACE, + NodeOrToken::Node(_) => true, + }; + + let is_comma = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() == T![,], + NodeOrToken::Node(_) => false, + }; + + let prev_start_untrimmed = match before.iter().rposition(is_comma) { + Some(pos) => pos + 1, + None => 1, + }; + let prev_end = 1 + before.iter().rposition(not_ws).unwrap(); + let prev_start = prev_start_untrimmed + + before[prev_start_untrimmed..prev_end].iter().position(not_ws).unwrap(); + + let next_start = after.iter().position(not_ws).unwrap(); + let next_end_untrimmed = match after.iter().position(is_comma) { + Some(pos) => pos, + None => after.len() - 1, + }; + let next_end = 1 + after[..next_end_untrimmed].iter().rposition(not_ws).unwrap(); + + let result = [ + &before[1..prev_start], + &after[next_start..next_end], + &before[prev_end..], + &[NodeOrToken::Token(comma)], + &after[..next_start], + &before[prev_start..prev_end], + &after[next_end..after.len() - 1], + ] + .concat(); + + let make = SyntaxFactory::new(); + let new_token_tree = make.token_tree(tree.left_delimiter_token().unwrap().kind(), result); + (new_token_tree, make.finish_with_mappings()) } #[cfg(test)] @@ -147,4 +178,9 @@ mod tests { r#"#[foo(bar, qux, baz(1 + 1), other)] struct Foo;"#, ); } + + #[test] + fn flip_comma_attribute_incomplete() { + check_assist_not_applicable(flip_comma, r#"#[repr(align(2),$0)] struct Foo;"#); + } } From 667697eac6e11dc6197e4485de589b59a32bf76d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 6 Dec 2024 16:26:00 +0100 Subject: [PATCH 082/197] Highlight right angle as part of fat arrow in macro rules arm --- .../crates/ide/src/syntax_highlighting/highlight.rs | 8 ++++++++ .../test_data/highlight_block_mod_items.html | 2 +- .../test_data/highlight_const.html | 4 ++-- .../test_data/highlight_doctest.html | 4 ++-- .../test_data/highlight_keywords_2015.html | 2 +- .../test_data/highlight_keywords_2018.html | 2 +- .../test_data/highlight_keywords_2021.html | 2 +- .../test_data/highlight_keywords_2024.html | 2 +- .../test_data/highlight_macros.html | 12 ++++++------ .../test_data/highlight_strings.html | 8 ++++---- .../test_data/highlight_unsafe.html | 4 ++-- 11 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 96375937a12e..3767a3917ce7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -151,6 +151,14 @@ fn punctuation( T!['['] | T![']'] => HlPunct::Bracket, T!['{'] | T!['}'] => HlPunct::Brace, T!['('] | T![')'] => HlPunct::Parenthesis, + T![>] + if parent + .as_ref() + .and_then(SyntaxNode::parent) + .map_or(false, |it| it.kind() == MACRO_RULES) => + { + return HlOperator::Other.into() + } T![<] | T![>] => HlPunct::Angle, T![,] => HlPunct::Comma, T![:] => HlPunct::Colon, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html index 70f2d7203e9c..edd9639768ab 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
macro_rules! foo {
-    ($foo:ident) => {
+    ($foo:ident) => {
         mod y {
             pub struct $foo;
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
index a14f2cc88cd3..05289cfe3fe3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html
@@ -46,7 +46,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
 
macro_rules! id {
-    ($($tt:tt)*) => {
+    ($($tt:tt)*) => {
         $($tt)*
     };
 }
@@ -79,7 +79,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 
 macro_rules! unsafe_deref {
-    () => {
+    () => {
         *(&() as *const ())
     };
 }
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 35650bbe87f6..aa9d23250c15 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -147,11 +147,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } /// ``` -/// macro_rules! noop { ($expr:expr) => { $expr }} +/// macro_rules! noop { ($expr:expr) => { $expr }} /// noop!(1); /// ``` macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html index a790b385786d..c2bf94fd9b6f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html index 6dac066bfaa1..a30d16d53271 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html index 6dac066bfaa1..a30d16d53271 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html index 4ccc40799088..b82a3f9f8196 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! void { - ($($tt:tt)*) => {} + ($($tt:tt)*) => {} } struct __ where Self:; 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 196552020ab6..06673d1a73c7 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 @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } Foo struct } macro_rules! def_fn { - ($($tt:tt)*) => {$($tt)*} + ($($tt:tt)*) => {$($tt)*} } def_fn! { @@ -64,24 +64,24 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! dont_color_me_braces { - () => {0} + () => {0} } macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } /// textually shadow previous definition macro_rules! noop { - ($expr:expr) => { + ($expr:expr) => { $expr } } macro_rules! keyword_frag { - ($type:ty) => ($type) + ($type:ty) => ($type) } macro with_args($i:ident) { @@ -95,7 +95,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } macro_rules! id { - ($($tt:tt)*) => { + ($($tt:tt)*) => { $($tt)* }; } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 5594a36e7318..1385ae0510aa 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
macro_rules! println {
-    ($($arg:tt)*) => ({
+    ($($arg:tt)*) => ({
         $crate::io::_print(format_args_nl!($($arg)*));
     })
 }
@@ -74,12 +74,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 }
 
 macro_rules! toho {
-    () => ($crate::panic!("not yet implemented"));
-    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
+    () => ($crate::panic!("not yet implemented"));
+    ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
 }
 
 macro_rules! reuse_twice {
-    ($literal:literal) => {{stringify!($literal); format_args!($literal)}};
+    ($literal:literal) => {{stringify!($literal); format_args!($literal)}};
 }
 
 fn main() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index be6176894b4c..4e69c82f3da6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -46,12 +46,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
 
macro_rules! id {
-    ($($tt:tt)*) => {
+    ($($tt:tt)*) => {
         $($tt)*
     };
 }
 macro_rules! unsafe_deref {
-    () => {
+    () => {
         *(&() as *const ())
     };
 }

From 18f8657415da5ebc480e63abe03f87d4b4ce4157 Mon Sep 17 00:00:00 2001
From: Kai Luo 
Date: Thu, 8 Aug 2024 22:08:57 -0400
Subject: [PATCH 083/197] Pass -bnoipath when adding rust upstream dynamic
 crates

---
 compiler/rustc_codegen_ssa/src/back/link.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ad81ff272c62..b3bb32bedf4b 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2753,6 +2753,13 @@ fn add_upstream_rust_crates(
         .find(|(ty, _)| *ty == crate_type)
         .expect("failed to find crate type in dependency format list");
 
+    if sess.target.is_like_aix {
+        // Unlike GNU's ld, AIX linker doesn't feature `-soname=...` when output
+        // a shared library. Instead, AIX linker offers `(no)ipath`. See
+        // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command.
+        cmd.link_or_cc_arg("-bnoipath");
+    }
+
     for &cnum in &codegen_results.crate_info.used_crates {
         // We may not pass all crates through to the linker. Some crates may appear statically in
         // an existing dylib, meaning we'll pick up all the symbols from the dylib.

From 1ae1f8ce9cb327eaa22454bbf5a8e25123091ffb Mon Sep 17 00:00:00 2001
From: David Tenty 
Date: Fri, 6 Dec 2024 10:53:26 -0500
Subject: [PATCH 084/197] Clarify comment

---
 compiler/rustc_codegen_ssa/src/back/link.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b3bb32bedf4b..eb8f7cf6d407 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2754,8 +2754,10 @@ fn add_upstream_rust_crates(
         .expect("failed to find crate type in dependency format list");
 
     if sess.target.is_like_aix {
-        // Unlike GNU's ld, AIX linker doesn't feature `-soname=...` when output
-        // a shared library. Instead, AIX linker offers `(no)ipath`. See
+        // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override
+        // the dependency name when outputing a shared library. Thus, `ld` will
+        // use the full path to shared libraries as the dependency if passed it
+        // by default unless `noipath` is passed.
         // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command.
         cmd.link_or_cc_arg("-bnoipath");
     }

From 29a66316ad6e86568e120153e60362d563ed8ae9 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 6 Dec 2024 17:06:18 +0100
Subject: [PATCH 085/197] Temporarily disable completion resolve support for
 helix

---
 .../crates/rust-analyzer/src/bin/main.rs      | 12 ++-----
 .../crates/rust-analyzer/src/config.rs        | 34 ++++++++++++++-----
 .../rust-analyzer/src/lsp/capabilities.rs     |  6 +++-
 3 files changed, 33 insertions(+), 19 deletions(-)

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 e872585c5717..eac33be56646 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
@@ -20,7 +20,6 @@ use rust_analyzer::{
     config::{Config, ConfigChange, ConfigErrors},
     from_json,
 };
-use semver::Version;
 use tracing_subscriber::fmt::writer::BoxMakeWriter;
 use vfs::AbsPathBuf;
 
@@ -204,18 +203,12 @@ fn run_server() -> anyhow::Result<()> {
         }
     };
 
-    let mut visual_studio_code_version = None;
-    if let Some(client_info) = client_info {
+    if let Some(client_info) = &client_info {
         tracing::info!(
             "Client '{}' {}",
             client_info.name,
             client_info.version.as_deref().unwrap_or_default()
         );
-        visual_studio_code_version = client_info
-            .name
-            .starts_with("Visual Studio Code")
-            .then(|| client_info.version.as_deref().map(Version::parse).and_then(Result::ok))
-            .flatten();
     }
 
     let workspace_roots = workspace_folders
@@ -230,8 +223,7 @@ fn run_server() -> anyhow::Result<()> {
         })
         .filter(|workspaces| !workspaces.is_empty())
         .unwrap_or_else(|| vec![root_path.clone()]);
-    let mut config =
-        Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version);
+    let mut config = Config::new(root_path, capabilities, workspace_roots, client_info);
     if let Some(json) = initialization_options {
         let mut change = ConfigChange::default();
         change.change_client_config(json);
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 0fdc48a0e7a2..a4f9246a5871 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -730,6 +730,12 @@ enum RatomlFile {
     Crate(LocalConfigInput),
 }
 
+#[derive(Clone, Debug)]
+struct ClientInfo {
+    name: String,
+    version: Option,
+}
+
 #[derive(Clone)]
 pub struct Config {
     /// Projects that have a Cargo.toml or a rust-project.json in a
@@ -744,7 +750,7 @@ pub struct Config {
     caps: ClientCapabilities,
     root_path: AbsPathBuf,
     snippets: Vec,
-    visual_studio_code_version: Option,
+    client_info: Option,
 
     default_config: &'static DefaultConfigData,
     /// Config node that obtains its initial value during the server initialization and
@@ -777,7 +783,7 @@ impl fmt::Debug for Config {
             .field("caps", &self.caps)
             .field("root_path", &self.root_path)
             .field("snippets", &self.snippets)
-            .field("visual_studio_code_version", &self.visual_studio_code_version)
+            .field("client_info", &self.client_info)
             .field("client_config", &self.client_config)
             .field("user_config", &self.user_config)
             .field("ratoml_file", &self.ratoml_file)
@@ -1335,7 +1341,7 @@ impl Config {
         root_path: AbsPathBuf,
         caps: lsp_types::ClientCapabilities,
         workspace_roots: Vec,
-        visual_studio_code_version: Option,
+        client_info: Option,
     ) -> Self {
         static DEFAULT_CONFIG_DATA: OnceLock<&'static DefaultConfigData> = OnceLock::new();
 
@@ -1346,7 +1352,10 @@ impl Config {
             root_path,
             snippets: Default::default(),
             workspace_roots,
-            visual_studio_code_version,
+            client_info: client_info.map(|it| ClientInfo {
+                name: it.name,
+                version: it.version.as_deref().map(Version::parse).and_then(Result::ok),
+            }),
             client_config: (FullConfigInput::default(), ConfigErrors(vec![])),
             default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())),
             source_root_parent_map: Arc::new(FxHashMap::default()),
@@ -1446,9 +1455,11 @@ impl Config {
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
             term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
-            fields_to_resolve: CompletionFieldsToResolve::from_client_capabilities(
-                &client_capability_fields,
-            ),
+            fields_to_resolve: if self.client_is_helix() {
+                CompletionFieldsToResolve::empty()
+            } else {
+                CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields)
+            },
         }
     }
 
@@ -2163,7 +2174,14 @@ impl Config {
     // VSCode is our reference implementation, so we allow ourselves to work around issues by
     // special casing certain versions
     pub fn visual_studio_code_version(&self) -> Option<&Version> {
-        self.visual_studio_code_version.as_ref()
+        self.client_info
+            .as_ref()
+            .filter(|it| it.name.starts_with("Visual Studio Code"))
+            .and_then(|it| it.version.as_ref())
+    }
+
+    pub fn client_is_helix(&self) -> bool {
+        self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default()
     }
 }
 // Deserialization definitions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 82e6ae2b49c1..036282120942 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -41,7 +41,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
-            resolve_provider: Some(config.caps().completions_resolve_provider()),
+            resolve_provider: if config.client_is_helix() {
+                None
+            } else {
+                Some(config.caps().completions_resolve_provider())
+            },
             trigger_characters: Some(vec![
                 ":".to_owned(),
                 ".".to_owned(),

From 78496f845d198f79d546365445e904ad4e50f95c Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Fri, 6 Dec 2024 17:10:24 +0100
Subject: [PATCH 086/197] Temporarily disable completion resolve support for
 neovim

---
 src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs  | 6 +++++-
 .../crates/rust-analyzer/src/lsp/capabilities.rs            | 4 ++--
 2 files changed, 7 insertions(+), 3 deletions(-)

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 a4f9246a5871..dd7351bcf26c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -1455,7 +1455,7 @@ impl Config {
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
             term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
-            fields_to_resolve: if self.client_is_helix() {
+            fields_to_resolve: if self.client_is_helix() || self.client_is_neovim() {
                 CompletionFieldsToResolve::empty()
             } else {
                 CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields)
@@ -2183,6 +2183,10 @@ impl Config {
     pub fn client_is_helix(&self) -> bool {
         self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default()
     }
+
+    pub fn client_is_neovim(&self) -> bool {
+        self.client_info.as_ref().map(|it| it.name == "Neovim").unwrap_or_default()
+    }
 }
 // Deserialization definitions
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 036282120942..6d73319e67b2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -41,8 +41,8 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         })),
         hover_provider: Some(HoverProviderCapability::Simple(true)),
         completion_provider: Some(CompletionOptions {
-            resolve_provider: if config.client_is_helix() {
-                None
+            resolve_provider: if config.client_is_helix() || config.client_is_neovim() {
+                config.completion_item_edit_resolve().then_some(true)
             } else {
                 Some(config.caps().completions_resolve_provider())
             },

From 3109f07d855cd758aec574b009d339fe3e54cdb3 Mon Sep 17 00:00:00 2001
From: Xing Xue 
Date: Fri, 6 Dec 2024 12:51:59 -0500
Subject: [PATCH 087/197] Replace sa_sigaction with sa_union.__su_sigaction for
 AIX.

---
 .../auxiliary/assert-sigpipe-disposition.rs              | 9 ++++++++-
 .../ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs | 9 ++++++++-
 tests/ui/runtime/signal-alternate-stack-cleanup.rs       | 9 ++++++++-
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
index 117f6134b4e0..229408fb7247 100644
--- a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs
@@ -25,7 +25,14 @@ fn start(argc: isize, argv: *const *const u8) -> isize {
     let actual = unsafe {
         let mut actual: libc::sigaction = std::mem::zeroed();
         libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
-        actual.sa_sigaction
+        #[cfg(not(target_os = "aix"))]
+        {
+            actual.sa_sigaction
+        }
+        #[cfg(target_os = "aix")]
+        {
+            actual.sa_union.__su_sigaction as libc::sighandler_t
+        }
     };
 
     assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs");
diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs
index 3d93d50ca3fb..d16a2b4d8c8a 100644
--- a/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs
+++ b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs
@@ -20,7 +20,14 @@ pub fn assert_sigpipe_handler(expected_handler: SignalHandler) {
         let actual = unsafe {
             let mut actual: libc::sigaction = std::mem::zeroed();
             libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual);
-            actual.sa_sigaction
+            #[cfg(not(target_os = "aix"))]
+            {
+                actual.sa_sigaction
+            }
+            #[cfg(target_os = "aix")]
+            {
+                actual.sa_union.__su_sigaction as libc::sighandler_t
+            }
         };
 
         let expected = match expected_handler {
diff --git a/tests/ui/runtime/signal-alternate-stack-cleanup.rs b/tests/ui/runtime/signal-alternate-stack-cleanup.rs
index f2af86be0a5f..8fce09282731 100644
--- a/tests/ui/runtime/signal-alternate-stack-cleanup.rs
+++ b/tests/ui/runtime/signal-alternate-stack-cleanup.rs
@@ -29,7 +29,14 @@ fn main() {
         // Install signal handler that runs on alternate signal stack.
         let mut action: sigaction = std::mem::zeroed();
         action.sa_flags = (SA_ONSTACK | SA_SIGINFO) as _;
-        action.sa_sigaction = signal_handler as sighandler_t;
+        #[cfg(not(target_os = "aix"))]
+        {
+            action.sa_sigaction = signal_handler as sighandler_t;
+        }
+        #[cfg(target_os = "aix")]
+        {
+            action.sa_union.__su_sigaction = signal_handler as sighandler_t;
+        }
         sigaction(SIGWINCH, &action, std::ptr::null_mut());
 
         // Send SIGWINCH on exit.

From ac815ff6b0c8f0fd68ddf666ea1f96e362c65300 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Thu, 5 Dec 2024 18:57:17 +1100
Subject: [PATCH 088/197] coverage: Prefer to visit nodes whose predecessors
 have been visited

---
 .../src/coverage/counters.rs                  |  15 +-
 .../rustc_mir_transform/src/coverage/graph.rs | 256 +++++-----
 tests/coverage/branch/guard.cov-map           |  40 +-
 tests/coverage/branch/if-let.cov-map          |  31 +-
 tests/coverage/branch/if.cov-map              |  48 +-
 tests/coverage/branch/lazy-boolean.cov-map    | 164 +++----
 tests/coverage/branch/match-arms.cov-map      |  57 ++-
 tests/coverage/branch/while.cov-map           |  13 +-
 tests/coverage/closure_macro.cov-map          |  12 +-
 tests/coverage/closure_macro_async.cov-map    |  12 +-
 tests/coverage/condition/conditions.cov-map   | 160 +++----
 tests/coverage/conditions.cov-map             | 452 +++++++-----------
 tests/coverage/continue.cov-map               |  12 +-
 tests/coverage/coroutine.cov-map              |  24 +-
 tests/coverage/inline.cov-map                 |  14 +-
 tests/coverage/loops_branches.cov-map         | 177 ++++---
 tests/coverage/mcdc/condition-limit.cov-map   | 112 ++---
 tests/coverage/mcdc/if.cov-map                | 203 ++++----
 .../coverage/mcdc/inlined_expressions.cov-map |  17 +-
 tests/coverage/mcdc/nested_if.cov-map         |  88 ++--
 tests/coverage/mcdc/non_control_flow.cov-map  | 207 ++++----
 tests/coverage/try_error_result.cov-map       |  10 +-
 tests/coverage/unicode.cov-map                |  15 +-
 tests/coverage/while_early_ret.cov-map        |  12 +-
 tests/coverage/yield.cov-map                  |  35 +-
 25 files changed, 936 insertions(+), 1250 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 46efdd16ee83..9e80f1f1c4ac 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -9,7 +9,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 use tracing::{debug, debug_span, instrument};
 
-use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops};
+use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, ReadyFirstTraversal};
 
 #[cfg(test)]
 mod tests;
@@ -236,23 +236,12 @@ impl<'a> CountersBuilder<'a> {
 
         // Traverse the coverage graph, ensuring that every node that needs a
         // coverage counter has one.
-        //
-        // The traversal tries to ensure that, when a loop is encountered, all
-        // nodes within the loop are visited before visiting any nodes outside
-        // the loop.
-        let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph);
-        while let Some(bcb) = traversal.next() {
+        for bcb in ReadyFirstTraversal::new(self.graph) {
             let _span = debug_span!("traversal", ?bcb).entered();
             if self.bcb_needs_counter.contains(bcb) {
                 self.make_node_counter_and_out_edge_counters(bcb);
             }
         }
-
-        assert!(
-            traversal.is_complete(),
-            "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
-            traversal.unvisited(),
-        );
     }
 
     /// Make sure the given node has a node counter, and then make sure each of
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 092bce1de2c2..ad6774fccd6f 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
 use tracing::debug;
 
@@ -462,138 +461,6 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
     CoverageSuccessors { targets, is_yield }
 }
 
-/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
-/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that
-/// ensures a loop is completely traversed before processing Blocks after the end of the loop.
-#[derive(Debug)]
-struct TraversalContext {
-    /// BCB with one or more incoming loop backedges, indicating which loop
-    /// this context is for.
-    ///
-    /// If `None`, this is the non-loop context for the function as a whole.
-    loop_header: Option,
-
-    /// Worklist of BCBs to be processed in this context.
-    worklist: VecDeque,
-}
-
-pub(crate) struct TraverseCoverageGraphWithLoops<'a> {
-    basic_coverage_blocks: &'a CoverageGraph,
-
-    context_stack: Vec,
-    visited: BitSet,
-}
-
-impl<'a> TraverseCoverageGraphWithLoops<'a> {
-    pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
-        let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
-        let context_stack = vec![TraversalContext { loop_header: None, worklist }];
-
-        // `context_stack` starts with a `TraversalContext` for the main function context (beginning
-        // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top
-        // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
-        // exhausted.
-        let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        Self { basic_coverage_blocks, context_stack, visited }
-    }
-
-    pub(crate) fn next(&mut self) -> Option {
-        debug!(
-            "TraverseCoverageGraphWithLoops::next - context_stack: {:?}",
-            self.context_stack.iter().rev().collect::>()
-        );
-
-        while let Some(context) = self.context_stack.last_mut() {
-            let Some(bcb) = context.worklist.pop_front() else {
-                // This stack level is exhausted; pop it and try the next one.
-                self.context_stack.pop();
-                continue;
-            };
-
-            if !self.visited.insert(bcb) {
-                debug!("Already visited: {bcb:?}");
-                continue;
-            }
-            debug!("Visiting {bcb:?}");
-
-            if self.basic_coverage_blocks.is_loop_header.contains(bcb) {
-                debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
-                self.context_stack
-                    .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() });
-            }
-            self.add_successors_to_worklists(bcb);
-            return Some(bcb);
-        }
-
-        None
-    }
-
-    fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) {
-        let successors = &self.basic_coverage_blocks.successors[bcb];
-        debug!("{:?} has {} successors:", bcb, successors.len());
-
-        for &successor in successors {
-            if successor == bcb {
-                debug!(
-                    "{:?} has itself as its own successor. (Note, the compiled code will \
-                    generate an infinite loop.)",
-                    bcb
-                );
-                // Don't re-add this successor to the worklist. We are already processing it.
-                // FIXME: This claims to skip just the self-successor, but it actually skips
-                // all other successors as well. Does that matter?
-                break;
-            }
-
-            // Add successors of the current BCB to the appropriate context. Successors that
-            // stay within a loop are added to the BCBs context worklist. Successors that
-            // exit the loop (they are not dominated by the loop header) must be reachable
-            // from other BCBs outside the loop, and they will be added to a different
-            // worklist.
-            //
-            // Branching blocks (with more than one successor) must be processed before
-            // blocks with only one successor, to prevent unnecessarily complicating
-            // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
-            // branching block would have given an `Expression` (or vice versa).
-
-            let context = self
-                .context_stack
-                .iter_mut()
-                .rev()
-                .find(|context| match context.loop_header {
-                    Some(loop_header) => {
-                        self.basic_coverage_blocks.dominates(loop_header, successor)
-                    }
-                    None => true,
-                })
-                .unwrap_or_else(|| bug!("should always fall back to the root non-loop context"));
-            debug!("adding to worklist for {:?}", context.loop_header);
-
-            // FIXME: The code below had debug messages claiming to add items to a
-            // particular end of the worklist, but was confused about which end was
-            // which. The existing behaviour has been preserved for now, but it's
-            // unclear what the intended behaviour was.
-
-            if self.basic_coverage_blocks.successors[successor].len() > 1 {
-                context.worklist.push_back(successor);
-            } else {
-                context.worklist.push_front(successor);
-            }
-        }
-    }
-
-    pub(crate) fn is_complete(&self) -> bool {
-        self.visited.count() == self.visited.domain_size()
-    }
-
-    pub(crate) fn unvisited(&self) -> Vec {
-        let mut unvisited_set: BitSet =
-            BitSet::new_filled(self.visited.domain_size());
-        unvisited_set.subtract(&self.visited);
-        unvisited_set.iter().collect::>()
-    }
-}
-
 /// Wrapper around a [`mir::BasicBlocks`] graph that restricts each node's
 /// successors to only the ones considered "relevant" when building a coverage
 /// graph.
@@ -622,3 +489,126 @@ impl<'a, 'tcx> graph::Successors for CoverageRelevantSubgraph<'a, 'tcx> {
         self.coverage_successors(bb).into_iter()
     }
 }
+
+/// State of a node in the coverage graph during ready-first traversal.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+enum ReadyState {
+    /// This node has not yet been added to the fallback queue or ready queue.
+    Unqueued,
+    /// This node is currently in the fallback queue.
+    InFallbackQueue,
+    /// This node's predecessors have all been visited, so it is in the ready queue.
+    /// (It might also have a stale entry in the fallback queue.)
+    InReadyQueue,
+    /// This node has been visited.
+    /// (It might also have a stale entry in the fallback queue.)
+    Visited,
+}
+
+/// Iterator that visits nodes in the coverage graph, in an order that always
+/// prefers "ready" nodes whose predecessors have already been visited.
+pub(crate) struct ReadyFirstTraversal<'a> {
+    graph: &'a CoverageGraph,
+
+    /// For each node, the number of its predecessor nodes that haven't been visited yet.
+    n_unvisited_preds: IndexVec,
+    /// Indicates whether a node has been visited, or which queue it is in.
+    state: IndexVec,
+
+    /// Holds unvisited nodes whose predecessors have all been visited.
+    ready_queue: VecDeque,
+    /// Holds unvisited nodes with some unvisited predecessors.
+    /// Also contains stale entries for nodes that were upgraded to ready.
+    fallback_queue: VecDeque,
+}
+
+impl<'a> ReadyFirstTraversal<'a> {
+    pub(crate) fn new(graph: &'a CoverageGraph) -> Self {
+        let num_nodes = graph.num_nodes();
+
+        let n_unvisited_preds =
+            IndexVec::from_fn_n(|node| graph.predecessors[node].len() as u32, num_nodes);
+        let mut state = IndexVec::from_elem_n(ReadyState::Unqueued, num_nodes);
+
+        // We know from coverage graph construction that the start node is the
+        // only node with no predecessors.
+        debug_assert!(
+            n_unvisited_preds.iter_enumerated().all(|(node, &n)| (node == START_BCB) == (n == 0))
+        );
+        let ready_queue = VecDeque::from(vec![START_BCB]);
+        state[START_BCB] = ReadyState::InReadyQueue;
+
+        Self { graph, state, n_unvisited_preds, ready_queue, fallback_queue: VecDeque::new() }
+    }
+
+    /// Returns the next node from the ready queue, or else the next unvisited
+    /// node from the fallback queue.
+    fn next_inner(&mut self) -> Option {
+        // Always prefer to yield a ready node if possible.
+        if let Some(node) = self.ready_queue.pop_front() {
+            assert_eq!(self.state[node], ReadyState::InReadyQueue);
+            return Some(node);
+        }
+
+        while let Some(node) = self.fallback_queue.pop_front() {
+            match self.state[node] {
+                // This entry in the fallback queue is not stale, so yield it.
+                ReadyState::InFallbackQueue => return Some(node),
+                // This node was added to the fallback queue, but later became
+                // ready and was visited via the ready queue. Ignore it here.
+                ReadyState::Visited => {}
+                // Unqueued nodes can't be in the fallback queue, by definition.
+                // We know that the ready queue is empty at this point.
+                ReadyState::Unqueued | ReadyState::InReadyQueue => unreachable!(
+                    "unexpected state for {node:?} in the fallback queue: {:?}",
+                    self.state[node]
+                ),
+            }
+        }
+
+        None
+    }
+
+    fn mark_visited_and_enqueue_successors(&mut self, node: BasicCoverageBlock) {
+        assert!(self.state[node] < ReadyState::Visited);
+        self.state[node] = ReadyState::Visited;
+
+        // For each of this node's successors, decrease the successor's
+        // "unvisited predecessors" count, and enqueue it if appropriate.
+        for &succ in &self.graph.successors[node] {
+            let is_unqueued = match self.state[succ] {
+                ReadyState::Unqueued => true,
+                ReadyState::InFallbackQueue => false,
+                ReadyState::InReadyQueue => {
+                    unreachable!("nodes in the ready queue have no unvisited predecessors")
+                }
+                // The successor was already visited via one of its other predecessors.
+                ReadyState::Visited => continue,
+            };
+
+            self.n_unvisited_preds[succ] -= 1;
+            if self.n_unvisited_preds[succ] == 0 {
+                // This node's predecessors have all been visited, so add it to
+                // the ready queue. If it's already in the fallback queue, that
+                // fallback entry will be ignored later.
+                self.state[succ] = ReadyState::InReadyQueue;
+                self.ready_queue.push_back(succ);
+            } else if is_unqueued {
+                // This node has unvisited predecessors, so add it to the
+                // fallback queue in case we run out of ready nodes later.
+                self.state[succ] = ReadyState::InFallbackQueue;
+                self.fallback_queue.push_back(succ);
+            }
+        }
+    }
+}
+
+impl<'a> Iterator for ReadyFirstTraversal<'a> {
+    type Item = BasicCoverageBlock;
+
+    fn next(&mut self) -> Option {
+        let node = self.next_inner()?;
+        self.mark_visited_and_enqueue_successors(node);
+        Some(node)
+    }
+}
diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map
index 1ba1c6e1228c..7ca499bd847c 100644
--- a/tests/coverage/branch/guard.cov-map
+++ b/tests/coverage/branch/guard.cov-map
@@ -1,35 +1,37 @@
 Function name: guard::branch_match_guard
-Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 02, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 05, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02]
+Raw bytes (89): 0x[01, 01, 08, 05, 0d, 05, 17, 0d, 11, 1f, 17, 05, 09, 0d, 11, 1f, 15, 05, 09, 0d, 01, 0c, 01, 01, 10, 02, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 06, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 0e, 03, 0e, 02, 0a, 1b, 04, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
-- expression 0 operands: lhs = Counter(6), rhs = Counter(3)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 8
+- expression 0 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 3 operands: lhs = Expression(7, Add), rhs = Expression(5, Add)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(5)
+- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 13
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Expression(0, Sub)) at (prev + 3, 11) to (start + 0, 12)
-    = (c6 - c3)
+    = (c1 - c3)
 - Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10)
 - Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15)
-- Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25)
+- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 25)
 - Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30)
     true  = c3
-    false = (c6 - c3)
+    false = (c1 - c3)
 - Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10)
 - Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15)
 - Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 0, 25)
-    = (c6 - c3)
-- Branch { true: Counter(4), false: Counter(1) } at (prev + 0, 20) to (start + 0, 30)
+    = (c1 - c3)
+- Branch { true: Counter(4), false: Expression(1, Sub) } at (prev + 0, 20) to (start + 0, 30)
     true  = c4
-    false = c1
+    false = (c1 - (c3 + c4))
 - Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10)
-- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10)
-    = (c1 + c2)
-- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2)
-    = ((((c1 + c2) + c3) + c4) + c5)
-Highest counter ID seen: c6
+- Code(Expression(3, Sub)) at (prev + 3, 14) to (start + 2, 10)
+    = ((c1 + c2) - (c3 + c4))
+- Code(Expression(6, Add)) at (prev + 4, 1) to (start + 0, 2)
+    = ((c1 + c2) + c5)
+Highest counter ID seen: c5
 
diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map
index 380765c7af4b..773c53924653 100644
--- a/tests/coverage/branch/if-let.cov-map
+++ b/tests/coverage/branch/if-let.cov-map
@@ -19,14 +19,18 @@ Number of file 0 mappings: 7
 Highest counter ID seen: c2
 
 Function name: if_let::if_let_chain
-Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
+Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
+Number of expressions: 8
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(0), rhs = Expression(7, Add)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(0), rhs = Expression(7, Add)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51)
 - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19)
@@ -35,16 +39,17 @@ Number of file 0 mappings: 10
 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18)
     = (c0 - c1)
 - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23)
-- Branch { true: Counter(3), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23)
-    true  = c3
+- Branch { true: Expression(5, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23)
+    true  = (c0 - (c1 + c2))
     false = c2
-- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 22)
+- Code(Expression(5, Sub)) at (prev + 0, 21) to (start + 0, 22)
+    = (c0 - (c1 + c2))
 - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27)
     = (c0 - c1)
-- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 6)
-- Code(Expression(3, Add)) at (prev + 3, 12) to (start + 2, 6)
+- Code(Expression(5, Sub)) at (prev + 1, 5) to (start + 3, 6)
+    = (c0 - (c1 + c2))
+- Code(Expression(7, Add)) at (prev + 3, 12) to (start + 2, 6)
     = (c1 + c2)
-- Code(Expression(2, Add)) at (prev + 3, 5) to (start + 1, 2)
-    = ((c1 + c2) + c3)
-Highest counter ID seen: c3
+- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2)
+Highest counter ID seen: c2
 
diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map
index bab982dd44c9..3d9a1d2e1ab6 100644
--- a/tests/coverage/branch/if.cov-map
+++ b/tests/coverage/branch/if.cov-map
@@ -1,14 +1,11 @@
 Function name: if::branch_and
-Raw bytes (60): 0x[01, 01, 06, 05, 09, 0b, 09, 05, 11, 13, 09, 17, 11, 05, 0d, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02]
+Raw bytes (54): 0x[01, 01, 03, 05, 09, 09, 0d, 05, 0d, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 0d, 06, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4)
-- expression 5 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(3)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 43, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
@@ -16,15 +13,14 @@ Number of file 0 mappings: 8
     true  = c2
     false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(3), false: Expression(1, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c3
-    false = c4
+    false = (c2 - c3)
 - Code(Counter(3)) at (prev + 0, 15) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c1 + c4) - c2)
-- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c1 + c3) + c4) - c2)
-Highest counter ID seen: c4
+- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c1 - c3)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
 Function name: if::branch_not
 Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 05, 00, 06, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 05, 00, 06, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 05, 00, 06, 05, 01, 01, 00, 02]
@@ -108,14 +104,16 @@ Number of file 0 mappings: 14
 Highest counter ID seen: c4
 
 Function name: if::branch_or
-Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
+Raw bytes (60): 0x[01, 01, 06, 05, 09, 05, 17, 09, 0d, 09, 0d, 05, 17, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
+Number of expressions: 6
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4)
+- expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
 - expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 4 operands: lhs = Counter(1), rhs = Expression(5, Add)
+- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 53, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
@@ -124,13 +122,13 @@ Number of file 0 mappings: 8
     false = (c1 - c2)
 - Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14)
     = (c1 - c2)
-- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c3
-    false = c4
-- Code(Expression(3, Add)) at (prev + 0, 15) to (start + 2, 6)
+    false = (c1 - (c2 + c3))
+- Code(Expression(5, Add)) at (prev + 0, 15) to (start + 2, 6)
     = (c2 + c3)
-- Code(Counter(4)) at (prev + 2, 12) to (start + 2, 6)
-- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c2 + c3) + c4)
-Highest counter ID seen: c4
+- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c1 - (c2 + c3))
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map
index decb847f60e3..94522734bcd4 100644
--- a/tests/coverage/branch/lazy-boolean.cov-map
+++ b/tests/coverage/branch/lazy-boolean.cov-map
@@ -34,86 +34,68 @@ Number of file 0 mappings: 6
 Highest counter ID seen: c2
 
 Function name: lazy_boolean::chain
-Raw bytes (169): 0x[01, 01, 1d, 5b, 0d, 5f, 15, 05, 11, 05, 09, 09, 0d, 6f, 25, 73, 21, 19, 1d, 5b, 67, 5f, 15, 05, 11, 0d, 19, 5b, 67, 5f, 15, 05, 11, 0d, 19, 5b, 63, 5f, 15, 05, 11, 67, 1d, 0d, 19, 5b, 63, 5f, 15, 05, 11, 67, 1d, 0d, 19, 6f, 25, 73, 21, 19, 1d, 13, 01, 24, 01, 01, 10, 02, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 0e, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 12, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 15, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 02, 01, 05, 00, 11, 6b, 03, 09, 00, 0a, 02, 00, 0d, 00, 12, 20, 19, 32, 00, 0d, 00, 12, 32, 00, 16, 00, 1b, 20, 1d, 56, 00, 16, 00, 1b, 56, 00, 1f, 00, 24, 20, 21, 25, 00, 1f, 00, 24, 25, 00, 28, 00, 2d, 6b, 01, 05, 01, 02]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 29
-- expression 0 operands: lhs = Expression(22, Add), rhs = Counter(3)
-- expression 1 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 5 operands: lhs = Expression(27, Add), rhs = Counter(9)
-- expression 6 operands: lhs = Expression(28, Add), rhs = Counter(8)
-- expression 7 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 8 operands: lhs = Expression(22, Add), rhs = Expression(25, Add)
-- expression 9 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 10 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 11 operands: lhs = Counter(3), rhs = Counter(6)
-- expression 12 operands: lhs = Expression(22, Add), rhs = Expression(25, Add)
-- expression 13 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 14 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 15 operands: lhs = Counter(3), rhs = Counter(6)
-- expression 16 operands: lhs = Expression(22, Add), rhs = Expression(24, Add)
-- expression 17 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 18 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 19 operands: lhs = Expression(25, Add), rhs = Counter(7)
-- expression 20 operands: lhs = Counter(3), rhs = Counter(6)
-- expression 21 operands: lhs = Expression(22, Add), rhs = Expression(24, Add)
-- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 23 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 24 operands: lhs = Expression(25, Add), rhs = Counter(7)
-- expression 25 operands: lhs = Counter(3), rhs = Counter(6)
-- expression 26 operands: lhs = Expression(27, Add), rhs = Counter(9)
-- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(8)
-- expression 28 operands: lhs = Counter(6), rhs = Counter(7)
-Number of file 0 mappings: 19
-- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 16)
-- Code(Expression(0, Sub)) at (prev + 4, 9) to (start + 0, 10)
-    = (((c1 + c4) + c5) - c3)
-- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 18)
-- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 18)
-    true  = c2
-    false = (c1 - c2)
-- Code(Counter(2)) at (prev + 0, 22) to (start + 0, 27)
-- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 22) to (start + 0, 27)
-    true  = c3
-    false = (c2 - c3)
-- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 36)
-- Branch { true: Counter(4), false: Counter(5) } at (prev + 0, 31) to (start + 0, 36)
-    true  = c4
-    false = c5
-- Code(Counter(4)) at (prev + 0, 40) to (start + 0, 45)
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 17)
-    = (((c1 + c4) + c5) - c3)
-- Code(Expression(26, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (((c6 + c7) + c8) + c9)
-- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 18)
-    = (((c1 + c4) + c5) - c3)
-- Branch { true: Counter(6), false: Expression(12, Sub) } at (prev + 0, 13) to (start + 0, 18)
-    true  = c6
-    false = (((c1 + c4) + c5) - (c3 + c6))
-- Code(Expression(12, Sub)) at (prev + 0, 22) to (start + 0, 27)
-    = (((c1 + c4) + c5) - (c3 + c6))
-- Branch { true: Counter(7), false: Expression(21, Sub) } at (prev + 0, 22) to (start + 0, 27)
-    true  = c7
-    false = (((c1 + c4) + c5) - ((c3 + c6) + c7))
-- Code(Expression(21, Sub)) at (prev + 0, 31) to (start + 0, 36)
-    = (((c1 + c4) + c5) - ((c3 + c6) + c7))
-- Branch { true: Counter(8), false: Counter(9) } at (prev + 0, 31) to (start + 0, 36)
-    true  = c8
-    false = c9
-- Code(Counter(9)) at (prev + 0, 40) to (start + 0, 45)
-- Code(Expression(26, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (((c6 + c7) + c8) + c9)
-Highest counter ID seen: c9
-
-Function name: lazy_boolean::nested_mixed
-Raw bytes (141): 0x[01, 01, 0f, 05, 09, 05, 1f, 09, 0d, 09, 0d, 1f, 11, 09, 0d, 1f, 11, 09, 0d, 3b, 21, 19, 1d, 05, 15, 15, 19, 05, 19, 3b, 21, 19, 1d, 13, 01, 31, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 0d, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 11, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 05, 01, 05, 00, 11, 37, 03, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 15, 2a, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 2e, 00, 17, 00, 1c, 32, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 37, 01, 05, 01, 02]
+Raw bytes (141): 0x[01, 01, 0f, 05, 09, 09, 0d, 0d, 11, 05, 15, 05, 15, 05, 3b, 15, 19, 05, 3b, 15, 19, 05, 37, 3b, 1d, 15, 19, 05, 37, 3b, 1d, 15, 19, 13, 01, 24, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 02, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 06, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 0a, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 05, 01, 05, 00, 11, 05, 03, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 15, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 19, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 1d, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 05, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 15
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(5)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(1), rhs = Expression(14, Add)
+- expression 6 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 7 operands: lhs = Counter(1), rhs = Expression(14, Add)
+- expression 8 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 9 operands: lhs = Counter(1), rhs = Expression(13, Add)
+- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(7)
+- expression 11 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add)
+- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(7)
+- expression 14 operands: lhs = Counter(5), rhs = Counter(6)
+Number of file 0 mappings: 19
+- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 16)
+- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
+- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 18)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 18)
+    true  = c2
+    false = (c1 - c2)
+- Code(Counter(2)) at (prev + 0, 22) to (start + 0, 27)
+- Branch { true: Counter(3), false: Expression(1, Sub) } at (prev + 0, 22) to (start + 0, 27)
+    true  = c3
+    false = (c2 - c3)
+- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 36)
+- Branch { true: Counter(4), false: Expression(2, Sub) } at (prev + 0, 31) to (start + 0, 36)
+    true  = c4
+    false = (c3 - c4)
+- Code(Counter(4)) at (prev + 0, 40) to (start + 0, 45)
+- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 17)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 10)
+- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 18)
+- Branch { true: Counter(5), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 18)
+    true  = c5
+    false = (c1 - c5)
+- Code(Expression(4, Sub)) at (prev + 0, 22) to (start + 0, 27)
+    = (c1 - c5)
+- Branch { true: Counter(6), false: Expression(7, Sub) } at (prev + 0, 22) to (start + 0, 27)
+    true  = c6
+    false = (c1 - (c5 + c6))
+- Code(Expression(7, Sub)) at (prev + 0, 31) to (start + 0, 36)
+    = (c1 - (c5 + c6))
+- Branch { true: Counter(7), false: Expression(12, Sub) } at (prev + 0, 31) to (start + 0, 36)
+    true  = c7
+    false = (c1 - ((c5 + c6) + c7))
+- Code(Expression(12, Sub)) at (prev + 0, 40) to (start + 0, 45)
+    = (c1 - ((c5 + c6) + c7))
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c7
+
+Function name: lazy_boolean::nested_mixed
+Raw bytes (137): 0x[01, 01, 0d, 05, 09, 05, 1f, 09, 0d, 09, 0d, 1f, 11, 09, 0d, 1f, 11, 09, 0d, 05, 15, 15, 19, 05, 19, 05, 33, 19, 1d, 13, 01, 31, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 0d, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 11, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 05, 01, 05, 00, 11, 05, 03, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 15, 22, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 1d, 2e, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 05, 01, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 13
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add)
 - expression 2 operands: lhs = Counter(2), rhs = Counter(3)
 - expression 3 operands: lhs = Counter(2), rhs = Counter(3)
@@ -121,13 +103,11 @@ Number of expressions: 15
 - expression 5 operands: lhs = Counter(2), rhs = Counter(3)
 - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4)
 - expression 7 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(8)
-- expression 9 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 10 operands: lhs = Counter(1), rhs = Counter(5)
-- expression 11 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 12 operands: lhs = Counter(1), rhs = Counter(6)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(8)
-- expression 14 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 8 operands: lhs = Counter(1), rhs = Counter(5)
+- expression 9 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 10 operands: lhs = Counter(1), rhs = Counter(6)
+- expression 11 operands: lhs = Counter(1), rhs = Expression(12, Add)
+- expression 12 operands: lhs = Counter(6), rhs = Counter(7)
 Number of file 0 mappings: 19
 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
@@ -148,23 +128,21 @@ Number of file 0 mappings: 19
 - Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 51)
     = ((c2 + c3) - c4)
 - Code(Counter(1)) at (prev + 1, 5) to (start + 0, 17)
-- Code(Expression(13, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = ((c6 + c7) + c8)
+- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 10)
 - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19)
-- Branch { true: Counter(5), false: Expression(10, Sub) } at (prev + 0, 14) to (start + 0, 19)
+- Branch { true: Counter(5), false: Expression(8, Sub) } at (prev + 0, 14) to (start + 0, 19)
     true  = c5
     false = (c1 - c5)
 - Code(Counter(5)) at (prev + 0, 23) to (start + 0, 28)
-- Branch { true: Counter(6), false: Expression(11, Sub) } at (prev + 0, 23) to (start + 0, 28)
+- Branch { true: Counter(6), false: Expression(9, Sub) } at (prev + 0, 23) to (start + 0, 28)
     true  = c6
     false = (c5 - c6)
-- Code(Expression(12, Sub)) at (prev + 0, 34) to (start + 0, 40)
+- Code(Expression(10, Sub)) at (prev + 0, 34) to (start + 0, 40)
     = (c1 - c6)
-- Branch { true: Counter(7), false: Counter(8) } at (prev + 0, 34) to (start + 0, 40)
+- Branch { true: Counter(7), false: Expression(11, Sub) } at (prev + 0, 34) to (start + 0, 40)
     true  = c7
-    false = c8
+    false = (c1 - (c6 + c7))
 - Code(Counter(7)) at (prev + 0, 44) to (start + 0, 51)
-- Code(Expression(13, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = ((c6 + c7) + c8)
-Highest counter ID seen: c8
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c7
 
diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map
index a93df9814ee7..53d0a4edbd0c 100644
--- a/tests/coverage/branch/match-arms.cov-map
+++ b/tests/coverage/branch/match-arms.cov-map
@@ -1,40 +1,45 @@
 Function name: match_arms::guards
-Raw bytes (88): 0x[01, 01, 08, 07, 00, 0b, 11, 0f, 0d, 05, 09, 17, 25, 1b, 21, 1f, 1d, 03, 19, 0c, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 19, 01, 11, 00, 29, 20, 19, 05, 00, 17, 00, 1b, 1d, 01, 11, 00, 29, 20, 1d, 09, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 0d, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 11, 00, 17, 00, 1b, 03, 01, 0e, 00, 18, 13, 03, 05, 01, 02]
+Raw bytes (98): 0x[01, 01, 0d, 11, 19, 27, 19, 2b, 00, 2f, 11, 33, 0d, 05, 09, 1f, 25, 23, 21, 27, 1d, 2b, 00, 2f, 11, 33, 0d, 05, 09, 0c, 01, 30, 01, 01, 10, 11, 03, 0b, 00, 10, 1d, 01, 11, 00, 29, 20, 1d, 05, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 09, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 0d, 00, 17, 00, 1b, 19, 01, 11, 00, 29, 20, 19, 02, 00, 17, 00, 1b, 06, 01, 0e, 00, 18, 1b, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 8
-- expression 0 operands: lhs = Expression(1, Add), rhs = Zero
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(9)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(8)
-- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(7)
-- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(6)
+Number of expressions: 13
+- expression 0 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 1 operands: lhs = Expression(9, Add), rhs = Counter(6)
+- expression 2 operands: lhs = Expression(10, Add), rhs = Zero
+- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Expression(12, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(9)
+- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(8)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(7)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Zero
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
+- expression 12 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 12
 - Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16)
-- Code(Counter(10)) at (prev + 3, 11) to (start + 0, 16)
-- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41)
-- Branch { true: Counter(6), false: Counter(1) } at (prev + 0, 23) to (start + 0, 27)
-    true  = c6
-    false = c1
+- Code(Counter(4)) at (prev + 3, 11) to (start + 0, 16)
 - Code(Counter(7)) at (prev + 1, 17) to (start + 0, 41)
-- Branch { true: Counter(7), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27)
+- Branch { true: Counter(7), false: Counter(1) } at (prev + 0, 23) to (start + 0, 27)
     true  = c7
-    false = c2
+    false = c1
 - Code(Counter(8)) at (prev + 1, 17) to (start + 0, 41)
-- Branch { true: Counter(8), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27)
+- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27)
     true  = c8
-    false = c3
+    false = c2
 - Code(Counter(9)) at (prev + 1, 17) to (start + 0, 41)
-- Branch { true: Counter(9), false: Counter(4) } at (prev + 0, 23) to (start + 0, 27)
+- Branch { true: Counter(9), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27)
     true  = c9
-    false = c4
-- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 24)
-    = ((((c1 + c2) + c3) + c4) + Zero)
-- Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2)
-    = ((((((((c1 + c2) + c3) + c4) + Zero) + c6) + c7) + c8) + c9)
-Highest counter ID seen: c10
+    false = c3
+- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41)
+- Branch { true: Counter(6), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27)
+    true  = c6
+    false = (c4 - c6)
+- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 24)
+    = (((((c1 + c2) + c3) + c4) + Zero) - c6)
+- Code(Expression(6, Add)) at (prev + 3, 5) to (start + 1, 2)
+    = (((((((c1 + c2) + c3) + c4) + Zero) + c7) + c8) + c9)
+Highest counter ID seen: c9
 
 Function name: match_arms::match_arms
 Raw bytes (45): 0x[01, 01, 03, 05, 07, 0b, 11, 09, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 09, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 11, 01, 11, 00, 21, 02, 01, 11, 00, 21, 05, 03, 05, 01, 02]
diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map
index 305f6bc74d83..5eb08a42803b 100644
--- a/tests/coverage/branch/while.cov-map
+++ b/tests/coverage/branch/while.cov-map
@@ -35,14 +35,14 @@ Number of file 0 mappings: 6
 Highest counter ID seen: c2
 
 Function name: while::while_op_and
-Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 0d, 11, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02]
+Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 05, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 0e, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 05, 04, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 4
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 1 operands: lhs = Expression(0, Add), rhs = Counter(3)
 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(3)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18)
@@ -53,13 +53,12 @@ Number of file 0 mappings: 8
     false = c3
 - Code(Expression(2, Sub)) at (prev + 0, 20) to (start + 0, 25)
     = ((c1 + c2) - c3)
-- Branch { true: Counter(2), false: Counter(4) } at (prev + 0, 20) to (start + 0, 25)
+- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 20) to (start + 0, 25)
     true  = c2
-    false = c4
+    false = (c1 - c3)
 - Code(Counter(2)) at (prev + 0, 26) to (start + 3, 6)
-- Code(Expression(3, Add)) at (prev + 4, 1) to (start + 0, 2)
-    = (c3 + c4)
-Highest counter ID seen: c4
+- Code(Counter(1)) at (prev + 4, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
 Function name: while::while_op_or
 Raw bytes (58): 0x[01, 01, 05, 07, 0d, 05, 09, 05, 0d, 05, 0d, 09, 0d, 08, 01, 29, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 09, 0f, 00, 0b, 00, 10, 0f, 00, 14, 00, 19, 20, 0d, 05, 00, 14, 00, 19, 13, 00, 1a, 03, 06, 05, 04, 01, 00, 02]
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
index aedb924eca86..653848dd6ffc 100644
--- a/tests/coverage/closure_macro.cov-map
+++ b/tests/coverage/closure_macro.cov-map
@@ -25,20 +25,20 @@ Number of file 0 mappings: 6
 Highest counter ID seen: c1
 
 Function name: closure_macro::main::{closure#0}
-Raw bytes (35): 0x[01, 01, 03, 01, 05, 0b, 0d, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
+Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33)
 - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
 - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
     = (c0 - c1)
-- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
-- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = ((c1 + c2) + c3)
-Highest counter ID seen: c3
+- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30)
+    = (c0 - (c1 + c2))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+Highest counter ID seen: c1
 
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
index df4652ac9ce7..1bd1460a147a 100644
--- a/tests/coverage/closure_macro_async.cov-map
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -34,20 +34,20 @@ Number of file 0 mappings: 6
 Highest counter ID seen: c1
 
 Function name: closure_macro_async::test::{closure#0}::{closure#0}
-Raw bytes (35): 0x[01, 01, 03, 01, 05, 0b, 0d, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
+Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 20, 28) to (start + 3, 33)
 - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39)
 - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22)
     = (c0 - c1)
-- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30)
-- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = ((c1 + c2) + c3)
-Highest counter ID seen: c3
+- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30)
+    = (c0 - (c1 + c2))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+Highest counter ID seen: c1
 
diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map
index 72f39b88c6a9..417637f2d2e3 100644
--- a/tests/coverage/condition/conditions.cov-map
+++ b/tests/coverage/condition/conditions.cov-map
@@ -1,120 +1,103 @@
 Function name: conditions::assign_3_and_or
-Raw bytes (65): 0x[01, 01, 05, 07, 11, 09, 0d, 01, 05, 05, 09, 01, 09, 09, 01, 1c, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0a, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0e, 00, 12, 00, 13, 12, 00, 17, 00, 18, 20, 0d, 11, 00, 17, 00, 18, 03, 01, 05, 01, 02]
+Raw bytes (65): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 1c, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 5
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4)
-- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add)
+- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 28, 1) to (start + 0, 47)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = ((c2 + c3) + c4)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(1), false: Expression(2, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
-- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 18) to (start + 0, 19)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 0, 24)
+- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24)
     = (c0 - c2)
-- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 23) to (start + 0, 24)
+- Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24)
     true  = c3
-    false = c4
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = ((c2 + c3) + c4)
-Highest counter ID seen: c4
+    false = (c0 - (c2 + c3))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c3
 
 Function name: conditions::assign_3_or_and
-Raw bytes (73): 0x[01, 01, 09, 07, 11, 0b, 0d, 05, 09, 01, 05, 01, 05, 01, 23, 05, 11, 01, 23, 05, 11, 09, 01, 17, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 12, 00, 0d, 00, 0e, 12, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 9
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 5 operands: lhs = Counter(0), rhs = Expression(8, Add)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add)
-- expression 8 operands: lhs = Counter(1), rhs = Counter(4)
-Number of file 0 mappings: 9
-- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = (((c1 + c2) + c3) + c4)
-- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(1), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 14)
-    true  = c1
-    false = (c0 - c1)
-- Code(Expression(4, Sub)) at (prev + 0, 18) to (start + 0, 19)
-    = (c0 - c1)
-- Branch { true: Expression(7, Sub), false: Counter(4) } at (prev + 0, 18) to (start + 0, 19)
-    true  = (c0 - (c1 + c4))
-    false = c4
-- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = (c0 - (c1 + c4))
-- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 23) to (start + 0, 24)
-    true  = c2
-    false = c3
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (((c1 + c2) + c3) + c4)
-Highest counter ID seen: c4
-
-Function name: conditions::assign_and
-Raw bytes (51): 0x[01, 01, 04, 07, 05, 0b, 0d, 01, 09, 01, 05, 07, 01, 0d, 01, 00, 21, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 02, 01, 05, 01, 02]
+Raw bytes (63): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 09, 01, 17, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 4
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+Number of file 0 mappings: 9
+- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
+    true  = c1
+    false = (c0 - c1)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
+    = (c0 - c1)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19)
+    true  = c2
+    false = (c0 - (c1 + c2))
+- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 24)
+- Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24)
+    true  = c3
+    false = (c2 - c3)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c3
+
+Function name: conditions::assign_and
+Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 0d, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33)
-- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10)
-    = (((c0 + c2) + c3) - c1)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
-- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
-    false = c3
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+    false = (c1 - c2)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c2
 
 Function name: conditions::assign_or
-Raw bytes (51): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 07, 01, 12, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (49): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 07, 01, 12, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 18, 1) to (start + 0, 32)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = ((c1 + c2) + c3)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
-- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
     = (c0 - c1)
-- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
-    false = c3
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = ((c1 + c2) + c3)
-Highest counter ID seen: c3
+    false = (c0 - (c1 + c2))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c2
 
 Function name: conditions::foo
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02]
@@ -126,26 +109,23 @@ Number of file 0 mappings: 1
 Highest counter ID seen: c0
 
 Function name: conditions::func_call
-Raw bytes (41): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 06, 01, 01, 00, 02]
+Raw bytes (37): 0x[01, 01, 02, 01, 05, 05, 09, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 37, 1) to (start + 1, 10)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 10)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15)
-- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 14) to (start + 0, 15)
+- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 15)
     true  = c2
-    false = c3
-- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+    false = (c1 - c2)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: conditions::simple_assign
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02]
diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map
index 21b2ec9a19e0..549b8bb0a209 100644
--- a/tests/coverage/conditions.cov-map
+++ b/tests/coverage/conditions.cov-map
@@ -1,294 +1,192 @@
 Function name: conditions::main
-Raw bytes (873): 0x[01, 01, b2, 01, 07, 19, 0b, 15, 0f, 11, 09, 0d, 01, 09, 8d, 01, 0d, 8d, 01, 33, 0d, 11, 33, 15, 0d, 11, 2f, 19, 33, 15, 0d, 11, 01, c7, 05, 09, 8d, 01, 03, 21, 03, 47, 21, 89, 01, 03, 4f, db, 03, 89, 01, 21, 25, 03, 5b, d7, 03, 89, 01, db, 03, 29, 21, 25, 77, 2d, 25, 29, 73, 31, 77, 2d, 25, 29, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, 35, 3d, 35, 93, 01, 3d, 85, 01, 35, 9b, 01, af, 01, 85, 01, 3d, 41, 35, a7, 01, ab, 01, 85, 01, af, 01, 45, 3d, 41, c3, 01, 49, 41, 45, bf, 01, 4d, c3, 01, 49, 41, 45, bb, 03, 35, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, bb, 03, 35, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, bb, 03, eb, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, 35, 55, bb, 03, fb, 02, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, eb, 03, 81, 01, 35, 55, bb, 03, ab, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, e7, 03, 81, 01, eb, 03, 59, 35, 55, bb, 03, df, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, e3, 03, 81, 01, e7, 03, 5d, eb, 03, 59, 35, 55, ff, 03, 61, 59, 5d, fb, 03, 65, ff, 03, 61, 59, 5d, 87, 04, 79, 83, 05, 75, 87, 05, 71, 69, 6d, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, ef, 04, 69, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, ef, 04, cb, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 69, 7d, ef, 04, e3, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 87, 05, 7d, 69, 6d, ef, 04, ff, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 83, 05, 7d, 87, 05, 71, 69, 6d, 9b, 05, 75, 6d, 71, 97, 05, 79, 9b, 05, 75, 6d, 71, a3, 05, c7, 05, a7, 05, 89, 01, ab, 05, 85, 01, af, 05, 81, 01, b3, 05, 7d, b7, 05, 79, bb, 05, 75, bf, 05, 71, c3, 05, 6d, 01, 69, 09, 8d, 01, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, 12, 02, 0f, 00, 1c, 8d, 01, 01, 0c, 00, 19, 16, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 19, 02, 09, 00, 0a, 2b, 01, 09, 01, 12, 36, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 1d, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 21, 00, 16, 02, 06, 3e, 02, 0f, 00, 1c, 42, 01, 0c, 00, 19, 4a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 73, 00, 3d, 02, 0a, 31, 02, 09, 00, 0a, 6f, 01, 09, 00, 17, 89, 01, 02, 09, 00, 0f, cf, 03, 03, 08, 00, 0c, 35, 01, 0d, 01, 10, 39, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 35, 02, 0c, 00, 19, 3d, 00, 1a, 02, 0a, 8a, 01, 04, 11, 00, 1e, 8e, 01, 01, 10, 00, 1d, 96, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, bf, 01, 00, 41, 02, 0e, 4d, 02, 0d, 00, 0e, bb, 01, 01, 0d, 00, 1b, 85, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, fe, 01, 02, 09, 01, 0c, 51, 01, 0d, 02, 06, 00, 02, 05, 00, 06, ef, 04, 02, 09, 00, 0a, fe, 01, 00, 10, 00, 1d, 55, 00, 1e, 02, 06, a6, 02, 02, 0f, 00, 1c, d2, 02, 01, 0c, 00, 19, 82, 03, 00, 1d, 00, 2a, b6, 03, 00, 2e, 00, 3c, fb, 03, 00, 3d, 02, 0a, 65, 02, 09, 00, 0a, f7, 03, 01, 09, 00, 17, 81, 01, 02, 0d, 02, 0f, 83, 04, 05, 09, 00, 0a, ef, 04, 00, 10, 00, 1d, 69, 00, 1e, 02, 06, a2, 04, 02, 0f, 00, 1c, b6, 04, 01, 0c, 00, 19, ce, 04, 00, 1d, 00, 2a, ea, 04, 00, 2e, 00, 3c, 97, 05, 00, 3d, 02, 0a, 79, 02, 09, 00, 0a, 93, 05, 01, 09, 00, 17, 7d, 02, 09, 00, 0f, 9e, 05, 02, 01, 00, 02]
+Raw bytes (545): 0x[01, 01, 4d, 09, 0d, 01, 09, 0d, 71, 0d, 27, 71, 75, 27, 79, 71, 75, 0d, 23, 27, 79, 71, 75, 01, 03, 03, 15, 19, 65, 19, 4f, 65, 69, 4f, 6d, 65, 69, 19, 4b, 4f, 6d, 65, 69, 03, ef, 01, 15, 19, 15, 19, 1d, 25, 29, 59, 29, 7f, 59, 5d, 7f, 61, 59, 5d, 29, 7b, 7f, 61, 59, 5d, 1d, 87, 01, 25, 29, e7, 01, 1d, eb, 01, 29, ef, 01, 25, 15, 19, 31, 35, e7, 01, 1d, eb, 01, 29, ef, 01, 25, 15, 19, e7, 01, f7, 01, eb, 01, 29, ef, 01, 25, 15, 19, 1d, 31, 35, 4d, 35, df, 01, 4d, 51, df, 01, 55, 4d, 51, 35, db, 01, df, 01, 55, 4d, 51, e7, 01, f3, 01, eb, 01, 29, ef, 01, 25, 15, 19, f7, 01, 35, 1d, 31, 39, 3d, 31, 35, af, 02, 39, 31, 35, 3d, 41, 3d, a7, 02, 41, 45, a7, 02, 49, 41, 45, 3d, a3, 02, a7, 02, 49, 41, 45, af, 02, b3, 02, 31, 35, 39, 3d, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, 06, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 0d, 01, 09, 01, 12, 2a, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 11, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 15, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 19, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 19, 01, 09, 00, 17, 52, 02, 09, 00, 0f, ef, 01, 03, 08, 00, 0c, 1d, 01, 0d, 01, 10, 21, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 1d, 02, 0c, 00, 19, 25, 00, 1a, 02, 0a, 5e, 04, 11, 00, 1e, 29, 01, 10, 00, 1d, 62, 00, 21, 00, 2e, 66, 00, 32, 00, 40, 7b, 00, 41, 02, 0e, 76, 02, 0d, 00, 0e, 29, 01, 0d, 00, 1b, 82, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 9e, 01, 02, 09, 01, 0c, 2d, 01, 0d, 02, 06, 00, 02, 05, 00, 06, af, 02, 02, 09, 00, 0a, 9e, 01, 00, 10, 00, 1d, 31, 00, 1e, 02, 06, ae, 01, 02, 0f, 00, 1c, 35, 01, 0c, 00, 19, c2, 01, 00, 1d, 00, 2a, c6, 01, 00, 2e, 00, 3c, db, 01, 00, 3d, 02, 0a, d6, 01, 02, 09, 00, 0a, 35, 01, 09, 00, 17, e2, 01, 02, 0d, 02, 0f, b3, 02, 05, 09, 00, 0a, af, 02, 00, 10, 00, 1d, 39, 00, 1e, 02, 06, 82, 02, 02, 0f, 00, 1c, 3d, 01, 0c, 00, 19, 8a, 02, 00, 1d, 00, 2a, 8e, 02, 00, 2e, 00, 3c, a3, 02, 00, 3d, 02, 0a, 9e, 02, 02, 09, 00, 0a, 3d, 01, 09, 00, 17, aa, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 178
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(6)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(5)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 5 operands: lhs = Counter(35), rhs = Counter(3)
-- expression 6 operands: lhs = Counter(35), rhs = Expression(12, Add)
-- expression 7 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 8 operands: lhs = Expression(12, Add), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(6)
-- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(5)
-- expression 12 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 13 operands: lhs = Counter(0), rhs = Expression(177, Add)
-- expression 14 operands: lhs = Counter(2), rhs = Counter(35)
-- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(8)
-- expression 16 operands: lhs = Expression(0, Add), rhs = Expression(17, Add)
-- expression 17 operands: lhs = Counter(8), rhs = Counter(34)
-- expression 18 operands: lhs = Expression(0, Add), rhs = Expression(19, Add)
-- expression 19 operands: lhs = Expression(118, Add), rhs = Counter(34)
-- expression 20 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 21 operands: lhs = Expression(0, Add), rhs = Expression(22, Add)
-- expression 22 operands: lhs = Expression(117, Add), rhs = Counter(34)
-- expression 23 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 24 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 25 operands: lhs = Expression(29, Add), rhs = Counter(11)
-- expression 26 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(12)
-- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(11)
-- expression 29 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 30 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 31 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 32 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 33 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 34 operands: lhs = Counter(13), rhs = Counter(15)
-- expression 35 operands: lhs = Counter(13), rhs = Expression(36, Add)
-- expression 36 operands: lhs = Counter(15), rhs = Counter(33)
-- expression 37 operands: lhs = Counter(13), rhs = Expression(38, Add)
-- expression 38 operands: lhs = Expression(43, Add), rhs = Counter(33)
-- expression 39 operands: lhs = Counter(15), rhs = Counter(16)
-- expression 40 operands: lhs = Counter(13), rhs = Expression(41, Add)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(33)
-- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(17)
-- expression 43 operands: lhs = Counter(15), rhs = Counter(16)
-- expression 44 operands: lhs = Expression(48, Add), rhs = Counter(18)
-- expression 45 operands: lhs = Counter(16), rhs = Counter(17)
-- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(19)
-- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(18)
-- expression 48 operands: lhs = Counter(16), rhs = Counter(17)
-- expression 49 operands: lhs = Expression(110, Add), rhs = Counter(13)
-- expression 50 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 51 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 52 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 53 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 54 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 55 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 56 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 57 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 58 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 59 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 60 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 61 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 62 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 63 operands: lhs = Expression(110, Add), rhs = Counter(13)
-- expression 64 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 65 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 66 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 67 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 68 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 69 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 70 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 71 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 72 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 73 operands: lhs = Expression(110, Add), rhs = Expression(122, Add)
-- expression 74 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 75 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 76 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 77 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 78 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 79 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 80 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 81 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 82 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 83 operands: lhs = Counter(13), rhs = Counter(21)
-- expression 84 operands: lhs = Expression(110, Add), rhs = Expression(94, Add)
-- expression 85 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 86 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 87 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 88 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 89 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 90 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 91 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 92 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 93 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 94 operands: lhs = Expression(122, Add), rhs = Counter(32)
-- expression 95 operands: lhs = Counter(13), rhs = Counter(21)
-- expression 96 operands: lhs = Expression(110, Add), rhs = Expression(106, Add)
-- expression 97 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 98 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 99 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 100 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 101 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 102 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 103 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 104 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 105 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 106 operands: lhs = Expression(121, Add), rhs = Counter(32)
-- expression 107 operands: lhs = Expression(122, Add), rhs = Counter(22)
-- expression 108 operands: lhs = Counter(13), rhs = Counter(21)
-- expression 109 operands: lhs = Expression(110, Add), rhs = Expression(119, Add)
-- expression 110 operands: lhs = Expression(111, Add), rhs = Counter(19)
-- expression 111 operands: lhs = Expression(112, Add), rhs = Counter(18)
-- expression 112 operands: lhs = Expression(113, Add), rhs = Counter(17)
-- expression 113 operands: lhs = Expression(114, Add), rhs = Counter(16)
-- expression 114 operands: lhs = Expression(115, Add), rhs = Counter(15)
-- expression 115 operands: lhs = Expression(116, Add), rhs = Counter(12)
-- expression 116 operands: lhs = Expression(117, Add), rhs = Counter(11)
-- expression 117 operands: lhs = Expression(118, Add), rhs = Counter(10)
-- expression 118 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 119 operands: lhs = Expression(120, Add), rhs = Counter(32)
-- expression 120 operands: lhs = Expression(121, Add), rhs = Counter(23)
-- expression 121 operands: lhs = Expression(122, Add), rhs = Counter(22)
-- expression 122 operands: lhs = Counter(13), rhs = Counter(21)
-- expression 123 operands: lhs = Expression(127, Add), rhs = Counter(24)
-- expression 124 operands: lhs = Counter(22), rhs = Counter(23)
-- expression 125 operands: lhs = Expression(126, Add), rhs = Counter(25)
-- expression 126 operands: lhs = Expression(127, Add), rhs = Counter(24)
-- expression 127 operands: lhs = Counter(22), rhs = Counter(23)
-- expression 128 operands: lhs = Expression(129, Add), rhs = Counter(30)
-- expression 129 operands: lhs = Expression(160, Add), rhs = Counter(29)
-- expression 130 operands: lhs = Expression(161, Add), rhs = Counter(28)
-- expression 131 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 132 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 133 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 134 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 135 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 136 operands: lhs = Expression(155, Add), rhs = Counter(26)
-- expression 137 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 138 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 139 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 140 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 141 operands: lhs = Expression(155, Add), rhs = Expression(146, Add)
-- expression 142 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 143 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 144 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 145 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 146 operands: lhs = Counter(26), rhs = Counter(31)
-- expression 147 operands: lhs = Expression(155, Add), rhs = Expression(152, Add)
-- expression 148 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 149 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 150 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 151 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 152 operands: lhs = Expression(161, Add), rhs = Counter(31)
-- expression 153 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 154 operands: lhs = Expression(155, Add), rhs = Expression(159, Add)
-- expression 155 operands: lhs = Expression(156, Add), rhs = Counter(25)
-- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(24)
-- expression 157 operands: lhs = Expression(158, Add), rhs = Counter(23)
-- expression 158 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 159 operands: lhs = Expression(160, Add), rhs = Counter(31)
-- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(28)
-- expression 161 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 162 operands: lhs = Expression(166, Add), rhs = Counter(29)
-- expression 163 operands: lhs = Counter(27), rhs = Counter(28)
-- expression 164 operands: lhs = Expression(165, Add), rhs = Counter(30)
-- expression 165 operands: lhs = Expression(166, Add), rhs = Counter(29)
-- expression 166 operands: lhs = Counter(27), rhs = Counter(28)
-- expression 167 operands: lhs = Expression(168, Add), rhs = Expression(177, Add)
-- expression 168 operands: lhs = Expression(169, Add), rhs = Counter(34)
-- expression 169 operands: lhs = Expression(170, Add), rhs = Counter(33)
-- expression 170 operands: lhs = Expression(171, Add), rhs = Counter(32)
-- expression 171 operands: lhs = Expression(172, Add), rhs = Counter(31)
-- expression 172 operands: lhs = Expression(173, Add), rhs = Counter(30)
-- expression 173 operands: lhs = Expression(174, Add), rhs = Counter(29)
-- expression 174 operands: lhs = Expression(175, Add), rhs = Counter(28)
-- expression 175 operands: lhs = Expression(176, Add), rhs = Counter(27)
-- expression 176 operands: lhs = Counter(0), rhs = Counter(26)
-- expression 177 operands: lhs = Counter(2), rhs = Counter(35)
+Number of expressions: 77
+- expression 0 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(28)
+- expression 3 operands: lhs = Counter(3), rhs = Expression(9, Add)
+- expression 4 operands: lhs = Counter(28), rhs = Counter(29)
+- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(30)
+- expression 6 operands: lhs = Counter(28), rhs = Counter(29)
+- expression 7 operands: lhs = Counter(3), rhs = Expression(8, Add)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(30)
+- expression 9 operands: lhs = Counter(28), rhs = Counter(29)
+- expression 10 operands: lhs = Counter(0), rhs = Expression(0, Add)
+- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 12 operands: lhs = Counter(6), rhs = Counter(25)
+- expression 13 operands: lhs = Counter(6), rhs = Expression(19, Add)
+- expression 14 operands: lhs = Counter(25), rhs = Counter(26)
+- expression 15 operands: lhs = Expression(19, Add), rhs = Counter(27)
+- expression 16 operands: lhs = Counter(25), rhs = Counter(26)
+- expression 17 operands: lhs = Counter(6), rhs = Expression(18, Add)
+- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(27)
+- expression 19 operands: lhs = Counter(25), rhs = Counter(26)
+- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(59, Add)
+- expression 21 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 22 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 23 operands: lhs = Counter(7), rhs = Counter(9)
+- expression 24 operands: lhs = Counter(10), rhs = Counter(22)
+- expression 25 operands: lhs = Counter(10), rhs = Expression(31, Add)
+- expression 26 operands: lhs = Counter(22), rhs = Counter(23)
+- expression 27 operands: lhs = Expression(31, Add), rhs = Counter(24)
+- expression 28 operands: lhs = Counter(22), rhs = Counter(23)
+- expression 29 operands: lhs = Counter(10), rhs = Expression(30, Add)
+- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(24)
+- expression 31 operands: lhs = Counter(22), rhs = Counter(23)
+- expression 32 operands: lhs = Counter(7), rhs = Expression(33, Add)
+- expression 33 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 34 operands: lhs = Expression(57, Add), rhs = Counter(7)
+- expression 35 operands: lhs = Expression(58, Add), rhs = Counter(10)
+- expression 36 operands: lhs = Expression(59, Add), rhs = Counter(9)
+- expression 37 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 38 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 39 operands: lhs = Expression(57, Add), rhs = Counter(7)
+- expression 40 operands: lhs = Expression(58, Add), rhs = Counter(10)
+- expression 41 operands: lhs = Expression(59, Add), rhs = Counter(9)
+- expression 42 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 43 operands: lhs = Expression(57, Add), rhs = Expression(61, Add)
+- expression 44 operands: lhs = Expression(58, Add), rhs = Counter(10)
+- expression 45 operands: lhs = Expression(59, Add), rhs = Counter(9)
+- expression 46 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 47 operands: lhs = Counter(7), rhs = Counter(12)
+- expression 48 operands: lhs = Counter(13), rhs = Counter(19)
+- expression 49 operands: lhs = Counter(13), rhs = Expression(55, Add)
+- expression 50 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 51 operands: lhs = Expression(55, Add), rhs = Counter(21)
+- expression 52 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 53 operands: lhs = Counter(13), rhs = Expression(54, Add)
+- expression 54 operands: lhs = Expression(55, Add), rhs = Counter(21)
+- expression 55 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(60, Add)
+- expression 57 operands: lhs = Expression(58, Add), rhs = Counter(10)
+- expression 58 operands: lhs = Expression(59, Add), rhs = Counter(9)
+- expression 59 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 60 operands: lhs = Expression(61, Add), rhs = Counter(13)
+- expression 61 operands: lhs = Counter(7), rhs = Counter(12)
+- expression 62 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 63 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 64 operands: lhs = Expression(75, Add), rhs = Counter(14)
+- expression 65 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 66 operands: lhs = Counter(15), rhs = Counter(16)
+- expression 67 operands: lhs = Counter(15), rhs = Expression(73, Add)
+- expression 68 operands: lhs = Counter(16), rhs = Counter(17)
+- expression 69 operands: lhs = Expression(73, Add), rhs = Counter(18)
+- expression 70 operands: lhs = Counter(16), rhs = Counter(17)
+- expression 71 operands: lhs = Counter(15), rhs = Expression(72, Add)
+- expression 72 operands: lhs = Expression(73, Add), rhs = Counter(18)
+- expression 73 operands: lhs = Counter(16), rhs = Counter(17)
+- expression 74 operands: lhs = Expression(75, Add), rhs = Expression(76, Add)
+- expression 75 operands: lhs = Counter(12), rhs = Counter(13)
+- expression 76 operands: lhs = Counter(14), rhs = Counter(15)
 Number of file 0 mappings: 68
 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 6)
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = ((((c2 + c3) + c4) + c5) + c6)
+    = (c2 + c3)
 - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29)
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10)
-- Code(Expression(4, Sub)) at (prev + 2, 15) to (start + 0, 28)
+- Code(Expression(1, Sub)) at (prev + 2, 15) to (start + 0, 28)
     = (c0 - c2)
-- Code(Counter(35)) at (prev + 1, 12) to (start + 0, 25)
-- Code(Expression(5, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = (c35 - c3)
-- Code(Expression(6, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (c35 - (c3 + c4))
-- Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10)
-    = ((c3 + c4) + c5)
-- Code(Counter(6)) at (prev + 2, 9) to (start + 0, 10)
-- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18)
-    = (((c3 + c4) + c5) + c6)
-- Code(Expression(13, Sub)) at (prev + 3, 9) to (start + 0, 15)
-    = (c0 - (c2 + c35))
+- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (c3 - c28)
+- Code(Expression(3, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (c3 - (c28 + c29))
+- Code(Expression(8, Add)) at (prev + 0, 61) to (start + 2, 10)
+    = ((c28 + c29) + c30)
+- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10)
+    = (c3 - ((c28 + c29) + c30))
+- Code(Counter(3)) at (prev + 1, 9) to (start + 1, 18)
+- Code(Expression(10, Sub)) at (prev + 3, 9) to (start + 0, 15)
+    = (c0 - (c2 + c3))
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12)
-    = ((((c2 + c3) + c4) + c5) + c6)
-- Code(Counter(7)) at (prev + 1, 13) to (start + 2, 6)
+    = (c2 + c3)
+- Code(Counter(4)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 6)
 - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21)
-    = ((((c2 + c3) + c4) + c5) + c6)
-- Code(Counter(8)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(15, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = (((((c2 + c3) + c4) + c5) + c6) - c8)
-- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((((c2 + c3) + c4) + c5) + c6) - (c8 + c34))
-- Code(Expression(18, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = (((((c2 + c3) + c4) + c5) + c6) - ((c8 + c9) + c34))
-- Code(Expression(21, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c2 + c3) + c4) + c5) + c6) - (((c8 + c9) + c10) + c34))
-- Code(Expression(28, Add)) at (prev + 0, 61) to (start + 2, 10)
-    = ((c9 + c10) + c11)
-- Code(Counter(12)) at (prev + 2, 9) to (start + 0, 10)
-- Code(Expression(27, Add)) at (prev + 1, 9) to (start + 0, 23)
-    = (((c9 + c10) + c11) + c12)
-- Code(Counter(34)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(115, Add)) at (prev + 3, 8) to (start + 0, 12)
-    = ((((c8 + c9) + c10) + c11) + c12)
-- Code(Counter(13)) at (prev + 1, 13) to (start + 1, 16)
-- Code(Counter(14)) at (prev + 1, 17) to (start + 2, 10)
+    = (c2 + c3)
+- Code(Counter(5)) at (prev + 0, 22) to (start + 2, 6)
+- Code(Expression(11, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = ((c2 + c3) - c5)
+- Code(Counter(6)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(12, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (c6 - c25)
+- Code(Expression(13, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (c6 - (c25 + c26))
+- Code(Expression(18, Add)) at (prev + 0, 61) to (start + 2, 10)
+    = ((c25 + c26) + c27)
+- Code(Expression(17, Sub)) at (prev + 2, 9) to (start + 0, 10)
+    = (c6 - ((c25 + c26) + c27))
+- Code(Counter(6)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15)
+    = ((c2 + c3) - (c5 + c6))
+- Code(Expression(59, Add)) at (prev + 3, 8) to (start + 0, 12)
+    = (c5 + c6)
+- Code(Counter(7)) at (prev + 1, 13) to (start + 1, 16)
+- Code(Counter(8)) at (prev + 1, 17) to (start + 2, 10)
 - Code(Zero) at (prev + 2, 9) to (start + 0, 10)
-- Code(Counter(13)) at (prev + 2, 12) to (start + 0, 25)
-- Code(Counter(15)) at (prev + 0, 26) to (start + 2, 10)
-- Code(Expression(34, Sub)) at (prev + 4, 17) to (start + 0, 30)
-    = (c13 - c15)
-- Code(Expression(35, Sub)) at (prev + 1, 16) to (start + 0, 29)
-    = (c13 - (c15 + c33))
-- Code(Expression(37, Sub)) at (prev + 0, 33) to (start + 0, 46)
-    = (c13 - ((c15 + c16) + c33))
-- Code(Expression(40, Sub)) at (prev + 0, 50) to (start + 0, 64)
-    = (c13 - (((c15 + c16) + c17) + c33))
-- Code(Expression(47, Add)) at (prev + 0, 65) to (start + 2, 14)
-    = ((c16 + c17) + c18)
-- Code(Counter(19)) at (prev + 2, 13) to (start + 0, 14)
-- Code(Expression(46, Add)) at (prev + 1, 13) to (start + 0, 27)
-    = (((c16 + c17) + c18) + c19)
-- Code(Counter(33)) at (prev + 2, 13) to (start + 0, 19)
-- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
-- Code(Expression(63, Sub)) at (prev + 2, 9) to (start + 1, 12)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - c13)
-- Code(Counter(20)) at (prev + 1, 13) to (start + 2, 6)
-- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
-- Code(Expression(155, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = ((((c21 + c22) + c23) + c24) + c25)
-- Code(Expression(63, Sub)) at (prev + 0, 16) to (start + 0, 29)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - c13)
-- Code(Counter(21)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(73, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - (c13 + c21))
-- Code(Expression(84, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - ((c13 + c21) + c32))
-- Code(Expression(96, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - (((c13 + c21) + c22) + c32))
-- Code(Expression(109, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - ((((c13 + c21) + c22) + c23) + c32))
-- Code(Expression(126, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 25)
+- Code(Counter(9)) at (prev + 0, 26) to (start + 2, 10)
+- Code(Expression(23, Sub)) at (prev + 4, 17) to (start + 0, 30)
+    = (c7 - c9)
+- Code(Counter(10)) at (prev + 1, 16) to (start + 0, 29)
+- Code(Expression(24, Sub)) at (prev + 0, 33) to (start + 0, 46)
+    = (c10 - c22)
+- Code(Expression(25, Sub)) at (prev + 0, 50) to (start + 0, 64)
+    = (c10 - (c22 + c23))
+- Code(Expression(30, Add)) at (prev + 0, 65) to (start + 2, 14)
     = ((c22 + c23) + c24)
-- Code(Counter(25)) at (prev + 2, 9) to (start + 0, 10)
-- Code(Expression(125, Add)) at (prev + 1, 9) to (start + 0, 23)
-    = (((c22 + c23) + c24) + c25)
-- Code(Counter(32)) at (prev + 2, 13) to (start + 2, 15)
-- Code(Expression(128, Add)) at (prev + 5, 9) to (start + 0, 10)
-    = ((((c26 + c27) + c28) + c29) + c30)
-- Code(Expression(155, Add)) at (prev + 0, 16) to (start + 0, 29)
-    = ((((c21 + c22) + c23) + c24) + c25)
-- Code(Counter(26)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(136, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = (((((c21 + c22) + c23) + c24) + c25) - c26)
-- Code(Expression(141, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((((c21 + c22) + c23) + c24) + c25) - (c26 + c31))
-- Code(Expression(147, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = (((((c21 + c22) + c23) + c24) + c25) - ((c26 + c27) + c31))
-- Code(Expression(154, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c21 + c22) + c23) + c24) + c25) - (((c26 + c27) + c28) + c31))
-- Code(Expression(165, Add)) at (prev + 0, 61) to (start + 2, 10)
-    = ((c27 + c28) + c29)
-- Code(Counter(30)) at (prev + 2, 9) to (start + 0, 10)
-- Code(Expression(164, Add)) at (prev + 1, 9) to (start + 0, 23)
-    = (((c27 + c28) + c29) + c30)
-- Code(Counter(31)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(167, Sub)) at (prev + 2, 1) to (start + 0, 2)
-    = ((((((((((c0 + c26) + c27) + c28) + c29) + c30) + c31) + c32) + c33) + c34) - (c2 + c35))
-Highest counter ID seen: c35
+- Code(Expression(29, Sub)) at (prev + 2, 13) to (start + 0, 14)
+    = (c10 - ((c22 + c23) + c24))
+- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 27)
+- Code(Expression(32, Sub)) at (prev + 2, 13) to (start + 0, 19)
+    = (c7 - (c9 + c10))
+- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
+- Code(Expression(39, Sub)) at (prev + 2, 9) to (start + 1, 12)
+    = ((((c5 + c6) + c9) + c10) - c7)
+- Code(Counter(11)) at (prev + 1, 13) to (start + 2, 6)
+- Code(Zero) at (prev + 2, 5) to (start + 0, 6)
+- Code(Expression(75, Add)) at (prev + 2, 9) to (start + 0, 10)
+    = (c12 + c13)
+- Code(Expression(39, Sub)) at (prev + 0, 16) to (start + 0, 29)
+    = ((((c5 + c6) + c9) + c10) - c7)
+- Code(Counter(12)) at (prev + 0, 30) to (start + 2, 6)
+- Code(Expression(43, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = ((((c5 + c6) + c9) + c10) - (c7 + c12))
+- Code(Counter(13)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(48, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (c13 - c19)
+- Code(Expression(49, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (c13 - (c19 + c20))
+- Code(Expression(54, Add)) at (prev + 0, 61) to (start + 2, 10)
+    = ((c19 + c20) + c21)
+- Code(Expression(53, Sub)) at (prev + 2, 9) to (start + 0, 10)
+    = (c13 - ((c19 + c20) + c21))
+- Code(Counter(13)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(56, Sub)) at (prev + 2, 13) to (start + 2, 15)
+    = ((((c5 + c6) + c9) + c10) - ((c7 + c12) + c13))
+- Code(Expression(76, Add)) at (prev + 5, 9) to (start + 0, 10)
+    = (c14 + c15)
+- Code(Expression(75, Add)) at (prev + 0, 16) to (start + 0, 29)
+    = (c12 + c13)
+- Code(Counter(14)) at (prev + 0, 30) to (start + 2, 6)
+- Code(Expression(64, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = ((c12 + c13) - c14)
+- Code(Counter(15)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(66, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (c15 - c16)
+- Code(Expression(67, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (c15 - (c16 + c17))
+- Code(Expression(72, Add)) at (prev + 0, 61) to (start + 2, 10)
+    = ((c16 + c17) + c18)
+- Code(Expression(71, Sub)) at (prev + 2, 9) to (start + 0, 10)
+    = (c15 - ((c16 + c17) + c18))
+- Code(Counter(15)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(74, Sub)) at (prev + 2, 9) to (start + 0, 15)
+    = ((c12 + c13) - (c14 + c15))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
+Highest counter ID seen: c15
 
diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map
index 55313d7db49e..eb968fbb747a 100644
--- a/tests/coverage/continue.cov-map
+++ b/tests/coverage/continue.cov-map
@@ -1,5 +1,5 @@
 Function name: continue::main
-Raw bytes (210): 0x[01, 01, 1c, 07, 09, 01, 05, 03, 0d, 1f, 15, 0d, 11, 1b, 19, 1f, 15, 0d, 11, 33, 21, 19, 1d, 2f, 25, 33, 21, 19, 1d, 47, 2d, 25, 29, 43, 31, 47, 2d, 25, 29, 5b, 39, 31, 35, 57, 3d, 5b, 39, 31, 35, 35, 39, 3d, 41, 6b, 45, 3d, 41, 45, 49, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 6f, 02, 0d, 01, 02]
+Raw bytes (210): 0x[01, 01, 1c, 07, 09, 01, 05, 03, 0d, 1f, 15, 0d, 11, 1b, 19, 1f, 15, 0d, 11, 33, 21, 19, 1d, 2f, 25, 33, 21, 19, 1d, 47, 2d, 25, 29, 43, 31, 47, 2d, 25, 29, 5b, 39, 31, 35, 57, 3d, 5b, 39, 31, 35, 35, 39, 3d, 41, 6b, 45, 3d, 41, 3d, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 6e, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 3d, 02, 0d, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 28
@@ -30,7 +30,7 @@ Number of expressions: 28
 - expression 24 operands: lhs = Counter(15), rhs = Counter(16)
 - expression 25 operands: lhs = Expression(26, Add), rhs = Counter(17)
 - expression 26 operands: lhs = Counter(15), rhs = Counter(16)
-- expression 27 operands: lhs = Counter(17), rhs = Counter(18)
+- expression 27 operands: lhs = Counter(15), rhs = Counter(17)
 Number of file 0 mappings: 30
 - Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18)
 - Code(Expression(0, Add)) at (prev + 4, 14) to (start + 0, 19)
@@ -72,9 +72,9 @@ Number of file 0 mappings: 30
 - Code(Expression(25, Sub)) at (prev + 1, 15) to (start + 0, 22)
     = ((c15 + c16) - c17)
 - Code(Counter(16)) at (prev + 1, 22) to (start + 2, 14)
-- Code(Counter(18)) at (prev + 4, 17) to (start + 0, 22)
+- Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 22)
+    = (c15 - c17)
 - Code(Counter(16)) at (prev + 3, 9) to (start + 0, 14)
-- Code(Expression(27, Add)) at (prev + 2, 13) to (start + 1, 2)
-    = (c17 + c18)
-Highest counter ID seen: c18
+- Code(Counter(15)) at (prev + 2, 13) to (start + 1, 2)
+Highest counter ID seen: c16
 
diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map
index 21f6787e9f2d..7457a528a869 100644
--- a/tests/coverage/coroutine.cov-map
+++ b/tests/coverage/coroutine.cov-map
@@ -13,18 +13,14 @@ Number of file 0 mappings: 4
 Highest counter ID seen: c1
 
 Function name: coroutine::main
-Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 11, 1f, 15, 19, 15, 19, 11, 1f, 15, 19, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 0a, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 1f, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
+Raw bytes (57): 0x[01, 01, 04, 07, 0d, 05, 09, 11, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 0a, 01, 22, 00, 27, 15, 00, 2c, 00, 2e, 0e, 01, 0e, 00, 35, 15, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 8
+Number of expressions: 4
 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 3 operands: lhs = Counter(4), rhs = Expression(7, Add)
-- expression 4 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 6 operands: lhs = Counter(4), rhs = Expression(7, Add)
-- expression 7 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 2 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 3 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22)
 - Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46)
@@ -33,14 +29,12 @@ Number of file 0 mappings: 9
     = ((c1 + c2) + c3)
 - Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46)
 - Code(Expression(2, Sub)) at (prev + 1, 34) to (start + 0, 39)
+    = (c4 - c6)
+- Code(Counter(5)) at (prev + 0, 44) to (start + 0, 46)
+- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 53)
     = (c4 - c5)
-- Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 46)
-    = (c4 - (c5 + c6))
-- Code(Expression(7, Add)) at (prev + 1, 14) to (start + 0, 53)
-    = (c5 + c6)
-- Code(Expression(6, Sub)) at (prev + 2, 1) to (start + 0, 2)
-    = (c4 - (c5 + c6))
-Highest counter ID seen: c4
+- Code(Counter(5)) at (prev + 2, 1) to (start + 0, 2)
+Highest counter ID seen: c5
 
 Function name: coroutine::main::{closure#0}
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06]
diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map
index 1b5b45695dc9..39ba2b2d99bf 100644
--- a/tests/coverage/inline.cov-map
+++ b/tests/coverage/inline.cov-map
@@ -41,7 +41,7 @@ Number of file 0 mappings: 1
 Highest counter ID seen: c0
 
 Function name: inline::permutate::
-Raw bytes (54): 0x[01, 01, 05, 01, 05, 01, 0b, 05, 0d, 13, 0d, 05, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 06, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 0d, 05, 0c, 02, 06, 0f, 03, 01, 00, 02]
+Raw bytes (54): 0x[01, 01, 05, 01, 05, 01, 0b, 05, 0d, 13, 0d, 01, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 0d, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 06, 05, 0c, 02, 06, 0e, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 5
@@ -49,19 +49,19 @@ Number of expressions: 5
 - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(3)
 - expression 3 operands: lhs = Expression(4, Add), rhs = Counter(3)
-- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14)
 - Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20)
     = (c0 - c1)
 - Code(Counter(4)) at (prev + 1, 13) to (start + 0, 14)
-- Code(Expression(1, Sub)) at (prev + 0, 18) to (start + 0, 22)
-    = (c0 - (c1 + c3))
+- Code(Counter(3)) at (prev + 0, 18) to (start + 0, 22)
 - Code(Counter(4)) at (prev + 0, 23) to (start + 4, 10)
-- Code(Counter(3)) at (prev + 5, 12) to (start + 2, 6)
-- Code(Expression(3, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c1 + c2) + c3)
+- Code(Expression(1, Sub)) at (prev + 5, 12) to (start + 2, 6)
+    = (c0 - (c1 + c3))
+- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
+    = ((c0 + c2) - c3)
 Highest counter ID seen: c4
 
 Function name: inline::permutations::
diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map
index 14707701d8a8..0279a1a51579 100644
--- a/tests/coverage/loops_branches.cov-map
+++ b/tests/coverage/loops_branches.cov-map
@@ -1,42 +1,32 @@
 Function name: ::fmt
-Raw bytes (174): 0x[01, 01, 22, 05, 00, 2f, 7b, 67, 00, 77, 19, 01, 15, 05, 21, 2f, 05, 67, 00, 77, 19, 01, 15, 2f, 7b, 67, 00, 77, 19, 01, 15, 05, 21, 67, 7b, 77, 19, 01, 15, 05, 21, 67, 5b, 77, 19, 01, 15, 7b, 00, 05, 21, 67, 7b, 77, 19, 01, 15, 05, 21, 77, 7b, 01, 15, 05, 21, 83, 01, 05, 87, 01, 15, 01, 11, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 2a, 03, 0d, 00, 0e, 1a, 00, 12, 00, 17, 2a, 01, 10, 00, 14, 62, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4e, 01, 11, 00, 12, 62, 01, 11, 00, 22, 72, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 21, 03, 09, 00, 0f, 7e, 01, 05, 00, 06]
+Raw bytes (152): 0x[01, 01, 18, 05, 00, 27, 57, 53, 00, 01, 1d, 11, 19, 27, 11, 53, 00, 01, 1d, 27, 57, 53, 00, 01, 1d, 11, 19, 53, 57, 01, 1d, 11, 19, 53, 47, 01, 1d, 57, 00, 11, 19, 53, 57, 01, 1d, 11, 19, 5f, 19, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 22, 03, 0d, 00, 0e, 16, 00, 12, 00, 17, 22, 01, 10, 00, 14, 4e, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 3e, 01, 11, 00, 12, 4e, 01, 11, 00, 22, 15, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 5b, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 34
+Number of expressions: 24
 - expression 0 operands: lhs = Counter(1), rhs = Zero
-- expression 1 operands: lhs = Expression(11, Add), rhs = Expression(30, Add)
-- expression 2 operands: lhs = Expression(25, Add), rhs = Zero
-- expression 3 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 5 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(1)
-- expression 7 operands: lhs = Expression(25, Add), rhs = Zero
-- expression 8 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 9 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 10 operands: lhs = Expression(11, Add), rhs = Expression(30, Add)
-- expression 11 operands: lhs = Expression(25, Add), rhs = Zero
-- expression 12 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 13 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 14 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 15 operands: lhs = Expression(25, Add), rhs = Expression(30, Add)
-- expression 16 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 17 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 18 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 19 operands: lhs = Expression(25, Add), rhs = Expression(22, Add)
-- expression 20 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 21 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 22 operands: lhs = Expression(30, Add), rhs = Zero
-- expression 23 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 24 operands: lhs = Expression(25, Add), rhs = Expression(30, Add)
-- expression 25 operands: lhs = Expression(29, Add), rhs = Counter(6)
-- expression 26 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 27 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 28 operands: lhs = Expression(29, Add), rhs = Expression(30, Add)
-- expression 29 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 30 operands: lhs = Counter(1), rhs = Counter(8)
-- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(1)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(5)
-- expression 33 operands: lhs = Counter(0), rhs = Counter(4)
+- expression 1 operands: lhs = Expression(9, Add), rhs = Expression(21, Add)
+- expression 2 operands: lhs = Expression(20, Add), rhs = Zero
+- expression 3 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Expression(20, Add), rhs = Zero
+- expression 7 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Expression(21, Add)
+- expression 9 operands: lhs = Expression(20, Add), rhs = Zero
+- expression 10 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 11 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 12 operands: lhs = Expression(20, Add), rhs = Expression(21, Add)
+- expression 13 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 14 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 15 operands: lhs = Expression(20, Add), rhs = Expression(17, Add)
+- expression 16 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 17 operands: lhs = Expression(21, Add), rhs = Zero
+- expression 18 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 19 operands: lhs = Expression(20, Add), rhs = Expression(21, Add)
+- expression 20 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 21 operands: lhs = Counter(4), rhs = Counter(6)
+- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(6)
+- expression 23 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21)
@@ -47,57 +37,57 @@ Number of file 0 mappings: 20
 - Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30)
 - Code(Counter(4)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Zero) at (prev + 1, 16) to (start + 1, 10)
-- Code(Expression(10, Sub)) at (prev + 3, 13) to (start + 0, 14)
-    = ((((c0 + c5) + c6) + Zero) - (c1 + c8))
-- Code(Expression(6, Sub)) at (prev + 0, 18) to (start + 0, 23)
-    = ((((c0 + c5) + c6) + Zero) - c1)
-- Code(Expression(10, Sub)) at (prev + 1, 16) to (start + 0, 20)
-    = ((((c0 + c5) + c6) + Zero) - (c1 + c8))
-- Code(Expression(24, Sub)) at (prev + 1, 20) to (start + 0, 25)
-    = (((c0 + c5) + c6) - (c1 + c8))
+- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 14)
+    = (((c0 + c7) + Zero) - (c4 + c6))
+- Code(Expression(5, Sub)) at (prev + 0, 18) to (start + 0, 23)
+    = (((c0 + c7) + Zero) - c4)
+- Code(Expression(8, Sub)) at (prev + 1, 16) to (start + 0, 20)
+    = (((c0 + c7) + Zero) - (c4 + c6))
+- Code(Expression(19, Sub)) at (prev + 1, 20) to (start + 0, 25)
+    = ((c0 + c7) - (c4 + c6))
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 18)
-    = (((c0 + c5) + c6) - ((c1 + c8) + Zero))
-- Code(Expression(24, Sub)) at (prev + 1, 17) to (start + 0, 34)
-    = (((c0 + c5) + c6) - (c1 + c8))
-- Code(Expression(28, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((c0 + c5) - (c1 + c8))
+- Code(Expression(15, Sub)) at (prev + 1, 17) to (start + 0, 18)
+    = ((c0 + c7) - ((c4 + c6) + Zero))
+- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((c0 + c7) - (c4 + c6))
+- Code(Counter(5)) at (prev + 0, 34) to (start + 0, 35)
 - Code(Zero) at (prev + 1, 20) to (start + 1, 14)
-- Code(Counter(8)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(31, Sub)) at (prev + 1, 5) to (start + 0, 6)
-    = (((c0 + c4) + c5) - c1)
-Highest counter ID seen: c8
+- Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
+- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = ((c4 + c5) + c6)
+Highest counter ID seen: c6
 
 Function name: ::fmt
-Raw bytes (152): 0x[01, 01, 18, 01, 00, 01, 00, 23, 15, 27, 11, 00, 0d, 27, 11, 00, 0d, 23, 15, 27, 11, 00, 0d, 4b, 15, 4f, 11, 00, 0d, 4b, 43, 4f, 11, 00, 0d, 15, 00, 4b, 15, 4f, 11, 00, 0d, 5f, 15, 00, 11, 5f, 21, 00, 11, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 21, 00, 1e, 00, 1f, 1e, 02, 0d, 00, 0e, 23, 00, 12, 00, 17, 1e, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 46, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 36, 01, 11, 00, 12, 46, 01, 11, 00, 22, 52, 00, 22, 00, 23, 15, 03, 09, 00, 0f, 5b, 01, 05, 00, 06]
+Raw bytes (154): 0x[01, 01, 19, 01, 00, 01, 00, 2b, 63, 2f, 0d, 01, 00, 11, 15, 2b, 11, 2f, 0d, 01, 00, 2b, 63, 2f, 0d, 01, 00, 11, 15, 57, 63, 01, 0d, 11, 15, 57, 4b, 01, 0d, 63, 00, 11, 15, 57, 63, 01, 0d, 11, 15, 63, 21, 11, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 26, 02, 0d, 00, 0e, 1a, 00, 12, 00, 17, 26, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 52, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 42, 01, 11, 00, 12, 52, 01, 11, 00, 22, 21, 00, 22, 00, 23, 15, 03, 09, 00, 0f, 5f, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 24
+Number of expressions: 25
 - expression 0 operands: lhs = Counter(0), rhs = Zero
 - expression 1 operands: lhs = Counter(0), rhs = Zero
-- expression 2 operands: lhs = Expression(8, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Zero, rhs = Counter(3)
-- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 6 operands: lhs = Zero, rhs = Counter(3)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(5)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 9 operands: lhs = Zero, rhs = Counter(3)
-- expression 10 operands: lhs = Expression(18, Add), rhs = Counter(5)
-- expression 11 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 12 operands: lhs = Zero, rhs = Counter(3)
-- expression 13 operands: lhs = Expression(18, Add), rhs = Expression(16, Add)
-- expression 14 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 15 operands: lhs = Zero, rhs = Counter(3)
-- expression 16 operands: lhs = Counter(5), rhs = Zero
-- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(5)
-- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 19 operands: lhs = Zero, rhs = Counter(3)
-- expression 20 operands: lhs = Expression(23, Add), rhs = Counter(5)
-- expression 21 operands: lhs = Zero, rhs = Counter(4)
-- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(8)
-- expression 23 operands: lhs = Zero, rhs = Counter(4)
+- expression 2 operands: lhs = Expression(10, Add), rhs = Expression(24, Add)
+- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(3)
+- expression 4 operands: lhs = Counter(0), rhs = Zero
+- expression 5 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 6 operands: lhs = Expression(10, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Expression(11, Add), rhs = Counter(3)
+- expression 8 operands: lhs = Counter(0), rhs = Zero
+- expression 9 operands: lhs = Expression(10, Add), rhs = Expression(24, Add)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(3)
+- expression 11 operands: lhs = Counter(0), rhs = Zero
+- expression 12 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 13 operands: lhs = Expression(21, Add), rhs = Expression(24, Add)
+- expression 14 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 15 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 16 operands: lhs = Expression(21, Add), rhs = Expression(18, Add)
+- expression 17 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 18 operands: lhs = Expression(24, Add), rhs = Zero
+- expression 19 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 20 operands: lhs = Expression(21, Add), rhs = Expression(24, Add)
+- expression 21 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 22 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(8)
+- expression 24 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17)
 - Code(Zero) at (prev + 1, 18) to (start + 1, 10)
@@ -109,27 +99,26 @@ Number of file 0 mappings: 20
     = (c0 - Zero)
 - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30)
     = (c0 - Zero)
-- Code(Counter(8)) at (prev + 0, 30) to (start + 0, 31)
-- Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 14)
-    = (((Zero + c3) + c4) - c5)
-- Code(Expression(8, Add)) at (prev + 0, 18) to (start + 0, 23)
-    = ((Zero + c3) + c4)
-- Code(Expression(7, Sub)) at (prev + 1, 16) to (start + 0, 21)
-    = (((Zero + c3) + c4) - c5)
+- Code(Counter(4)) at (prev + 0, 30) to (start + 0, 31)
+- Code(Expression(9, Sub)) at (prev + 2, 13) to (start + 0, 14)
+    = (((c0 + Zero) + c3) - (c4 + c5))
+- Code(Expression(6, Sub)) at (prev + 0, 18) to (start + 0, 23)
+    = (((c0 + Zero) + c3) - c4)
+- Code(Expression(9, Sub)) at (prev + 1, 16) to (start + 0, 21)
+    = (((c0 + Zero) + c3) - (c4 + c5))
 - Code(Zero) at (prev + 0, 22) to (start + 1, 14)
-- Code(Expression(17, Sub)) at (prev + 2, 20) to (start + 0, 25)
-    = (((Zero + c3) + c4) - c5)
+- Code(Expression(20, Sub)) at (prev + 2, 20) to (start + 0, 25)
+    = ((c0 + c3) - (c4 + c5))
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(13, Sub)) at (prev + 1, 17) to (start + 0, 18)
-    = (((Zero + c3) + c4) - (c5 + Zero))
-- Code(Expression(17, Sub)) at (prev + 1, 17) to (start + 0, 34)
-    = (((Zero + c3) + c4) - c5)
-- Code(Expression(20, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + c4) - c5)
+- Code(Expression(16, Sub)) at (prev + 1, 17) to (start + 0, 18)
+    = ((c0 + c3) - ((c4 + c5) + Zero))
+- Code(Expression(20, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((c0 + c3) - (c4 + c5))
+- Code(Counter(8)) at (prev + 0, 34) to (start + 0, 35)
 - Code(Counter(5)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((Zero + c4) + c8)
+- Code(Expression(23, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = ((c4 + c5) + c8)
 Highest counter ID seen: c8
 
 Function name: loops_branches::main
diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map
index 19716878600d..8ff5d6360f67 100644
--- a/tests/coverage/mcdc/condition-limit.cov-map
+++ b/tests/coverage/mcdc/condition-limit.cov-map
@@ -1,54 +1,16 @@
 Function name: condition_limit::accept_7_conditions
-Raw bytes (237): 0x[01, 01, 2e, 01, 05, 05, 09, 05, 09, 05, 7b, 09, 0d, 05, 7b, 09, 0d, 05, 77, 7b, 11, 09, 0d, 05, 77, 7b, 11, 09, 0d, 05, 73, 77, 15, 7b, 11, 09, 0d, 05, 73, 77, 15, 7b, 11, 09, 0d, 05, 6f, 73, 19, 77, 15, 7b, 11, 09, 0d, 05, 6f, 73, 19, 77, 15, 7b, 11, 09, 0d, 83, 01, 05, a7, 01, 21, ab, 01, 19, af, 01, 15, b3, 01, 11, b7, 01, 0d, 01, 09, 9f, 01, 05, a3, 01, 21, a7, 01, 1d, ab, 01, 19, af, 01, 15, b3, 01, 11, b7, 01, 0d, 01, 09, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0a, 09, 07, 06, 00, 00, 0d, 00, 0e, 0a, 00, 12, 00, 13, 30, 16, 0d, 06, 05, 00, 00, 12, 00, 13, 16, 00, 17, 00, 18, 30, 2a, 11, 05, 04, 00, 00, 17, 00, 18, 2a, 00, 1c, 00, 1d, 30, 46, 15, 04, 03, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 6a, 19, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 1d, 21, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 7e, 02, 05, 00, 06, 9a, 01, 01, 01, 00, 02]
+Raw bytes (147): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 46
+Number of expressions: 8
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(30, Add)
-- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(1), rhs = Expression(30, Add)
-- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 7 operands: lhs = Counter(1), rhs = Expression(29, Add)
-- expression 8 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 9 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(29, Add)
-- expression 11 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 12 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 13 operands: lhs = Counter(1), rhs = Expression(28, Add)
-- expression 14 operands: lhs = Expression(29, Add), rhs = Counter(5)
-- expression 15 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 16 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 17 operands: lhs = Counter(1), rhs = Expression(28, Add)
-- expression 18 operands: lhs = Expression(29, Add), rhs = Counter(5)
-- expression 19 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 20 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(1), rhs = Expression(27, Add)
-- expression 22 operands: lhs = Expression(28, Add), rhs = Counter(6)
-- expression 23 operands: lhs = Expression(29, Add), rhs = Counter(5)
-- expression 24 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 25 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 26 operands: lhs = Counter(1), rhs = Expression(27, Add)
-- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(6)
-- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(5)
-- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(4)
-- expression 30 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(1)
-- expression 32 operands: lhs = Expression(41, Add), rhs = Counter(8)
-- expression 33 operands: lhs = Expression(42, Add), rhs = Counter(6)
-- expression 34 operands: lhs = Expression(43, Add), rhs = Counter(5)
-- expression 35 operands: lhs = Expression(44, Add), rhs = Counter(4)
-- expression 36 operands: lhs = Expression(45, Add), rhs = Counter(3)
-- expression 37 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(1)
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(8)
-- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(7)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(6)
-- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(5)
-- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(4)
-- expression 44 operands: lhs = Expression(45, Add), rhs = Counter(3)
-- expression 45 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
+- expression 5 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 6 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 7 operands: lhs = Counter(0), rhs = Counter(7)
 Number of file 0 mappings: 18
 - Code(Counter(0)) at (prev + 7, 1) to (start + 2, 9)
 - MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39)
@@ -56,38 +18,32 @@ Number of file 0 mappings: 18
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- MCDCBranch { true: Expression(2, Sub), false: Counter(2), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
-    true  = (c1 - c2)
-    false = c2
-- Code(Expression(2, Sub)) at (prev + 0, 18) to (start + 0, 19)
-    = (c1 - c2)
-- MCDCBranch { true: Expression(5, Sub), false: Counter(3), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
-    true  = (c1 - (c2 + c3))
-    false = c3
-- Code(Expression(5, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = (c1 - (c2 + c3))
-- MCDCBranch { true: Expression(10, Sub), false: Counter(4), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
-    true  = (c1 - ((c2 + c3) + c4))
-    false = c4
-- Code(Expression(10, Sub)) at (prev + 0, 28) to (start + 0, 29)
-    = (c1 - ((c2 + c3) + c4))
-- MCDCBranch { true: Expression(17, Sub), false: Counter(5), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
-    true  = (c1 - (((c2 + c3) + c4) + c5))
-    false = c5
-- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34)
-    = (c1 - (((c2 + c3) + c4) + c5))
-- MCDCBranch { true: Expression(26, Sub), false: Counter(6), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
-    true  = (c1 - ((((c2 + c3) + c4) + c5) + c6))
-    false = c6
-- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39)
-    = (c1 - ((((c2 + c3) + c4) + c5) + c6))
-- MCDCBranch { true: Counter(7), false: Counter(8), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+    true  = c2
+    false = (c1 - c2)
+- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19)
+- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
+    true  = c3
+    false = (c2 - c3)
+- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 24)
+- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
+    true  = c4
+    false = (c3 - c4)
+- Code(Counter(4)) at (prev + 0, 28) to (start + 0, 29)
+- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
+    true  = c5
+    false = (c4 - c5)
+- Code(Counter(5)) at (prev + 0, 33) to (start + 0, 34)
+- MCDCBranch { true: Counter(6), false: Expression(5, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
+    true  = c6
+    false = (c5 - c6)
+- Code(Counter(6)) at (prev + 0, 38) to (start + 0, 39)
+- MCDCBranch { true: Counter(7), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39)
     true  = c7
-    false = c8
+    false = (c6 - c7)
 - Code(Counter(7)) at (prev + 0, 40) to (start + 2, 6)
-- Code(Expression(31, Sub)) at (prev + 2, 5) to (start + 0, 6)
-    = (((((((c0 + c2) + c3) + c4) + c5) + c6) + c8) - c1)
-- Code(Expression(38, Sub)) at (prev + 1, 1) to (start + 0, 2)
-    = ((((((((c0 + c2) + c3) + c4) + c5) + c6) + c7) + c8) - c1)
-Highest counter ID seen: c8
+- Code(Expression(7, Sub)) at (prev + 2, 5) to (start + 0, 6)
+    = (c0 - c7)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c7
 
diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map
index acb8aac63de5..771351f649f1 100644
--- a/tests/coverage/mcdc/if.cov-map
+++ b/tests/coverage/mcdc/if.cov-map
@@ -1,14 +1,11 @@
 Function name: if::mcdc_check_a
-Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02]
+Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14)
@@ -16,27 +13,23 @@ Number of file 0 mappings: 8
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
-    false = c3
+    false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c3) - c1)
-- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: if::mcdc_check_b
-Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02]
+Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 23, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14)
@@ -44,27 +37,23 @@ Number of file 0 mappings: 8
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
-    false = c3
+    false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c3) - c1)
-- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: if::mcdc_check_both
-Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02]
+Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 31, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14)
@@ -72,27 +61,23 @@ Number of file 0 mappings: 8
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
-    false = c3
+    false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c3) - c1)
-- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: if::mcdc_check_neither
-Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02]
+Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14)
@@ -100,32 +85,27 @@ Number of file 0 mappings: 8
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
-    false = c3
+    false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c3) - c1)
-- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: if::mcdc_check_not_tree_decision
-Raw bytes (93): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 17, 2b, 01, 11, 05, 09, 23, 2b, 27, 11, 01, 0d, 05, 09, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 2b, 00, 14, 00, 15, 30, 0d, 11, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 12, 02, 0c, 02, 06, 1e, 03, 01, 00, 02]
+Raw bytes (85): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 11
+Number of expressions: 7
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Expression(10, Add)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(4)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Expression(10, Add)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 9 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 10 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 6 operands: lhs = Counter(0), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 49, 1) to (start + 3, 10)
 - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21)
@@ -137,33 +117,30 @@ Number of file 0 mappings: 10
 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
     true  = c2
     false = (c0 - (c1 + c2))
-- Code(Expression(10, Add)) at (prev + 0, 20) to (start + 0, 21)
+- Code(Expression(5, Add)) at (prev + 0, 20) to (start + 0, 21)
     = (c1 + c2)
-- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 20) to (start + 0, 21)
+- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 20) to (start + 0, 21)
     true  = c3
-    false = c4
+    false = ((c1 + c2) - c3)
 - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c4) - (c1 + c2))
-- Code(Expression(7, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = (((c0 + c3) + c4) - (c1 + c2))
-Highest counter ID seen: c4
+- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
 Function name: if::mcdc_check_tree_decision
-Raw bytes (91): 0x[01, 01, 0a, 01, 05, 05, 09, 05, 09, 09, 0d, 17, 05, 01, 11, 1f, 05, 23, 11, 27, 0d, 01, 09, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 11, 03, 00, 00, 00, 13, 00, 14, 0f, 00, 16, 02, 06, 12, 02, 0c, 02, 06, 1a, 03, 01, 00, 02]
+Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 10
+Number of expressions: 8
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(1)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(4)
-- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(1)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(4)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(3)
-- expression 9 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 39, 1) to (start + 3, 9)
 - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21)
@@ -176,38 +153,32 @@ Number of file 0 mappings: 10
     false = (c1 - c2)
 - Code(Expression(2, Sub)) at (prev + 0, 19) to (start + 0, 20)
     = (c1 - c2)
-- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
+- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
     true  = c3
-    false = c4
-- Code(Expression(3, Add)) at (prev + 0, 22) to (start + 2, 6)
+    false = (c1 - (c2 + c3))
+- Code(Expression(7, Add)) at (prev + 0, 22) to (start + 2, 6)
     = (c2 + c3)
-- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c0 + c4) - c1)
-- Code(Expression(6, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((((c0 + c2) + c3) + c4) - c1)
-Highest counter ID seen: c4
+- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - (c2 + c3))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
 Function name: if::mcdc_nested_if
-Raw bytes (130): 0x[01, 01, 10, 01, 05, 01, 3f, 05, 09, 05, 09, 3f, 0d, 05, 09, 3f, 0d, 05, 09, 0d, 15, 01, 3f, 05, 09, 33, 3f, 37, 15, 3b, 11, 01, 0d, 05, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 3f, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 1a, 0d, 01, 02, 00, 00, 0c, 00, 0d, 1a, 00, 11, 00, 12, 30, 11, 15, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 23, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 2e, 03, 01, 00, 02]
+Raw bytes (120): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 2b, 0d, 05, 09, 0d, 11, 2b, 11, 05, 09, 01, 2b, 05, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 2b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 0d, 12, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 1a, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 1e, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 16
+Number of expressions: 11
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(0), rhs = Expression(15, Add)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(15, Add), rhs = Counter(3)
+- expression 4 operands: lhs = Expression(10, Add), rhs = Counter(3)
 - expression 5 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 6 operands: lhs = Expression(15, Add), rhs = Counter(3)
-- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(3), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(0), rhs = Expression(15, Add)
+- expression 6 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 7 operands: lhs = Expression(10, Add), rhs = Counter(4)
+- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 9 operands: lhs = Counter(0), rhs = Expression(10, Add)
 - expression 10 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(15, Add)
-- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(5)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(0), rhs = Counter(3)
-- expression 15 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 14
 - Code(Counter(0)) at (prev + 59, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14)
@@ -219,23 +190,21 @@ Number of file 0 mappings: 14
 - MCDCBranch { true: Counter(2), false: Expression(9, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
     false = (c0 - (c1 + c2))
-- Code(Expression(15, Add)) at (prev + 1, 9) to (start + 1, 13)
+- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 13)
     = (c1 + c2)
 - MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18)
-- MCDCBranch { true: Expression(6, Sub), false: Counter(3), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13)
-    true  = ((c1 + c2) - c3)
-    false = c3
-- Code(Expression(6, Sub)) at (prev + 0, 17) to (start + 0, 18)
-    = ((c1 + c2) - c3)
-- MCDCBranch { true: Counter(4), false: Counter(5), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18)
+- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13)
+    true  = c3
+    false = ((c1 + c2) - c3)
+- Code(Counter(3)) at (prev + 0, 17) to (start + 0, 18)
+- MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18)
     true  = c4
-    false = c5
+    false = (c3 - c4)
 - Code(Counter(4)) at (prev + 0, 19) to (start + 2, 10)
-- Code(Expression(8, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c3 + c5)
+- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10)
+    = ((c1 + c2) - c4)
 - Code(Expression(9, Sub)) at (prev + 1, 12) to (start + 2, 6)
     = (c0 - (c1 + c2))
-- Code(Expression(11, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((((c0 + c3) + c4) + c5) - (c1 + c2))
-Highest counter ID seen: c5
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
+Highest counter ID seen: c4
 
diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map
index 92ec60dc23cb..6a112b66e88b 100644
--- a/tests/coverage/mcdc/inlined_expressions.cov-map
+++ b/tests/coverage/mcdc/inlined_expressions.cov-map
@@ -1,12 +1,10 @@
 Function name: inlined_expressions::inlined_instance
-Raw bytes (54): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 06, 01, 01, 00, 02]
+Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 8, 1) to (start + 1, 6)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11)
@@ -14,10 +12,9 @@ Number of file 0 mappings: 6
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 10) to (start + 0, 11)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11)
     true  = c2
-    false = c3
-- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+    false = (c1 - c2)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map
index 72daecabc77a..72c7d68840d3 100644
--- a/tests/coverage/mcdc/nested_if.cov-map
+++ b/tests/coverage/mcdc/nested_if.cov-map
@@ -1,24 +1,22 @@
 Function name: nested_if::doubly_nested_if_in_condition
-Raw bytes (172): 0x[01, 01, 10, 01, 05, 05, 09, 05, 09, 05, 27, 09, 19, 19, 1d, 19, 1d, 23, 27, 05, 1d, 09, 19, 09, 0d, 33, 05, 01, 15, 3b, 05, 3f, 15, 01, 11, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 15, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 21, 02, 00, 00, 00, 15, 00, 36, 0a, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 0e, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1e, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 2e, 02, 0c, 02, 06, 36, 03, 01, 00, 02]
+Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 09, 05, 09, 05, 13, 09, 19, 19, 1d, 05, 1f, 09, 1d, 09, 0d, 2b, 05, 01, 15, 33, 05, 37, 15, 01, 11, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 15, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 21, 02, 00, 00, 00, 15, 00, 36, 0a, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 0e, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1d, 16, 02, 00, 00, 00, 1d, 00, 1e, 1d, 00, 21, 00, 25, 1a, 00, 2f, 00, 34, 23, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 26, 02, 0c, 02, 06, 2e, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 16
+Number of expressions: 14
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(9, Add)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add)
 - expression 4 operands: lhs = Counter(2), rhs = Counter(6)
 - expression 5 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 6 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Expression(9, Add)
-- expression 8 operands: lhs = Counter(1), rhs = Counter(7)
-- expression 9 operands: lhs = Counter(2), rhs = Counter(6)
-- expression 10 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add)
+- expression 7 operands: lhs = Counter(2), rhs = Counter(7)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(1)
+- expression 10 operands: lhs = Counter(0), rhs = Counter(5)
 - expression 11 operands: lhs = Expression(12, Add), rhs = Counter(1)
-- expression 12 operands: lhs = Counter(0), rhs = Counter(5)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(1)
-- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(5)
-- expression 15 operands: lhs = Counter(0), rhs = Counter(4)
+- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(5)
+- expression 13 operands: lhs = Counter(0), rhs = Counter(4)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78)
@@ -43,20 +41,19 @@ Number of file 0 mappings: 20
     true  = c6
     false = (c1 - (c2 + c6))
 - Code(Counter(6)) at (prev + 0, 29) to (start + 0, 30)
-- MCDCBranch { true: Expression(6, Sub), false: Counter(7), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 29) to (start + 0, 30)
-    true  = (c6 - c7)
-    false = c7
-- Code(Expression(6, Sub)) at (prev + 0, 33) to (start + 0, 37)
-    = (c6 - c7)
-- Code(Expression(7, Sub)) at (prev + 0, 47) to (start + 0, 52)
-    = ((c1 + c7) - (c2 + c6))
-- Code(Expression(10, Add)) at (prev + 0, 57) to (start + 0, 62)
+- MCDCBranch { true: Counter(7), false: Expression(5, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 29) to (start + 0, 30)
+    true  = c7
+    false = (c6 - c7)
+- Code(Counter(7)) at (prev + 0, 33) to (start + 0, 37)
+- Code(Expression(6, Sub)) at (prev + 0, 47) to (start + 0, 52)
+    = (c1 - (c2 + c7))
+- Code(Expression(8, Add)) at (prev + 0, 57) to (start + 0, 62)
     = (c2 + c3)
 - Code(Counter(8)) at (prev + 0, 72) to (start + 0, 76)
 - Code(Counter(4)) at (prev + 0, 79) to (start + 2, 6)
-- Code(Expression(11, Sub)) at (prev + 2, 12) to (start + 2, 6)
+- Code(Expression(9, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = ((c0 + c5) - c1)
-- Code(Expression(13, Sub)) at (prev + 3, 1) to (start + 0, 2)
+- Code(Expression(11, Sub)) at (prev + 3, 1) to (start + 0, 2)
     = (((c0 + c4) + c5) - c1)
 Highest counter ID seen: c8
 
@@ -109,30 +106,28 @@ Number of file 0 mappings: 14
 Highest counter ID seen: c5
 
 Function name: nested_if::nested_in_then_block_in_condition
-Raw bytes (180): 0x[01, 01, 14, 01, 05, 05, 09, 05, 09, 05, 3b, 09, 0d, 09, 0d, 3b, 11, 09, 0d, 11, 15, 11, 15, 2f, 11, 3b, 15, 09, 0d, 05, 3b, 09, 0d, 43, 05, 01, 1d, 4b, 05, 4f, 1d, 01, 19, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 1d, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 0a, 00, 15, 00, 16, 30, 0d, 36, 02, 00, 00, 00, 15, 00, 16, 3b, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1a, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 26, 15, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 36, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3e, 02, 0c, 02, 06, 46, 03, 01, 00, 02]
+Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 09, 05, 09, 05, 33, 09, 0d, 09, 0d, 33, 11, 09, 0d, 11, 15, 33, 15, 09, 0d, 05, 33, 09, 0d, 3b, 05, 01, 1d, 43, 05, 47, 1d, 01, 19, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 1d, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 0a, 00, 15, 00, 16, 30, 0d, 2e, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1a, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 22, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 26, 00, 33, 00, 38, 2e, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 36, 02, 0c, 02, 06, 3e, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 20
+Number of expressions: 18
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(14, Add)
+- expression 3 operands: lhs = Counter(1), rhs = Expression(12, Add)
 - expression 4 operands: lhs = Counter(2), rhs = Counter(3)
 - expression 5 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 6 operands: lhs = Expression(14, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4)
 - expression 7 operands: lhs = Counter(2), rhs = Counter(3)
 - expression 8 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 11 operands: lhs = Expression(14, Add), rhs = Counter(5)
+- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(5)
+- expression 10 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 11 operands: lhs = Counter(1), rhs = Expression(12, Add)
 - expression 12 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 13 operands: lhs = Counter(1), rhs = Expression(14, Add)
-- expression 14 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(1)
+- expression 14 operands: lhs = Counter(0), rhs = Counter(7)
 - expression 15 operands: lhs = Expression(16, Add), rhs = Counter(1)
-- expression 16 operands: lhs = Counter(0), rhs = Counter(7)
-- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(1)
-- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(7)
-- expression 19 operands: lhs = Counter(0), rhs = Counter(6)
+- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(7)
+- expression 17 operands: lhs = Counter(0), rhs = Counter(6)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 1) to (start + 1, 9)
 - MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75)
@@ -149,29 +144,28 @@ Number of file 0 mappings: 20
     false = (c1 - c2)
 - Code(Expression(2, Sub)) at (prev + 0, 21) to (start + 0, 22)
     = (c1 - c2)
-- MCDCBranch { true: Counter(3), false: Expression(13, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22)
+- MCDCBranch { true: Counter(3), false: Expression(11, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22)
     true  = c3
     false = (c1 - (c2 + c3))
-- Code(Expression(14, Add)) at (prev + 0, 28) to (start + 0, 29)
+- Code(Expression(12, Add)) at (prev + 0, 28) to (start + 0, 29)
     = (c2 + c3)
 - MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34)
 - MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29)
     true  = c4
     false = ((c2 + c3) - c4)
 - Code(Counter(4)) at (prev + 0, 33) to (start + 0, 34)
-- MCDCBranch { true: Expression(9, Sub), false: Counter(5), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
-    true  = (c4 - c5)
-    false = c5
-- Code(Expression(9, Sub)) at (prev + 0, 37) to (start + 0, 41)
-    = (c4 - c5)
-- Code(Expression(10, Sub)) at (prev + 0, 51) to (start + 0, 56)
-    = (((c2 + c3) + c5) - c4)
-- Code(Expression(13, Sub)) at (prev + 0, 68) to (start + 0, 73)
+- MCDCBranch { true: Counter(5), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34)
+    true  = c5
+    false = (c4 - c5)
+- Code(Counter(5)) at (prev + 0, 37) to (start + 0, 41)
+- Code(Expression(9, Sub)) at (prev + 0, 51) to (start + 0, 56)
+    = ((c2 + c3) - c5)
+- Code(Expression(11, Sub)) at (prev + 0, 68) to (start + 0, 73)
     = (c1 - (c2 + c3))
 - Code(Counter(6)) at (prev + 0, 76) to (start + 2, 6)
-- Code(Expression(15, Sub)) at (prev + 2, 12) to (start + 2, 6)
+- Code(Expression(13, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = ((c0 + c7) - c1)
-- Code(Expression(17, Sub)) at (prev + 3, 1) to (start + 0, 2)
+- Code(Expression(15, Sub)) at (prev + 3, 1) to (start + 0, 2)
     = (((c0 + c6) + c7) - c1)
 Highest counter ID seen: c7
 
diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map
index 0edeff9a5867..c282d53c5ac2 100644
--- a/tests/coverage/mcdc/non_control_flow.cov-map
+++ b/tests/coverage/mcdc/non_control_flow.cov-map
@@ -1,124 +1,107 @@
 Function name: non_control_flow::assign_3
-Raw bytes (89): 0x[01, 01, 09, 07, 11, 0b, 0d, 05, 09, 01, 05, 01, 05, 01, 23, 05, 11, 01, 23, 05, 11, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 12, 01, 00, 02, 00, 0d, 00, 0e, 12, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
+Raw bytes (79): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0a, 01, 16, 01, 00, 28, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 9
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
+Number of expressions: 4
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
 - expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 5 operands: lhs = Counter(0), rhs = Expression(8, Add)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(4)
-- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add)
-- expression 8 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 22, 1) to (start + 0, 40)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = (((c1 + c2) + c3) + c4)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
 - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
-- MCDCBranch { true: Counter(1), false: Expression(4, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
-- Code(Expression(4, Sub)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
     = (c0 - c1)
-- MCDCBranch { true: Expression(7, Sub), false: Counter(4), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
-    true  = (c0 - (c1 + c4))
-    false = c4
-- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = (c0 - (c1 + c4))
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
-    false = c3
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (((c1 + c2) + c3) + c4)
-Highest counter ID seen: c4
+    false = (c0 - (c1 + c2))
+- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 24)
+- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
+    true  = c3
+    false = (c2 - c3)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c3
 
 Function name: non_control_flow::assign_3_bis
-Raw bytes (81): 0x[01, 01, 05, 07, 11, 09, 0d, 01, 05, 05, 09, 01, 09, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 0a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0e, 03, 00, 02, 00, 12, 00, 13, 12, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02]
+Raw bytes (81): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0a, 01, 1b, 01, 00, 2c, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 5
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4)
-- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add)
+- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 27, 1) to (start + 0, 44)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = ((c2 + c3) + c4)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
 - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24)
-- MCDCBranch { true: Counter(1), false: Expression(2, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
-- MCDCBranch { true: Counter(2), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 0, 24)
+- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24)
     = (c0 - c2)
-- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
+- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24)
     true  = c3
-    false = c4
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = ((c2 + c3) + c4)
-Highest counter ID seen: c4
+    false = (c0 - (c2 + c3))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c3
 
 Function name: non_control_flow::assign_and
-Raw bytes (64): 0x[01, 01, 04, 07, 05, 0b, 0d, 01, 09, 01, 05, 08, 01, 0c, 01, 00, 21, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 02, 01, 05, 01, 02]
+Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 0c, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 2
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33)
-- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10)
-    = (((c0 + c2) + c3) - c1)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
-- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
-    false = c3
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+    false = (c1 - c2)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c2
 
 Function name: non_control_flow::assign_or
-Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (62): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 08, 01, 11, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 3
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 8
 - Code(Counter(0)) at (prev + 17, 1) to (start + 0, 32)
-- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10)
-    = ((c1 + c2) + c3)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19)
-- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
-- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
     = (c0 - c1)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19)
     true  = c2
-    false = c3
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = ((c1 + c2) + c3)
-Highest counter ID seen: c3
+    false = (c0 - (c1 + c2))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c2
 
 Function name: non_control_flow::foo
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02]
@@ -130,14 +113,12 @@ Number of file 0 mappings: 1
 Highest counter ID seen: c0
 
 Function name: non_control_flow::func_call
-Raw bytes (54): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 06, 01, 01, 00, 02]
+Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10)
 - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15)
@@ -145,66 +126,46 @@ Number of file 0 mappings: 6
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15)
-- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15)
     true  = c2
-    false = c3
-- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2)
-    = (((c0 + c2) + c3) - c1)
-Highest counter ID seen: c3
+    false = (c1 - c2)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c2
 
 Function name: non_control_flow::right_comb_tree
-Raw bytes (139): 0x[01, 01, 13, 07, 05, 0b, 19, 0f, 15, 13, 11, 17, 0d, 01, 09, 01, 05, 05, 09, 05, 09, 05, 4b, 09, 0d, 05, 4b, 09, 0d, 05, 47, 4b, 11, 09, 0d, 05, 47, 4b, 11, 09, 0d, 0e, 01, 20, 01, 00, 41, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 22, 09, 02, 03, 00, 00, 13, 00, 14, 22, 00, 19, 00, 1a, 30, 2e, 0d, 03, 04, 00, 00, 19, 00, 1a, 2e, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 15, 19, 05, 00, 00, 00, 24, 00, 27, 02, 01, 05, 01, 02]
+Raw bytes (111): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 0e, 01, 20, 01, 00, 41, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 19
-- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(6)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 7 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 9 operands: lhs = Counter(1), rhs = Expression(18, Add)
-- expression 10 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 11 operands: lhs = Counter(1), rhs = Expression(18, Add)
-- expression 12 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 13 operands: lhs = Counter(1), rhs = Expression(17, Add)
-- expression 14 operands: lhs = Expression(18, Add), rhs = Counter(4)
-- expression 15 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(1), rhs = Expression(17, Add)
-- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(4)
-- expression 18 operands: lhs = Counter(2), rhs = Counter(3)
+Number of expressions: 5
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
 Number of file 0 mappings: 14
 - Code(Counter(0)) at (prev + 32, 1) to (start + 0, 65)
-- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10)
-    = ((((((c0 + c2) + c3) + c4) + c5) + c6) - c1)
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14)
 - MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42)
-- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
+- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14)
     true  = c1
     false = (c0 - c1)
 - Code(Counter(1)) at (prev + 0, 19) to (start + 0, 20)
-- MCDCBranch { true: Expression(8, Sub), false: Counter(2), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
-    true  = (c1 - c2)
-    false = c2
-- Code(Expression(8, Sub)) at (prev + 0, 25) to (start + 0, 26)
-    = (c1 - c2)
-- MCDCBranch { true: Expression(11, Sub), false: Counter(3), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26)
-    true  = (c1 - (c2 + c3))
-    false = c3
-- Code(Expression(11, Sub)) at (prev + 0, 31) to (start + 0, 32)
-    = (c1 - (c2 + c3))
-- MCDCBranch { true: Expression(16, Sub), false: Counter(4), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32)
-    true  = (c1 - ((c2 + c3) + c4))
-    false = c4
-- Code(Expression(16, Sub)) at (prev + 0, 36) to (start + 0, 39)
-    = (c1 - ((c2 + c3) + c4))
-- MCDCBranch { true: Counter(5), false: Counter(6), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39)
+- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20)
+    true  = c2
+    false = (c1 - c2)
+- Code(Counter(2)) at (prev + 0, 25) to (start + 0, 26)
+- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26)
+    true  = c3
+    false = (c2 - c3)
+- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 32)
+- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32)
+    true  = c4
+    false = (c3 - c4)
+- Code(Counter(4)) at (prev + 0, 36) to (start + 0, 39)
+- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39)
     true  = c5
-    false = c6
-- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2)
-    = ((((((c0 + c2) + c3) + c4) + c5) + c6) - c1)
-Highest counter ID seen: c6
+    false = (c4 - c5)
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
+Highest counter ID seen: c5
 
diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map
index 7fbd2cc642e6..f90b73592bdf 100644
--- a/tests/coverage/try_error_result.cov-map
+++ b/tests/coverage/try_error_result.cov-map
@@ -55,18 +55,15 @@ Number of file 0 mappings: 4
 Highest counter ID seen: c1
 
 Function name: try_error_result::test1
-Raw bytes (75): 0x[01, 01, 08, 07, 09, 01, 00, 03, 0d, 03, 13, 0d, 11, 1b, 00, 1f, 00, 0d, 15, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 0a, 02, 09, 04, 1a, 11, 06, 0d, 00, 29, 15, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 17, 01, 01, 00, 02]
+Raw bytes (69): 0x[01, 01, 05, 07, 09, 01, 00, 03, 0d, 03, 13, 0d, 11, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 0a, 02, 09, 04, 1a, 11, 06, 0d, 00, 29, 15, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 8
+Number of expressions: 5
 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(2)
 - expression 1 operands: lhs = Counter(0), rhs = Zero
 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
 - expression 3 operands: lhs = Expression(0, Add), rhs = Expression(4, Add)
 - expression 4 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Zero
-- expression 6 operands: lhs = Expression(7, Add), rhs = Zero
-- expression 7 operands: lhs = Counter(3), rhs = Counter(5)
 Number of file 0 mappings: 11
 - Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23)
 - Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14)
@@ -81,8 +78,7 @@ Number of file 0 mappings: 11
     = (((c0 + Zero) + c2) - (c3 + c4))
 - Code(Zero) at (prev + 0, 42) to (start + 0, 43)
 - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11)
-- Code(Expression(5, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (((c3 + c5) + Zero) + Zero)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 Highest counter ID seen: c5
 
 Function name: try_error_result::test2
diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map
index 630ab4ce47e1..0a4e367bb9e3 100644
--- a/tests/coverage/unicode.cov-map
+++ b/tests/coverage/unicode.cov-map
@@ -1,14 +1,10 @@
 Function name: unicode::main
-Raw bytes (61): 0x[01, 01, 06, 01, 05, 0b, 09, 01, 11, 13, 09, 17, 11, 01, 0d, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 0e, 02, 05, 01, 02]
+Raw bytes (53): 0x[01, 01, 02, 01, 05, 01, 0d, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 6
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(4)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4)
-- expression 5 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(3)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12)
@@ -19,9 +15,8 @@ Number of file 0 mappings: 9
 - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70)
 - Code(Counter(3)) at (prev + 0, 71) to (start + 2, 6)
 - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6)
-    = ((c0 + c4) - c2)
-- Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 1, 2)
-    = (((c0 + c3) + c4) - c2)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2)
 Highest counter ID seen: c3
 
 Function name: unicode::ä»– (unused)
diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map
index ade770597e2f..554056fa8010 100644
--- a/tests/coverage/while_early_ret.cov-map
+++ b/tests/coverage/while_early_ret.cov-map
@@ -1,12 +1,12 @@
 Function name: while_early_ret::main
-Raw bytes (59): 0x[01, 01, 05, 01, 05, 03, 09, 01, 09, 13, 11, 09, 0d, 09, 01, 05, 01, 01, 1b, 03, 03, 09, 02, 0a, 06, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 0f, 01, 01, 00, 02]
+Raw bytes (59): 0x[01, 01, 05, 01, 05, 03, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 05, 01, 01, 1b, 03, 03, 09, 02, 0a, 06, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0e, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 5
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 - expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
 - expression 2 operands: lhs = Counter(0), rhs = Counter(2)
-- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add)
 - expression 4 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 5, 1) to (start + 1, 27)
@@ -17,10 +17,10 @@ Number of file 0 mappings: 9
 - Code(Expression(2, Sub)) at (prev + 6, 21) to (start + 2, 22)
     = (c0 - c2)
 - Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27)
-- Code(Counter(4)) at (prev + 4, 21) to (start + 0, 27)
+- Code(Expression(3, Sub)) at (prev + 4, 21) to (start + 0, 27)
+    = (c0 - (c2 + c3))
 - Code(Counter(1)) at (prev + 3, 10) to (start + 3, 10)
 - Code(Counter(2)) at (prev + 6, 5) to (start + 0, 11)
-- Code(Expression(3, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = ((c2 + c3) + c4)
-Highest counter ID seen: c4
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
+Highest counter ID seen: c3
 
diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map
index e01ec8f9edbe..868fec4b1079 100644
--- a/tests/coverage/yield.cov-map
+++ b/tests/coverage/yield.cov-map
@@ -1,19 +1,13 @@
 Function name: yield::main
-Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 0d, 23, 11, 15, 11, 15, 0d, 23, 11, 15, 0d, 23, 11, 15, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 06, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 23, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02]
+Raw bytes (94): 0x[01, 01, 05, 05, 00, 0d, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 06, 01, 22, 00, 27, 11, 00, 2c, 00, 2e, 0a, 01, 0e, 00, 34, 11, 03, 09, 00, 16, 11, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 0f, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 13, 01, 0e, 00, 34, 2d, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 11
+Number of expressions: 5
 - expression 0 operands: lhs = Counter(1), rhs = Zero
-- expression 1 operands: lhs = Counter(3), rhs = Counter(4)
-- expression 2 operands: lhs = Counter(3), rhs = Expression(8, Add)
-- expression 3 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 4 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 5 operands: lhs = Counter(3), rhs = Expression(8, Add)
-- expression 6 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 7 operands: lhs = Counter(3), rhs = Expression(8, Add)
-- expression 8 operands: lhs = Counter(4), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 10 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 1 operands: lhs = Counter(3), rhs = Counter(5)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 4 operands: lhs = Counter(9), rhs = Counter(10)
 Number of file 0 mappings: 16
 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22)
 - Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46)
@@ -22,21 +16,18 @@ Number of file 0 mappings: 16
     = (c1 + Zero)
 - Code(Counter(3)) at (prev + 2, 11) to (start + 0, 46)
 - Code(Expression(1, Sub)) at (prev + 1, 34) to (start + 0, 39)
+    = (c3 - c5)
+- Code(Counter(4)) at (prev + 0, 44) to (start + 0, 46)
+- Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 52)
     = (c3 - c4)
-- Code(Expression(7, Sub)) at (prev + 0, 44) to (start + 0, 46)
-    = (c3 - (c4 + c5))
-- Code(Expression(8, Add)) at (prev + 1, 14) to (start + 0, 52)
-    = (c4 + c5)
-- Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22)
-    = (c3 - (c4 + c5))
-- Code(Expression(7, Sub)) at (prev + 8, 11) to (start + 0, 46)
-    = (c3 - (c4 + c5))
+- Code(Counter(4)) at (prev + 3, 9) to (start + 0, 22)
+- Code(Counter(4)) at (prev + 8, 11) to (start + 0, 46)
 - Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41)
-- Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52)
+- Code(Expression(3, Add)) at (prev + 1, 14) to (start + 0, 52)
     = (c6 + c7)
 - Code(Counter(8)) at (prev + 2, 11) to (start + 0, 46)
 - Code(Counter(11)) at (prev + 1, 39) to (start + 0, 41)
-- Code(Expression(10, Add)) at (prev + 1, 14) to (start + 0, 52)
+- Code(Expression(4, Add)) at (prev + 1, 14) to (start + 0, 52)
     = (c9 + c10)
 - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2)
 Highest counter ID seen: c11

From ab2ee7aa2f0eb8906b5d04104c93050e703b3936 Mon Sep 17 00:00:00 2001
From: Xing Xue 
Date: Fri, 6 Dec 2024 15:22:46 -0500
Subject: [PATCH 089/197] Use option "-sf" for the AIX "ln" command.

---
 tests/run-make/libs-through-symlinks/Makefile | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/tests/run-make/libs-through-symlinks/Makefile b/tests/run-make/libs-through-symlinks/Makefile
index 592eae663a49..c6ff566a0e86 100644
--- a/tests/run-make/libs-through-symlinks/Makefile
+++ b/tests/run-make/libs-through-symlinks/Makefile
@@ -3,10 +3,20 @@ include ../tools.mk
 
 # ignore-windows
 
+# The option -n for the AIX ln command has a different purpose than it does
+# on Linux. On Linux, the -n option is used to treat the destination path as
+# normal file if it is a symbolic link to a directory, which is the default
+# behavior of the AIX ln command.
+ifeq ($(UNAME),AIX)
+LN_FLAGS := -sf
+else
+LN_FLAGS := -nsf
+endif
+
 NAME := $(shell $(RUSTC) --print file-names foo.rs)
 
 all:
 	mkdir -p $(TMPDIR)/outdir
 	$(RUSTC) foo.rs -o $(TMPDIR)/outdir/$(NAME)
-	ln -nsf outdir/$(NAME) $(TMPDIR)
+	ln $(LN_FLAGS) outdir/$(NAME) $(TMPDIR)
 	RUSTC_LOG=rustc_metadata::loader $(RUSTC) bar.rs

From f884f18151d63ac9ce7e573cadb165ecbe8d7f9b Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Sat, 7 Dec 2024 12:35:19 +1100
Subject: [PATCH 090/197] Move tests for `-l` and `#[link(..)]` into
 `tests/ui/link-native-libs`

---
 .../empty-kind-1.rs                                               | 0
 .../empty-kind-1.stderr                                           | 0
 .../empty-kind-2.rs                                               | 0
 .../empty-kind-2.stderr                                           | 0
 .../link-arg-error.rs                                             | 0
 .../link-arg-error.stderr                                         | 0
 .../link-arg-from-rs.rs                                           | 0
 .../link-arg-from-rs.stderr                                       | 0
 tests/ui/{manual => link-native-libs}/manual-link-bad-form.rs     | 0
 tests/ui/{manual => link-native-libs}/manual-link-bad-form.stderr | 0
 tests/ui/{manual => link-native-libs}/manual-link-bad-kind.rs     | 0
 tests/ui/{manual => link-native-libs}/manual-link-bad-kind.stderr | 0
 .../{manual => link-native-libs}/manual-link-bad-search-path.rs   | 0
 .../manual-link-bad-search-path.stderr                            | 0
 tests/ui/{manual => link-native-libs}/manual-link-framework.rs    | 0
 .../ui/{manual => link-native-libs}/manual-link-framework.stderr  | 0
 .../{manual => link-native-libs}/manual-link-unsupported-kind.rs  | 0
 .../manual-link-unsupported-kind.stderr                           | 0
 .../modifiers-bad.blank.stderr                                    | 0
 .../modifiers-bad.no-prefix.stderr                                | 0
 .../modifiers-bad.prefix-only.stderr                              | 0
 .../modifiers-bad.rs                                              | 0
 .../modifiers-bad.unknown.stderr                                  | 0
 .../modifiers-override-2.rs                                       | 0
 .../modifiers-override-2.stderr                                   | 0
 .../modifiers-override-3.rs                                       | 0
 .../modifiers-override-3.stderr                                   | 0
 .../modifiers-override.rs                                         | 0
 .../modifiers-override.stderr                                     | 0
 .../msvc-non-utf8-output.rs                                       | 0
 .../msvc-non-utf8-output.stderr                                   | 0
 .../suggest-libname-only-1.rs                                     | 0
 .../suggest-libname-only-1.stderr                                 | 0
 .../suggest-libname-only-2.rs                                     | 0
 .../suggest-libname-only-2.stderr                                 | 0
 35 files changed, 0 insertions(+), 0 deletions(-)
 rename tests/ui/{native-library-link-flags => link-native-libs}/empty-kind-1.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/empty-kind-1.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/empty-kind-2.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/empty-kind-2.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/link-arg-error.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/link-arg-error.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/link-arg-from-rs.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/link-arg-from-rs.stderr (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-form.rs (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-form.stderr (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-kind.rs (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-kind.stderr (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-search-path.rs (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-bad-search-path.stderr (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-framework.rs (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-framework.stderr (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-unsupported-kind.rs (100%)
 rename tests/ui/{manual => link-native-libs}/manual-link-unsupported-kind.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-bad.blank.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-bad.no-prefix.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-bad.prefix-only.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-bad.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-bad.unknown.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override-2.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override-2.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override-3.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override-3.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/modifiers-override.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/msvc-non-utf8-output.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/msvc-non-utf8-output.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/suggest-libname-only-1.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/suggest-libname-only-1.stderr (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/suggest-libname-only-2.rs (100%)
 rename tests/ui/{native-library-link-flags => link-native-libs}/suggest-libname-only-2.stderr (100%)

diff --git a/tests/ui/native-library-link-flags/empty-kind-1.rs b/tests/ui/link-native-libs/empty-kind-1.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/empty-kind-1.rs
rename to tests/ui/link-native-libs/empty-kind-1.rs
diff --git a/tests/ui/native-library-link-flags/empty-kind-1.stderr b/tests/ui/link-native-libs/empty-kind-1.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/empty-kind-1.stderr
rename to tests/ui/link-native-libs/empty-kind-1.stderr
diff --git a/tests/ui/native-library-link-flags/empty-kind-2.rs b/tests/ui/link-native-libs/empty-kind-2.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/empty-kind-2.rs
rename to tests/ui/link-native-libs/empty-kind-2.rs
diff --git a/tests/ui/native-library-link-flags/empty-kind-2.stderr b/tests/ui/link-native-libs/empty-kind-2.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/empty-kind-2.stderr
rename to tests/ui/link-native-libs/empty-kind-2.stderr
diff --git a/tests/ui/native-library-link-flags/link-arg-error.rs b/tests/ui/link-native-libs/link-arg-error.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/link-arg-error.rs
rename to tests/ui/link-native-libs/link-arg-error.rs
diff --git a/tests/ui/native-library-link-flags/link-arg-error.stderr b/tests/ui/link-native-libs/link-arg-error.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/link-arg-error.stderr
rename to tests/ui/link-native-libs/link-arg-error.stderr
diff --git a/tests/ui/native-library-link-flags/link-arg-from-rs.rs b/tests/ui/link-native-libs/link-arg-from-rs.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/link-arg-from-rs.rs
rename to tests/ui/link-native-libs/link-arg-from-rs.rs
diff --git a/tests/ui/native-library-link-flags/link-arg-from-rs.stderr b/tests/ui/link-native-libs/link-arg-from-rs.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/link-arg-from-rs.stderr
rename to tests/ui/link-native-libs/link-arg-from-rs.stderr
diff --git a/tests/ui/manual/manual-link-bad-form.rs b/tests/ui/link-native-libs/manual-link-bad-form.rs
similarity index 100%
rename from tests/ui/manual/manual-link-bad-form.rs
rename to tests/ui/link-native-libs/manual-link-bad-form.rs
diff --git a/tests/ui/manual/manual-link-bad-form.stderr b/tests/ui/link-native-libs/manual-link-bad-form.stderr
similarity index 100%
rename from tests/ui/manual/manual-link-bad-form.stderr
rename to tests/ui/link-native-libs/manual-link-bad-form.stderr
diff --git a/tests/ui/manual/manual-link-bad-kind.rs b/tests/ui/link-native-libs/manual-link-bad-kind.rs
similarity index 100%
rename from tests/ui/manual/manual-link-bad-kind.rs
rename to tests/ui/link-native-libs/manual-link-bad-kind.rs
diff --git a/tests/ui/manual/manual-link-bad-kind.stderr b/tests/ui/link-native-libs/manual-link-bad-kind.stderr
similarity index 100%
rename from tests/ui/manual/manual-link-bad-kind.stderr
rename to tests/ui/link-native-libs/manual-link-bad-kind.stderr
diff --git a/tests/ui/manual/manual-link-bad-search-path.rs b/tests/ui/link-native-libs/manual-link-bad-search-path.rs
similarity index 100%
rename from tests/ui/manual/manual-link-bad-search-path.rs
rename to tests/ui/link-native-libs/manual-link-bad-search-path.rs
diff --git a/tests/ui/manual/manual-link-bad-search-path.stderr b/tests/ui/link-native-libs/manual-link-bad-search-path.stderr
similarity index 100%
rename from tests/ui/manual/manual-link-bad-search-path.stderr
rename to tests/ui/link-native-libs/manual-link-bad-search-path.stderr
diff --git a/tests/ui/manual/manual-link-framework.rs b/tests/ui/link-native-libs/manual-link-framework.rs
similarity index 100%
rename from tests/ui/manual/manual-link-framework.rs
rename to tests/ui/link-native-libs/manual-link-framework.rs
diff --git a/tests/ui/manual/manual-link-framework.stderr b/tests/ui/link-native-libs/manual-link-framework.stderr
similarity index 100%
rename from tests/ui/manual/manual-link-framework.stderr
rename to tests/ui/link-native-libs/manual-link-framework.stderr
diff --git a/tests/ui/manual/manual-link-unsupported-kind.rs b/tests/ui/link-native-libs/manual-link-unsupported-kind.rs
similarity index 100%
rename from tests/ui/manual/manual-link-unsupported-kind.rs
rename to tests/ui/link-native-libs/manual-link-unsupported-kind.rs
diff --git a/tests/ui/manual/manual-link-unsupported-kind.stderr b/tests/ui/link-native-libs/manual-link-unsupported-kind.stderr
similarity index 100%
rename from tests/ui/manual/manual-link-unsupported-kind.stderr
rename to tests/ui/link-native-libs/manual-link-unsupported-kind.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr b/tests/ui/link-native-libs/modifiers-bad.blank.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-bad.blank.stderr
rename to tests/ui/link-native-libs/modifiers-bad.blank.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr b/tests/ui/link-native-libs/modifiers-bad.no-prefix.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr
rename to tests/ui/link-native-libs/modifiers-bad.no-prefix.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr b/tests/ui/link-native-libs/modifiers-bad.prefix-only.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr
rename to tests/ui/link-native-libs/modifiers-bad.prefix-only.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.rs b/tests/ui/link-native-libs/modifiers-bad.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-bad.rs
rename to tests/ui/link-native-libs/modifiers-bad.rs
diff --git a/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr b/tests/ui/link-native-libs/modifiers-bad.unknown.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr
rename to tests/ui/link-native-libs/modifiers-bad.unknown.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-override-2.rs b/tests/ui/link-native-libs/modifiers-override-2.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override-2.rs
rename to tests/ui/link-native-libs/modifiers-override-2.rs
diff --git a/tests/ui/native-library-link-flags/modifiers-override-2.stderr b/tests/ui/link-native-libs/modifiers-override-2.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override-2.stderr
rename to tests/ui/link-native-libs/modifiers-override-2.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-override-3.rs b/tests/ui/link-native-libs/modifiers-override-3.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override-3.rs
rename to tests/ui/link-native-libs/modifiers-override-3.rs
diff --git a/tests/ui/native-library-link-flags/modifiers-override-3.stderr b/tests/ui/link-native-libs/modifiers-override-3.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override-3.stderr
rename to tests/ui/link-native-libs/modifiers-override-3.stderr
diff --git a/tests/ui/native-library-link-flags/modifiers-override.rs b/tests/ui/link-native-libs/modifiers-override.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override.rs
rename to tests/ui/link-native-libs/modifiers-override.rs
diff --git a/tests/ui/native-library-link-flags/modifiers-override.stderr b/tests/ui/link-native-libs/modifiers-override.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/modifiers-override.stderr
rename to tests/ui/link-native-libs/modifiers-override.stderr
diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs b/tests/ui/link-native-libs/msvc-non-utf8-output.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/msvc-non-utf8-output.rs
rename to tests/ui/link-native-libs/msvc-non-utf8-output.rs
diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr b/tests/ui/link-native-libs/msvc-non-utf8-output.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr
rename to tests/ui/link-native-libs/msvc-non-utf8-output.stderr
diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/suggest-libname-only-1.rs
rename to tests/ui/link-native-libs/suggest-libname-only-1.rs
diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/suggest-libname-only-1.stderr
rename to tests/ui/link-native-libs/suggest-libname-only-1.stderr
diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs
similarity index 100%
rename from tests/ui/native-library-link-flags/suggest-libname-only-2.rs
rename to tests/ui/link-native-libs/suggest-libname-only-2.rs
diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
similarity index 100%
rename from tests/ui/native-library-link-flags/suggest-libname-only-2.stderr
rename to tests/ui/link-native-libs/suggest-libname-only-2.stderr

From 0a48b96859d3d66138082ffad6a1057b54cd55c7 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Sat, 7 Dec 2024 12:35:30 +1100
Subject: [PATCH 091/197] Move more tests into `tests/ui/link-native-libs`

---
 src/tools/tidy/src/issues.txt                          | 10 +++++-----
 src/tools/tidy/src/ui_tests.rs                         |  2 +-
 .../auxiliary/link-cfg-works-transitive-dylib.rs       |  0
 .../auxiliary/link-cfg-works-transitive-rlib.rs        |  0
 .../{linkage-attr => link-native-libs}/issue-109144.rs |  0
 .../issue-109144.stderr                                |  0
 tests/ui/{issues => link-native-libs}/issue-43925.rs   |  0
 .../ui/{issues => link-native-libs}/issue-43925.stderr |  0
 tests/ui/{issues => link-native-libs}/issue-43926.rs   |  0
 .../ui/{issues => link-native-libs}/issue-43926.stderr |  0
 .../issue-70093/issue-70093-link-directives.rs         |  0
 .../issue-70093/issue-70093.rs                         |  0
 .../kind-framework.rs                                  |  0
 .../kind-framework.stderr                              |  0
 .../link-attr-validation-early.rs                      |  0
 .../link-attr-validation-early.stderr                  |  0
 .../link-attr-validation-late.rs                       |  0
 .../link-attr-validation-late.stderr                   |  0
 .../link-cfg-works.rs                                  |  0
 .../uikit-framework.rs                                 |  0
 20 files changed, 6 insertions(+), 6 deletions(-)
 rename tests/ui/{linkage-attr => link-native-libs}/auxiliary/link-cfg-works-transitive-dylib.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/auxiliary/link-cfg-works-transitive-rlib.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/issue-109144.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/issue-109144.stderr (100%)
 rename tests/ui/{issues => link-native-libs}/issue-43925.rs (100%)
 rename tests/ui/{issues => link-native-libs}/issue-43925.stderr (100%)
 rename tests/ui/{issues => link-native-libs}/issue-43926.rs (100%)
 rename tests/ui/{issues => link-native-libs}/issue-43926.stderr (100%)
 rename tests/ui/{issues => link-native-libs}/issue-70093/issue-70093-link-directives.rs (100%)
 rename tests/ui/{issues => link-native-libs}/issue-70093/issue-70093.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/kind-framework.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/kind-framework.stderr (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/link-attr-validation-early.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/link-attr-validation-early.stderr (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/link-attr-validation-late.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/link-attr-validation-late.stderr (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/link-cfg-works.rs (100%)
 rename tests/ui/{linkage-attr => link-native-libs}/uikit-framework.rs (100%)

diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index ac82a17e1459..4088b2de2cdb 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2297,8 +2297,6 @@ ui/issues/issue-43853.rs
 ui/issues/issue-4387.rs
 ui/issues/issue-43910.rs
 ui/issues/issue-43923.rs
-ui/issues/issue-43925.rs
-ui/issues/issue-43926.rs
 ui/issues/issue-43988.rs
 ui/issues/issue-44023.rs
 ui/issues/issue-44056.rs
@@ -2547,8 +2545,6 @@ ui/issues/issue-6936.rs
 ui/issues/issue-69455.rs
 ui/issues/issue-69602-type-err-during-codegen-ice.rs
 ui/issues/issue-69683.rs
-ui/issues/issue-70093/issue-70093-link-directives.rs
-ui/issues/issue-70093/issue-70093.rs
 ui/issues/issue-7012.rs
 ui/issues/issue-70381.rs
 ui/issues/issue-7044.rs
@@ -2713,11 +2709,15 @@ ui/limits/issue-17913.rs
 ui/limits/issue-55878.rs
 ui/limits/issue-69485-var-size-diffs-too-large.rs
 ui/limits/issue-75158-64.rs
+ui/link-native-libs/issue-109144.rs
+ui/link-native-libs/issue-43925.rs
+ui/link-native-libs/issue-43926.rs
+ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
+ui/link-native-libs/issue-70093/issue-70093.rs
 ui/linkage-attr/auxiliary/issue-12133-dylib.rs
 ui/linkage-attr/auxiliary/issue-12133-dylib2.rs
 ui/linkage-attr/auxiliary/issue-12133-rlib.rs
 ui/linkage-attr/issue-10755.rs
-ui/linkage-attr/issue-109144.rs
 ui/linkage-attr/issue-12133-1.rs
 ui/linkage-attr/issue-12133-2.rs
 ui/linkage-attr/issue-12133-3.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 11f9d5bb03df..401169c838f7 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1672;
+const ISSUES_ENTRY_LIMIT: u32 = 1667;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs
similarity index 100%
rename from tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs
rename to tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs
diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs
similarity index 100%
rename from tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs
rename to tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs
diff --git a/tests/ui/linkage-attr/issue-109144.rs b/tests/ui/link-native-libs/issue-109144.rs
similarity index 100%
rename from tests/ui/linkage-attr/issue-109144.rs
rename to tests/ui/link-native-libs/issue-109144.rs
diff --git a/tests/ui/linkage-attr/issue-109144.stderr b/tests/ui/link-native-libs/issue-109144.stderr
similarity index 100%
rename from tests/ui/linkage-attr/issue-109144.stderr
rename to tests/ui/link-native-libs/issue-109144.stderr
diff --git a/tests/ui/issues/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs
similarity index 100%
rename from tests/ui/issues/issue-43925.rs
rename to tests/ui/link-native-libs/issue-43925.rs
diff --git a/tests/ui/issues/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr
similarity index 100%
rename from tests/ui/issues/issue-43925.stderr
rename to tests/ui/link-native-libs/issue-43925.stderr
diff --git a/tests/ui/issues/issue-43926.rs b/tests/ui/link-native-libs/issue-43926.rs
similarity index 100%
rename from tests/ui/issues/issue-43926.rs
rename to tests/ui/link-native-libs/issue-43926.rs
diff --git a/tests/ui/issues/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr
similarity index 100%
rename from tests/ui/issues/issue-43926.stderr
rename to tests/ui/link-native-libs/issue-43926.stderr
diff --git a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs b/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
similarity index 100%
rename from tests/ui/issues/issue-70093/issue-70093-link-directives.rs
rename to tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs
diff --git a/tests/ui/issues/issue-70093/issue-70093.rs b/tests/ui/link-native-libs/issue-70093/issue-70093.rs
similarity index 100%
rename from tests/ui/issues/issue-70093/issue-70093.rs
rename to tests/ui/link-native-libs/issue-70093/issue-70093.rs
diff --git a/tests/ui/linkage-attr/kind-framework.rs b/tests/ui/link-native-libs/kind-framework.rs
similarity index 100%
rename from tests/ui/linkage-attr/kind-framework.rs
rename to tests/ui/link-native-libs/kind-framework.rs
diff --git a/tests/ui/linkage-attr/kind-framework.stderr b/tests/ui/link-native-libs/kind-framework.stderr
similarity index 100%
rename from tests/ui/linkage-attr/kind-framework.stderr
rename to tests/ui/link-native-libs/kind-framework.stderr
diff --git a/tests/ui/linkage-attr/link-attr-validation-early.rs b/tests/ui/link-native-libs/link-attr-validation-early.rs
similarity index 100%
rename from tests/ui/linkage-attr/link-attr-validation-early.rs
rename to tests/ui/link-native-libs/link-attr-validation-early.rs
diff --git a/tests/ui/linkage-attr/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr
similarity index 100%
rename from tests/ui/linkage-attr/link-attr-validation-early.stderr
rename to tests/ui/link-native-libs/link-attr-validation-early.stderr
diff --git a/tests/ui/linkage-attr/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs
similarity index 100%
rename from tests/ui/linkage-attr/link-attr-validation-late.rs
rename to tests/ui/link-native-libs/link-attr-validation-late.rs
diff --git a/tests/ui/linkage-attr/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr
similarity index 100%
rename from tests/ui/linkage-attr/link-attr-validation-late.stderr
rename to tests/ui/link-native-libs/link-attr-validation-late.stderr
diff --git a/tests/ui/linkage-attr/link-cfg-works.rs b/tests/ui/link-native-libs/link-cfg-works.rs
similarity index 100%
rename from tests/ui/linkage-attr/link-cfg-works.rs
rename to tests/ui/link-native-libs/link-cfg-works.rs
diff --git a/tests/ui/linkage-attr/uikit-framework.rs b/tests/ui/link-native-libs/uikit-framework.rs
similarity index 100%
rename from tests/ui/linkage-attr/uikit-framework.rs
rename to tests/ui/link-native-libs/uikit-framework.rs

From afdf4c8ea966a7b148723e91e42f9c5040520ca3 Mon Sep 17 00:00:00 2001
From: Ali Bektas 
Date: Sun, 25 Aug 2024 13:28:07 +0200
Subject: [PATCH 092/197] Watch for user config ratoml

---
 .../crates/load-cargo/src/lib.rs              | 24 +++++++++-
 .../crates/rust-analyzer/src/config.rs        | 14 ++----
 .../crates/rust-analyzer/src/global_state.rs  | 11 ++++-
 .../crates/rust-analyzer/src/reload.rs        |  8 +++-
 .../rust-analyzer/tests/slow-tests/ratoml.rs  | 44 ++++++++++++-------
 .../rust-analyzer/tests/slow-tests/support.rs | 30 +++++++++++--
 6 files changed, 94 insertions(+), 37 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 0e1606a69911..ab8a780363d9 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -123,7 +123,7 @@ pub fn load_workspace(
             .collect()
     };
 
-    let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]);
+    let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[], None);
     loader.set_config(vfs::loader::Config {
         load: project_folders.load,
         watch: vec![],
@@ -153,7 +153,11 @@ pub struct ProjectFolders {
 }
 
 impl ProjectFolders {
-    pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders {
+    pub fn new(
+        workspaces: &[ProjectWorkspace],
+        global_excludes: &[AbsPathBuf],
+        user_config_dir_path: Option<&'static AbsPath>,
+    ) -> ProjectFolders {
         let mut res = ProjectFolders::default();
         let mut fsc = FileSetConfig::builder();
         let mut local_filesets = vec![];
@@ -291,6 +295,22 @@ impl ProjectFolders {
             }
         }
 
+        if let Some(user_config_path) = user_config_dir_path {
+            let ratoml_path = {
+                let mut p = user_config_path.to_path_buf();
+                p.push("rust-analyzer.toml");
+                p
+            };
+
+            let file_set_roots: Vec = vec![VfsPath::from(ratoml_path.to_owned())];
+            let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
+
+            res.watch.push(res.load.len());
+            res.load.push(entry);
+            local_filesets.push(fsc.len() as u64);
+            fsc.add_file_set(file_set_roots)
+        }
+
         let fsc = fsc.build();
         res.source_root_config = SourceRootConfig { fsc, local_filesets };
 
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 dd7351bcf26c..921c9b991c5a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -804,22 +804,14 @@ impl std::ops::Deref for Config {
 }
 
 impl Config {
-    /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux.
-    /// This path is equal to:
-    ///
-    /// |Platform | Value                                 | Example                                  |
-    /// | ------- | ------------------------------------- | ---------------------------------------- |
-    /// | Linux   | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config                      |
-    /// | macOS   | `$HOME`/Library/Application Support   | /Users/Alice/Library/Application Support |
-    /// | Windows | `{FOLDERID_RoamingAppData}`           | C:\Users\Alice\AppData\Roaming           |
-    pub fn user_config_path() -> Option<&'static AbsPath> {
+    /// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux.
+    pub fn user_config_dir_path() -> Option<&'static AbsPath> {
         static USER_CONFIG_PATH: LazyLock> = LazyLock::new(|| {
             let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
                 std::path::PathBuf::from(path)
             } else {
                 dirs::config_dir()?.join("rust-analyzer")
-            }
-            .join("rust-analyzer.toml");
+            };
             Some(AbsPathBuf::assert_utf8(user_config_path))
         });
         USER_CONFIG_PATH.as_deref()
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 7fbeaa4e3ea9..8d5536e1b094 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
@@ -392,7 +392,14 @@ impl GlobalState {
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
         {
             let config_change = {
-                let user_config_path = Config::user_config_path();
+                let user_config_path = {
+                    let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
+                    p.push("rust-analyzer.toml");
+                    p
+                };
+
+                let user_config_abs_path = Some(user_config_path.as_path());
+
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
 
@@ -411,7 +418,7 @@ impl GlobalState {
                     .collect_vec();
 
                 for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files {
-                    if vfs_path.as_path() == user_config_path {
+                    if vfs_path.as_path() == user_config_abs_path {
                         change.change_user_config(Some(db.file_text(file_id)));
                         continue;
                     }
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 bc85afa0e494..b0b622035282 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -590,7 +590,7 @@ impl GlobalState {
             }
 
             watchers.extend(
-                iter::once(Config::user_config_path())
+                iter::once(Config::user_config_dir_path())
                     .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
                     .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
@@ -613,7 +613,11 @@ impl GlobalState {
         }
 
         let files_config = self.config.files();
-        let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
+        let project_folders = ProjectFolders::new(
+            &self.workspaces,
+            &files_config.exclude,
+            Config::user_config_dir_path().to_owned(),
+        );
 
         if (self.proc_macro_clients.is_empty() || !same_workspaces)
             && self.config.expand_proc_macros()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index a857e0c2967c..623a9f76d14e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -30,6 +30,23 @@ impl RatomlTest {
         fixtures: Vec<&str>,
         roots: Vec<&str>,
         client_config: Option,
+    ) -> Self {
+        RatomlTest::new_with_lock(fixtures, roots, client_config, false)
+    }
+
+    fn new_locked(
+        fixtures: Vec<&str>,
+        roots: Vec<&str>,
+        client_config: Option,
+    ) -> Self {
+        RatomlTest::new_with_lock(fixtures, roots, client_config, true)
+    }
+
+    fn new_with_lock(
+        fixtures: Vec<&str>,
+        roots: Vec<&str>,
+        client_config: Option,
+        prelock: bool,
     ) -> Self {
         let tmp_dir = TestDir::new();
         let tmp_path = tmp_dir.path().to_owned();
@@ -46,7 +63,7 @@ impl RatomlTest {
             project = project.with_config(client_config);
         }
 
-        let server = project.server().wait_until_workspace_is_loaded();
+        let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
 
         let mut case = Self { urls: vec![], server, tmp_path };
         let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::>();
@@ -72,7 +89,7 @@ impl RatomlTest {
         let mut spl = spl.into_iter();
         if let Some(first) = spl.next() {
             if first == "$$CONFIG_DIR$$" {
-                path = Config::user_config_path().unwrap().to_path_buf().into();
+                path = Config::user_config_dir_path().unwrap().to_path_buf().into();
             } else {
                 path = path.join(first);
             }
@@ -285,16 +302,15 @@ enum Value {
 //     }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_user_config_detected() {
     if skip_slow_tests() {
         return;
     }
 
-    let server = RatomlTest::new(
+    let server = RatomlTest::new_locked(
         vec![
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true
 "#,
             r#"
@@ -322,13 +338,12 @@ enum Value {
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_create_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -353,10 +368,7 @@ enum Value {
         1,
         InternalTestingFetchConfigResponse::AssistEmitMustUse(false),
     );
-    server.create(
-        "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml",
-        RatomlTest::EMIT_MUST_USE.to_owned(),
-    );
+    server.create("//- /$$CONFIG_DIR$$/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned());
     server.query(
         InternalTestingFetchConfigOption::AssistEmitMustUse,
         1,
@@ -365,13 +377,12 @@ enum Value {
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_modify_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -386,7 +397,7 @@ enum Value {
     Text(String),
 }"#,
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true"#,
         ],
         vec!["p1"],
@@ -407,13 +418,12 @@ assist.emitMustUse = true"#,
 }
 
 #[test]
-#[ignore = "the user config is currently not being watched on startup, fix this"]
 fn ratoml_delete_user_config() {
     if skip_slow_tests() {
         return;
     }
 
-    let mut server = RatomlTest::new(
+    let mut server = RatomlTest::new_locked(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -428,7 +438,7 @@ enum Value {
     Text(String),
 }"#,
             r#"
-//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml
+//- /$$CONFIG_DIR$$/rust-analyzer.toml
 assist.emitMustUse = true"#,
         ],
         vec!["p1"],
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 78572e37a9b1..86137e3f2ccb 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
@@ -1,6 +1,6 @@
 use std::{
     cell::{Cell, RefCell},
-    fs,
+    env, fs,
     sync::Once,
     time::Duration,
 };
@@ -127,7 +127,30 @@ impl Project<'_> {
     }
 
     pub(crate) fn server(self) -> Server {
+        Project::server_with_lock(self, false)
+    }
+
+    /// `prelock` : Forcefully acquire a lock that will maintain the path to the config dir throughout the whole test.
+    ///
+    /// When testing we set the user config dir by setting an envvar `__TEST_RA_USER_CONFIG_DIR`.
+    /// This value must be maintained until the end of a test case. When tests run in parallel
+    /// this value may change thus making the tests flaky. As such, we use a `MutexGuard` that locks
+    /// the process until `Server` is dropped. To optimize parallelization we use a lock only when it is
+    /// needed, that is when a test uses config directory to do stuff. Our naive approach is to use a lock
+    /// if there is a path to config dir in the test fixture. However, in certain cases we create a
+    /// file in the config dir after server is run, something where our naive approach comes short.
+    /// Using a `prelock` allows us to force a lock when we know we need it.
+    pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
         static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
+
+        let mut config_dir_guard = if prelock {
+            let v = Some(CONFIG_DIR_LOCK.lock());
+            env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
+            v
+        } else {
+            None
+        };
+
         let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
             if self.root_dir_contains_symlink {
                 TestDir::new_symlink()
@@ -160,13 +183,14 @@ impl Project<'_> {
         assert!(mini_core.is_none());
         assert!(toolchain.is_none());
 
-        let mut config_dir_guard = None;
         for entry in fixture {
             if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
                 if config_dir_guard.is_none() {
                     config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
+                    env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
                 }
-                let path = Config::user_config_path().unwrap().join(&pth['/'.len_utf8()..]);
+
+                let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
                 fs::create_dir_all(path.parent().unwrap()).unwrap();
                 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
             } else {

From 19077860388fa32f3747632ad87b51d79a9ef9dc Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Sat, 7 Dec 2024 19:16:00 +0200
Subject: [PATCH 093/197] Coerce two `FnDef`s to fn pointers even if they are
 the same, if they are subtypes

That's because they can be the same function but still different substs, which mandates them to coerce to fn pointers in order to unify.
---
 .../crates/hir-ty/src/infer/coerce.rs            |  6 +++++-
 .../crates/hir-ty/src/tests/coercion.rs          | 16 ++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 366c3cb0f177..2fe90a8a9243 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -125,7 +125,11 @@ impl CoerceMany {
         // pointers to have a chance at getting a match. See
         // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
         let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) {
-            (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) if x == y => None,
+            (TyKind::FnDef(x, _), TyKind::FnDef(y, _))
+                if x == y && ctx.table.unify(&self.merged_ty(), &expr_ty) =>
+            {
+                None
+            }
             (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None,
             (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => {
                 // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index 273571901ad5..7992f1feeeb1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -942,3 +942,19 @@ fn main() {
 "#,
     )
 }
+
+#[test]
+fn regression_18626() {
+    check_no_mismatches(
+        r#"
+fn f() {
+    trait T {
+        fn f() {}
+    }
+    impl T for i32 {}
+    impl T for u32 {}
+    &[i32::f, u32::f] as &[fn()];
+}
+    "#,
+    );
+}

From 3ce35a4ec5f06828f908a018da083af5eb54301a Mon Sep 17 00:00:00 2001
From: Jack Wrenn 
Date: Fri, 6 Dec 2024 17:11:36 +0000
Subject: [PATCH 094/197] Make `Copy` unsafe to implement for ADTs with
 `unsafe` fields

As a rule, the application of `unsafe` to a declaration requires that use-sites
of that declaration also require `unsafe`. For example, a field declared
`unsafe` may only be read in the lexical context of an `unsafe` block.

For nearly all safe traits, the safety obligations of fields are explicitly
discharged when they are mentioned in method definitions. For example,
idiomatically implementing `Clone` (a safe trait) for a type with unsafe fields
will require `unsafe` to clone those fields.

Prior to this commit, `Copy` violated this rule. The trait is marked safe, and
although it has no explicit methods, its implementation permits reads of `Self`.

This commit resolves this by making `Copy` conditionally safe to implement. It
remains safe to implement for ADTs without unsafe fields, but unsafe to
implement for ADTs with unsafe fields.

Tracking: #132922
---
 .../example/mini_core.rs                      | 38 ++++++++---------
 .../rustc_codegen_gcc/example/mini_core.rs    | 34 +++++++--------
 .../src/coherence/builtin.rs                  |  8 +++-
 .../src/coherence/unsafety.rs                 | 38 +++++++++++++----
 compiler/rustc_lint/src/builtin.rs            |  1 +
 compiler/rustc_middle/src/ty/sty.rs           |  6 +--
 compiler/rustc_middle/src/ty/util.rs          |  9 ++++
 .../rustc_trait_selection/src/traits/misc.rs  | 10 +++++
 .../src/traits/select/candidate_assembly.rs   |  2 -
 .../src/needless_pass_by_value.rs             |  1 +
 tests/ui/unsafe-fields/copy-trait.rs          | 41 +++++++++++++++++++
 tests/ui/unsafe-fields/copy-trait.stderr      | 28 +++++++++++++
 12 files changed, 164 insertions(+), 52 deletions(-)
 create mode 100644 tests/ui/unsafe-fields/copy-trait.rs
 create mode 100644 tests/ui/unsafe-fields/copy-trait.stderr

diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 3da215fe6c01..a0a381638c06 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -55,26 +55,26 @@ impl LegacyReceiver for &mut T {}
 impl LegacyReceiver for Box {}
 
 #[lang = "copy"]
-pub unsafe trait Copy {}
+pub trait Copy {}
 
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for u128 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for f64 {}
-unsafe impl Copy for char {}
-unsafe impl<'a, T: ?Sized> Copy for &'a T {}
-unsafe impl Copy for *const T {}
-unsafe impl Copy for *mut T {}
-unsafe impl Copy for Option {}
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for u128 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for char {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+impl Copy for *const T {}
+impl Copy for *mut T {}
+impl Copy for Option {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index c887598f6e90..cdd151613df8 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -52,24 +52,24 @@ impl LegacyReceiver for &mut T {}
 impl LegacyReceiver for Box {}
 
 #[lang = "copy"]
-pub unsafe trait Copy {}
+pub trait Copy {}
 
-unsafe impl Copy for bool {}
-unsafe impl Copy for u8 {}
-unsafe impl Copy for u16 {}
-unsafe impl Copy for u32 {}
-unsafe impl Copy for u64 {}
-unsafe impl Copy for usize {}
-unsafe impl Copy for i8 {}
-unsafe impl Copy for i16 {}
-unsafe impl Copy for i32 {}
-unsafe impl Copy for isize {}
-unsafe impl Copy for f32 {}
-unsafe impl Copy for f64 {}
-unsafe impl Copy for char {}
-unsafe impl<'a, T: ?Sized> Copy for &'a T {}
-unsafe impl Copy for *const T {}
-unsafe impl Copy for *mut T {}
+impl Copy for bool {}
+impl Copy for u8 {}
+impl Copy for u16 {}
+impl Copy for u32 {}
+impl Copy for u64 {}
+impl Copy for usize {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for isize {}
+impl Copy for f32 {}
+impl Copy for f64 {}
+impl Copy for char {}
+impl<'a, T: ?Sized> Copy for &'a T {}
+impl Copy for *const T {}
+impl Copy for *mut T {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 3b49bc41ffe4..2eea65125b03 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -103,7 +103,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
     }
 
     let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
-    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
+    match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) {
         Ok(()) => Ok(()),
         Err(CopyImplementationError::InfringingFields(fields)) => {
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
@@ -123,6 +123,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran
             let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
             Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
         }
+        Err(CopyImplementationError::HasUnsafeFields) => {
+            let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
+            Err(tcx
+                .dcx()
+                .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type)))
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index d66114a50d78..86839e403303 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -3,7 +3,7 @@
 
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
-use rustc_hir::Safety;
+use rustc_hir::{LangItem, Safety};
 use rustc_middle::ty::ImplPolarity::*;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt};
@@ -20,7 +20,19 @@ pub(super) fn check_item(
         tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
     let trait_ref = trait_header.trait_ref.instantiate_identity();
 
-    match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
+    let is_copy = tcx.is_lang_item(trait_def.def_id, LangItem::Copy);
+    let trait_def_safety = if is_copy {
+        // If `Self` has unsafe fields, `Copy` is unsafe to implement.
+        if trait_header.trait_ref.skip_binder().self_ty().has_unsafe_fields() {
+            rustc_hir::Safety::Unsafe
+        } else {
+            rustc_hir::Safety::Safe
+        }
+    } else {
+        trait_def.safety
+    };
+
+    match (trait_def_safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
         (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
@@ -48,12 +60,22 @@ pub(super) fn check_item(
                 "the trait `{}` requires an `unsafe impl` declaration",
                 trait_ref.print_trait_sugared()
             )
-            .with_note(format!(
-                "the trait `{}` enforces invariants that the compiler can't check. \
-                    Review the trait documentation and make sure this implementation \
-                    upholds those invariants before adding the `unsafe` keyword",
-                trait_ref.print_trait_sugared()
-            ))
+            .with_note(if is_copy {
+                format!(
+                    "the trait `{}` cannot be safely implemented for `{}` \
+                        because it has unsafe fields. Review the invariants \
+                        of those fields before adding an `unsafe impl`",
+                    trait_ref.print_trait_sugared(),
+                    trait_ref.self_ty(),
+                )
+            } else {
+                format!(
+                    "the trait `{}` enforces invariants that the compiler can't check. \
+                        Review the trait documentation and make sure this implementation \
+                        upholds those invariants before adding the `unsafe` keyword",
+                    trait_ref.print_trait_sugared()
+                )
+            })
             .with_span_suggestion_verbose(
                 span.shrink_to_lo(),
                 "add `unsafe` to this trait implementation",
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ec0851989220..093cc16fb4c1 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -625,6 +625,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             cx.param_env,
             ty,
             traits::ObligationCause::misc(item.span, item.owner_id.def_id),
+            hir::Safety::Safe,
         )
         .is_ok()
         {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 474062218c97..3fbc23924f59 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -980,11 +980,7 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> {
     }
 
     fn has_unsafe_fields(self) -> bool {
-        if let ty::Adt(adt_def, ..) = self.kind() {
-            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
-        } else {
-            false
-        }
+        Ty::has_unsafe_fields(self)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 57054bd1a0b2..b9a45ea3c2c5 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1288,6 +1288,15 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    /// Checks whether this type is an ADT that has unsafe fields.
+    pub fn has_unsafe_fields(self) -> bool {
+        if let ty::Adt(adt_def, ..) = self.kind() {
+            adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe)
+        } else {
+            false
+        }
+    }
+
     /// Get morphology of the async drop glue, needed for types which do not
     /// use async drop. To get async drop glue morphology for a definition see
     /// [`TyCtxt::async_drop_glue_morphology`]. Used for `AsyncDestruct::Destructor`
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 3b17fa6b0328..d216ae729133 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -18,6 +18,7 @@ pub enum CopyImplementationError<'tcx> {
     InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
     NotAnAdt,
     HasDestructor,
+    HasUnsafeFields,
 }
 
 pub enum ConstParamTyImplementationError<'tcx> {
@@ -39,11 +40,16 @@ pub enum InfringingFieldsReason<'tcx> {
 ///
 /// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
 /// a reference or an array returns `Err(NotAnAdt)`.
+///
+/// If the impl is `Safe`, `self_type` must not have unsafe fields. When used to
+/// generate suggestions in lints, `Safe` should be supplied so as to not
+/// suggest implementing `Copy` for types with unsafe fields.
 pub fn type_allowed_to_implement_copy<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
     parent_cause: ObligationCause<'tcx>,
+    impl_safety: hir::Safety,
 ) -> Result<(), CopyImplementationError<'tcx>> {
     let (adt, args) = match self_type.kind() {
         // These types used to have a builtin impl.
@@ -78,6 +84,10 @@ pub fn type_allowed_to_implement_copy<'tcx>(
         return Err(CopyImplementationError::HasDestructor);
     }
 
+    if impl_safety == hir::Safety::Safe && self_type.has_unsafe_fields() {
+        return Err(CopyImplementationError::HasUnsafeFields);
+    }
+
     Ok(())
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3e2c8467d322..5e27fd437897 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -795,8 +795,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Never
                 | ty::Tuple(_)
                 | ty::CoroutineWitness(..) => {
-                    use rustc_type_ir::inherent::*;
-
                     // Only consider auto impls of unsafe traits when there are
                     // no unsafe fields.
                     if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index cd90d2f90f77..6f3f371a68d6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -200,6 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                                 cx.param_env,
                                 ty,
                                 traits::ObligationCause::dummy_with_span(span),
+                                rustc_hir::Safety::Safe,
                             )
                             .is_ok()
                             {
diff --git a/tests/ui/unsafe-fields/copy-trait.rs b/tests/ui/unsafe-fields/copy-trait.rs
new file mode 100644
index 000000000000..fb09ed02e3ff
--- /dev/null
+++ b/tests/ui/unsafe-fields/copy-trait.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: --crate-type=lib
+
+#![feature(unsafe_fields)]
+#![allow(incomplete_features)]
+#![deny(missing_copy_implementations)]
+
+mod good_safe_impl {
+    enum SafeEnum {
+        Safe(u8),
+    }
+
+    impl Copy for SafeEnum {}
+}
+
+mod bad_safe_impl {
+    enum UnsafeEnum {
+        Safe(u8),
+        Unsafe { unsafe field: u8 },
+    }
+
+    impl Copy for UnsafeEnum {}
+    //~^ ERROR the trait `Copy` requires an `unsafe impl` declaration
+}
+
+mod good_unsafe_impl {
+    enum UnsafeEnum {
+        Safe(u8),
+        Unsafe { unsafe field: u8 },
+    }
+
+    unsafe impl Copy for UnsafeEnum {}
+}
+
+mod bad_unsafe_impl {
+    enum SafeEnum {
+        Safe(u8),
+    }
+
+    unsafe impl Copy for SafeEnum {}
+    //~^ ERROR implementing the trait `Copy` is not unsafe
+}
diff --git a/tests/ui/unsafe-fields/copy-trait.stderr b/tests/ui/unsafe-fields/copy-trait.stderr
new file mode 100644
index 000000000000..5952f8c89c14
--- /dev/null
+++ b/tests/ui/unsafe-fields/copy-trait.stderr
@@ -0,0 +1,28 @@
+error[E0200]: the trait `Copy` requires an `unsafe impl` declaration
+  --> $DIR/copy-trait.rs:21:5
+   |
+LL |     impl Copy for UnsafeEnum {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the trait `Copy` cannot be safely implemented for `bad_safe_impl::UnsafeEnum` because it has unsafe fields. Review the invariants of those fields before adding an `unsafe impl`
+help: add `unsafe` to this trait implementation
+   |
+LL |     unsafe impl Copy for UnsafeEnum {}
+   |     ++++++
+
+error[E0199]: implementing the trait `Copy` is not unsafe
+  --> $DIR/copy-trait.rs:39:5
+   |
+LL |     unsafe impl Copy for SafeEnum {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove `unsafe` from this trait implementation
+   |
+LL -     unsafe impl Copy for SafeEnum {}
+LL +     impl Copy for SafeEnum {}
+   |
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0199, E0200.
+For more information about an error, try `rustc --explain E0199`.

From 88669aed22aeeef5fb7ecdb7f43ed33e674f8fcb Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Sat, 7 Dec 2024 23:54:10 +0000
Subject: [PATCH 095/197] Don't use AsyncFnOnce::CallOnceFuture bounds for
 signature deduction

---
 compiler/rustc_hir_typeck/src/closure.rs           | 12 ++++--------
 .../async-closures/call-once-deduction.rs          | 14 ++++++++++++++
 2 files changed, 18 insertions(+), 8 deletions(-)
 create mode 100644 tests/ui/async-await/async-closures/call-once-deduction.rs

diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index e715a7f7e158..9037caf0066f 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -454,20 +454,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         closure_kind: hir::ClosureKind,
         projection: ty::PolyProjectionPredicate<'tcx>,
     ) -> Option> {
-        let tcx = self.tcx;
-
-        let trait_def_id = projection.trait_def_id(tcx);
+        let def_id = projection.projection_def_id();
 
         // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
         // for closures and async closures, respectively.
         match closure_kind {
-            hir::ClosureKind::Closure
-                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
-            {
+            hir::ClosureKind::Closure if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) => {
                 self.extract_sig_from_projection(cause_span, projection)
             }
             hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
-                if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+                if self.tcx.is_lang_item(def_id, LangItem::AsyncFnOnceOutput) =>
             {
                 self.extract_sig_from_projection(cause_span, projection)
             }
@@ -475,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // `F: FnOnce() -> Fut, Fut: Future` style bound. Let's still
             // guide inference here, since it's beneficial for the user.
             hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
-                if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() =>
+                if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) =>
             {
                 self.extract_sig_from_projection_and_future_bound(cause_span, projection)
             }
diff --git a/tests/ui/async-await/async-closures/call-once-deduction.rs b/tests/ui/async-await/async-closures/call-once-deduction.rs
new file mode 100644
index 000000000000..41d92bc3d786
--- /dev/null
+++ b/tests/ui/async-await/async-closures/call-once-deduction.rs
@@ -0,0 +1,14 @@
+//@ edition: 2021
+//@ check-pass
+
+#![feature(async_closure, async_fn_traits, unboxed_closures)]
+
+fn bar(_: F)
+where
+    F: AsyncFnOnce<(), CallOnceFuture = O>,
+{
+}
+
+fn main() {
+    bar(async move || {});
+}

From f3f7c20f7b85fa289657b36c30faddff869f8a1f Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Fri, 6 Dec 2024 23:00:22 +1100
Subject: [PATCH 096/197] coverage: Move `CoverageIdsInfo` into `mir::coverage`

---
 .../src/coverageinfo/map_data.rs              |  5 ++--
 compiler/rustc_middle/src/mir/coverage.rs     | 28 +++++++++++++++++
 compiler/rustc_middle/src/mir/query.rs        | 30 +------------------
 compiler/rustc_middle/src/query/mod.rs        |  2 +-
 .../rustc_mir_transform/src/coverage/query.rs |  4 +--
 5 files changed, 34 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 0752c718c706..74e0a647b65f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,10 +1,9 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::CoverageIdsInfo;
 use rustc_middle::mir::coverage::{
-    CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, MappingKind, Op,
-    SourceRegion,
+    CounterId, CovTerm, CoverageIdsInfo, Expression, ExpressionId, FunctionCoverageInfo, Mapping,
+    MappingKind, Op, SourceRegion,
 };
 use rustc_middle::ty::Instance;
 use tracing::debug;
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index b7410ca5f189..ce87255380b6 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -3,6 +3,7 @@
 use std::fmt::{self, Debug, Formatter};
 
 use rustc_index::IndexVec;
+use rustc_index::bit_set::BitSet;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
 
@@ -310,3 +311,30 @@ pub struct MCDCDecisionSpan {
     pub decision_depth: u16,
     pub num_conditions: usize,
 }
+
+/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
+/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
+/// have had a chance to potentially remove some of them.
+///
+/// Used by the `coverage_ids_info` query.
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
+pub struct CoverageIdsInfo {
+    pub counters_seen: BitSet,
+    pub expressions_seen: BitSet,
+}
+
+impl CoverageIdsInfo {
+    /// Coverage codegen needs to know how many coverage counters are ever
+    /// incremented within a function, so that it can set the `num-counters`
+    /// argument of the `llvm.instrprof.increment` intrinsic.
+    ///
+    /// This may be less than the highest counter ID emitted by the
+    /// InstrumentCoverage MIR pass, if the highest-numbered counter increments
+    /// were removed by MIR optimizations.
+    pub fn num_counters_after_mir_opts(&self) -> u32 {
+        // FIXME(Zalathar): Currently this treats an unused counter as "used"
+        // if its ID is less than that of the highest counter that really is
+        // used. Fixing this would require adding a renumbering step somewhere.
+        self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1)
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 80dfcbf2e69f..f690359e0121 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -8,7 +8,7 @@ use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::LocalDefId;
-use rustc_index::bit_set::{BitMatrix, BitSet};
+use rustc_index::bit_set::BitMatrix;
 use rustc_index::{Idx, IndexVec};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
@@ -16,7 +16,6 @@ use rustc_span::symbol::Symbol;
 use smallvec::SmallVec;
 
 use super::{ConstValue, SourceInfo};
-use crate::mir;
 use crate::ty::fold::fold_regions;
 use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt};
 
@@ -351,30 +350,3 @@ pub struct DestructuredConstant<'tcx> {
     pub variant: Option,
     pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
 }
-
-/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
-/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
-/// have had a chance to potentially remove some of them.
-///
-/// Used by the `coverage_ids_info` query.
-#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
-pub struct CoverageIdsInfo {
-    pub counters_seen: BitSet,
-    pub expressions_seen: BitSet,
-}
-
-impl CoverageIdsInfo {
-    /// Coverage codegen needs to know how many coverage counters are ever
-    /// incremented within a function, so that it can set the `num-counters`
-    /// argument of the `llvm.instrprof.increment` intrinsic.
-    ///
-    /// This may be less than the highest counter ID emitted by the
-    /// InstrumentCoverage MIR pass, if the highest-numbered counter increments
-    /// were removed by MIR optimizations.
-    pub fn num_counters_after_mir_opts(&self) -> u32 {
-        // FIXME(Zalathar): Currently this treats an unused counter as "used"
-        // if its ID is less than that of the highest counter that really is
-        // used. Fixing this would require adding a renumbering step somewhere.
-        self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1)
-    }
-}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d04876d0bef0..01cccb7a09d3 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -581,7 +581,7 @@ rustc_queries! {
     /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass
     /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations
     /// have had a chance to potentially remove some of them.
-    query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::CoverageIdsInfo {
+    query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::coverage::CoverageIdsInfo {
         desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
         arena_cache
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 0090f6f30404..bd1632a666c7 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::captures::Captures;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::coverage::{CovTerm, CoverageKind, MappingKind};
-use rustc_middle::mir::{Body, CoverageIdsInfo, Statement, StatementKind};
+use rustc_middle::mir::coverage::{CovTerm, CoverageIdsInfo, CoverageKind, MappingKind};
+use rustc_middle::mir::{Body, Statement, StatementKind};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;

From 2022ef7f12fe6ebc810ee5731557d23ba763cc96 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Fri, 6 Dec 2024 22:33:24 +1100
Subject: [PATCH 097/197] coverage: Use a query to find counters/expressions
 that must be zero

This query (`coverage_ids_info`) already determines which counter/expression
IDs are unused, so it only takes a little extra effort to also determine which
counters/expressions must have a value of zero.
---
 .../src/coverageinfo/map_data.rs              | 116 +-----------------
 compiler/rustc_middle/src/mir/coverage.rs     |  13 +-
 .../rustc_mir_transform/src/coverage/query.rs | 105 +++++++++++++++-
 3 files changed, 117 insertions(+), 117 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 74e0a647b65f..95db80f63eed 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -1,9 +1,7 @@
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::coverage::{
-    CounterId, CovTerm, CoverageIdsInfo, Expression, ExpressionId, FunctionCoverageInfo, Mapping,
-    MappingKind, Op, SourceRegion,
+    CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
+    SourceRegion,
 };
 use rustc_middle::ty::Instance;
 use tracing::debug;
@@ -55,83 +53,10 @@ impl<'tcx> FunctionCoverageCollector<'tcx> {
         Self { function_coverage_info, ids_info, is_used }
     }
 
-    /// Identify expressions that will always have a value of zero, and note
-    /// their IDs in [`ZeroExpressions`]. Mappings that refer to a zero expression
-    /// can instead become mappings to a constant zero value.
-    ///
-    /// This method mainly exists to preserve the simplifications that were
-    /// already being performed by the Rust-side expression renumbering, so that
-    /// the resulting coverage mappings don't get worse.
-    fn identify_zero_expressions(&self) -> ZeroExpressions {
-        // The set of expressions that either were optimized out entirely, or
-        // have zero as both of their operands, and will therefore always have
-        // a value of zero. Other expressions that refer to these as operands
-        // can have those operands replaced with `CovTerm::Zero`.
-        let mut zero_expressions = ZeroExpressions::default();
-
-        // Simplify a copy of each expression based on lower-numbered expressions,
-        // and then update the set of always-zero expressions if necessary.
-        // (By construction, expressions can only refer to other expressions
-        // that have lower IDs, so one pass is sufficient.)
-        for (id, expression) in self.function_coverage_info.expressions.iter_enumerated() {
-            if !self.is_used || !self.ids_info.expressions_seen.contains(id) {
-                // If an expression was not seen, it must have been optimized away,
-                // so any operand that refers to it can be replaced with zero.
-                zero_expressions.insert(id);
-                continue;
-            }
-
-            // We don't need to simplify the actual expression data in the
-            // expressions list; we can just simplify a temporary copy and then
-            // use that to update the set of always-zero expressions.
-            let Expression { mut lhs, op, mut rhs } = *expression;
-
-            // If an expression has an operand that is also an expression, the
-            // operand's ID must be strictly lower. This is what lets us find
-            // all zero expressions in one pass.
-            let assert_operand_expression_is_lower = |operand_id: ExpressionId| {
-                assert!(
-                    operand_id < id,
-                    "Operand {operand_id:?} should be less than {id:?} in {expression:?}",
-                )
-            };
-
-            // If an operand refers to a counter or expression that is always
-            // zero, then that operand can be replaced with `CovTerm::Zero`.
-            let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
-                if let CovTerm::Expression(id) = *operand {
-                    assert_operand_expression_is_lower(id);
-                }
-
-                if is_zero_term(&self.ids_info.counters_seen, &zero_expressions, *operand) {
-                    *operand = CovTerm::Zero;
-                }
-            };
-            maybe_set_operand_to_zero(&mut lhs);
-            maybe_set_operand_to_zero(&mut rhs);
-
-            // Coverage counter values cannot be negative, so if an expression
-            // involves subtraction from zero, assume that its RHS must also be zero.
-            // (Do this after simplifications that could set the LHS to zero.)
-            if lhs == CovTerm::Zero && op == Op::Subtract {
-                rhs = CovTerm::Zero;
-            }
-
-            // After the above simplifications, if both operands are zero, then
-            // we know that this expression is always zero too.
-            if lhs == CovTerm::Zero && rhs == CovTerm::Zero {
-                zero_expressions.insert(id);
-            }
-        }
-
-        zero_expressions
-    }
-
     pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
-        let zero_expressions = self.identify_zero_expressions();
         let FunctionCoverageCollector { function_coverage_info, ids_info, is_used, .. } = self;
 
-        FunctionCoverage { function_coverage_info, ids_info, is_used, zero_expressions }
+        FunctionCoverage { function_coverage_info, ids_info, is_used }
     }
 }
 
@@ -139,8 +64,6 @@ pub(crate) struct FunctionCoverage<'tcx> {
     pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo,
     ids_info: &'tcx CoverageIdsInfo,
     is_used: bool,
-
-    zero_expressions: ZeroExpressions,
 }
 
 impl<'tcx> FunctionCoverage<'tcx> {
@@ -195,37 +118,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
     }
 
     fn is_zero_term(&self, term: CovTerm) -> bool {
-        !self.is_used || is_zero_term(&self.ids_info.counters_seen, &self.zero_expressions, term)
-    }
-}
-
-/// Set of expression IDs that are known to always evaluate to zero.
-/// Any mapping or expression operand that refers to these expressions can have
-/// that reference replaced with a constant zero value.
-#[derive(Default)]
-struct ZeroExpressions(FxIndexSet);
-
-impl ZeroExpressions {
-    fn insert(&mut self, id: ExpressionId) {
-        self.0.insert(id);
-    }
-
-    fn contains(&self, id: ExpressionId) -> bool {
-        self.0.contains(&id)
-    }
-}
-
-/// Returns `true` if the given term is known to have a value of zero, taking
-/// into account knowledge of which counters are unused and which expressions
-/// are always zero.
-fn is_zero_term(
-    counters_seen: &BitSet,
-    zero_expressions: &ZeroExpressions,
-    term: CovTerm,
-) -> bool {
-    match term {
-        CovTerm::Zero => true,
-        CovTerm::Counter(id) => !counters_seen.contains(id),
-        CovTerm::Expression(id) => zero_expressions.contains(id),
+        !self.is_used || self.ids_info.is_zero_term(term)
     }
 }
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index ce87255380b6..962176290df3 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -320,7 +320,7 @@ pub struct MCDCDecisionSpan {
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct CoverageIdsInfo {
     pub counters_seen: BitSet,
-    pub expressions_seen: BitSet,
+    pub zero_expressions: BitSet,
 }
 
 impl CoverageIdsInfo {
@@ -337,4 +337,15 @@ impl CoverageIdsInfo {
         // used. Fixing this would require adding a renumbering step somewhere.
         self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1)
     }
+
+    /// Returns `true` if the given term is known to have a value of zero, taking
+    /// into account knowledge of which counters are unused and which expressions
+    /// are always zero.
+    pub fn is_zero_term(&self, term: CovTerm) -> bool {
+        match term {
+            CovTerm::Zero => true,
+            CovTerm::Counter(id) => !self.counters_seen.contains(id),
+            CovTerm::Expression(id) => self.zero_expressions.contains(id),
+        }
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index bd1632a666c7..edaec3c79651 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -1,7 +1,10 @@
 use rustc_data_structures::captures::Captures;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::coverage::{CovTerm, CoverageIdsInfo, CoverageKind, MappingKind};
+use rustc_middle::mir::coverage::{
+    CounterId, CovTerm, CoverageIdsInfo, CoverageKind, Expression, ExpressionId,
+    FunctionCoverageInfo, MappingKind, Op,
+};
 use rustc_middle::mir::{Body, Statement, StatementKind};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::{self, TyCtxt};
@@ -87,10 +90,10 @@ fn coverage_ids_info<'tcx>(
 ) -> CoverageIdsInfo {
     let mir_body = tcx.instance_mir(instance_def);
 
-    let Some(fn_cov_info) = mir_body.function_coverage_info.as_ref() else {
+    let Some(fn_cov_info) = mir_body.function_coverage_info.as_deref() else {
         return CoverageIdsInfo {
             counters_seen: BitSet::new_empty(0),
-            expressions_seen: BitSet::new_empty(0),
+            zero_expressions: BitSet::new_empty(0),
         };
     };
 
@@ -123,7 +126,10 @@ fn coverage_ids_info<'tcx>(
         }
     }
 
-    CoverageIdsInfo { counters_seen, expressions_seen }
+    let zero_expressions =
+        identify_zero_expressions(fn_cov_info, &counters_seen, &expressions_seen);
+
+    CoverageIdsInfo { counters_seen, zero_expressions }
 }
 
 fn all_coverage_in_mir_body<'a, 'tcx>(
@@ -141,3 +147,94 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
     let scope_data = &body.source_scopes[statement.source_info.scope];
     scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some()
 }
+
+/// Identify expressions that will always have a value of zero, and note
+/// their IDs in a `BitSet`. Mappings that refer to a zero expression
+/// can instead become mappings to a constant zero value.
+///
+/// This function mainly exists to preserve the simplifications that were
+/// already being performed by the Rust-side expression renumbering, so that
+/// the resulting coverage mappings don't get worse.
+fn identify_zero_expressions(
+    fn_cov_info: &FunctionCoverageInfo,
+    counters_seen: &BitSet,
+    expressions_seen: &BitSet,
+) -> BitSet {
+    // The set of expressions that either were optimized out entirely, or
+    // have zero as both of their operands, and will therefore always have
+    // a value of zero. Other expressions that refer to these as operands
+    // can have those operands replaced with `CovTerm::Zero`.
+    let mut zero_expressions = BitSet::new_empty(fn_cov_info.expressions.len());
+
+    // Simplify a copy of each expression based on lower-numbered expressions,
+    // and then update the set of always-zero expressions if necessary.
+    // (By construction, expressions can only refer to other expressions
+    // that have lower IDs, so one pass is sufficient.)
+    for (id, expression) in fn_cov_info.expressions.iter_enumerated() {
+        if !expressions_seen.contains(id) {
+            // If an expression was not seen, it must have been optimized away,
+            // so any operand that refers to it can be replaced with zero.
+            zero_expressions.insert(id);
+            continue;
+        }
+
+        // We don't need to simplify the actual expression data in the
+        // expressions list; we can just simplify a temporary copy and then
+        // use that to update the set of always-zero expressions.
+        let Expression { mut lhs, op, mut rhs } = *expression;
+
+        // If an expression has an operand that is also an expression, the
+        // operand's ID must be strictly lower. This is what lets us find
+        // all zero expressions in one pass.
+        let assert_operand_expression_is_lower = |operand_id: ExpressionId| {
+            assert!(
+                operand_id < id,
+                "Operand {operand_id:?} should be less than {id:?} in {expression:?}",
+            )
+        };
+
+        // If an operand refers to a counter or expression that is always
+        // zero, then that operand can be replaced with `CovTerm::Zero`.
+        let maybe_set_operand_to_zero = |operand: &mut CovTerm| {
+            if let CovTerm::Expression(id) = *operand {
+                assert_operand_expression_is_lower(id);
+            }
+
+            if is_zero_term(&counters_seen, &zero_expressions, *operand) {
+                *operand = CovTerm::Zero;
+            }
+        };
+        maybe_set_operand_to_zero(&mut lhs);
+        maybe_set_operand_to_zero(&mut rhs);
+
+        // Coverage counter values cannot be negative, so if an expression
+        // involves subtraction from zero, assume that its RHS must also be zero.
+        // (Do this after simplifications that could set the LHS to zero.)
+        if lhs == CovTerm::Zero && op == Op::Subtract {
+            rhs = CovTerm::Zero;
+        }
+
+        // After the above simplifications, if both operands are zero, then
+        // we know that this expression is always zero too.
+        if lhs == CovTerm::Zero && rhs == CovTerm::Zero {
+            zero_expressions.insert(id);
+        }
+    }
+
+    zero_expressions
+}
+
+/// Returns `true` if the given term is known to have a value of zero, taking
+/// into account knowledge of which counters are unused and which expressions
+/// are always zero.
+fn is_zero_term(
+    counters_seen: &BitSet,
+    zero_expressions: &BitSet,
+    term: CovTerm,
+) -> bool {
+    match term {
+        CovTerm::Zero => true,
+        CovTerm::Counter(id) => !counters_seen.contains(id),
+        CovTerm::Expression(id) => zero_expressions.contains(id),
+    }
+}

From 4d2bfece41cef781247b5fdcb29407baeb344f71 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Fri, 6 Dec 2024 22:55:09 +1100
Subject: [PATCH 098/197] coverage: Remove FunctionCoverageCollector

The information that was being collected by this builder type is now collected
by the `coverage_ids_info` query instead.
---
 .../src/coverageinfo/map_data.rs              | 68 ++++---------------
 .../src/coverageinfo/mapgen.rs                | 21 ++----
 .../src/coverageinfo/mod.rs                   | 12 ++--
 3 files changed, 24 insertions(+), 77 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index 95db80f63eed..f30a987e4a19 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -3,63 +3,9 @@ use rustc_middle::mir::coverage::{
     CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op,
     SourceRegion,
 };
-use rustc_middle::ty::Instance;
-use tracing::debug;
 
 use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
 
-/// Holds all of the coverage mapping data associated with a function instance,
-/// collected during traversal of `Coverage` statements in the function's MIR.
-#[derive(Debug)]
-pub(crate) struct FunctionCoverageCollector<'tcx> {
-    /// Coverage info that was attached to this function by the instrumentor.
-    function_coverage_info: &'tcx FunctionCoverageInfo,
-    ids_info: &'tcx CoverageIdsInfo,
-    is_used: bool,
-}
-
-impl<'tcx> FunctionCoverageCollector<'tcx> {
-    /// Creates a new set of coverage data for a used (called) function.
-    pub(crate) fn new(
-        instance: Instance<'tcx>,
-        function_coverage_info: &'tcx FunctionCoverageInfo,
-        ids_info: &'tcx CoverageIdsInfo,
-    ) -> Self {
-        Self::create(instance, function_coverage_info, ids_info, true)
-    }
-
-    /// Creates a new set of coverage data for an unused (never called) function.
-    pub(crate) fn unused(
-        instance: Instance<'tcx>,
-        function_coverage_info: &'tcx FunctionCoverageInfo,
-        ids_info: &'tcx CoverageIdsInfo,
-    ) -> Self {
-        Self::create(instance, function_coverage_info, ids_info, false)
-    }
-
-    fn create(
-        instance: Instance<'tcx>,
-        function_coverage_info: &'tcx FunctionCoverageInfo,
-        ids_info: &'tcx CoverageIdsInfo,
-        is_used: bool,
-    ) -> Self {
-        let num_counters = function_coverage_info.num_counters;
-        let num_expressions = function_coverage_info.expressions.len();
-        debug!(
-            "FunctionCoverage::create(instance={instance:?}) has \
-            num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}"
-        );
-
-        Self { function_coverage_info, ids_info, is_used }
-    }
-
-    pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> {
-        let FunctionCoverageCollector { function_coverage_info, ids_info, is_used, .. } = self;
-
-        FunctionCoverage { function_coverage_info, ids_info, is_used }
-    }
-}
-
 pub(crate) struct FunctionCoverage<'tcx> {
     pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo,
     ids_info: &'tcx CoverageIdsInfo,
@@ -67,6 +13,20 @@ pub(crate) struct FunctionCoverage<'tcx> {
 }
 
 impl<'tcx> FunctionCoverage<'tcx> {
+    pub(crate) fn new_used(
+        function_coverage_info: &'tcx FunctionCoverageInfo,
+        ids_info: &'tcx CoverageIdsInfo,
+    ) -> Self {
+        Self { function_coverage_info, ids_info, is_used: true }
+    }
+
+    pub(crate) fn new_unused(
+        function_coverage_info: &'tcx FunctionCoverageInfo,
+        ids_info: &'tcx CoverageIdsInfo,
+    ) -> Self {
+        Self { function_coverage_info, ids_info, is_used: false }
+    }
+
     /// Returns true for a used (called) function, and false for an unused function.
     pub(crate) fn is_used(&self) -> bool {
         self.is_used
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 8c24579fa7cc..593b986389bf 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -20,7 +20,7 @@ use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
 use crate::common::CodegenCx;
-use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
+use crate::coverageinfo::map_data::FunctionCoverage;
 use crate::coverageinfo::{ffi, llvm_cov};
 use crate::llvm;
 
@@ -63,16 +63,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         None => return,
     };
     if function_coverage_map.is_empty() {
-        // This module has no functions with coverage instrumentation
+        // This CGU has no functions with coverage instrumentation.
         return;
     }
 
-    let function_coverage_entries = function_coverage_map
-        .into_iter()
-        .map(|(instance, function_coverage)| (instance, function_coverage.into_finished()))
-        .collect::>();
-
-    let all_file_names = function_coverage_entries
+    let all_file_names = function_coverage_map
         .iter()
         .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span)
         .map(|span| span_file_name(tcx, span));
@@ -92,7 +87,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
     let mut unused_function_names = Vec::new();
 
     // Encode coverage mappings and generate function records
-    for (instance, function_coverage) in function_coverage_entries {
+    for (instance, function_coverage) in function_coverage_map {
         debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
 
         let mangled_function_name = tcx.symbol_name(instance).name;
@@ -536,11 +531,7 @@ fn add_unused_function_coverage<'tcx>(
     );
 
     // An unused function's mappings will all be rewritten to map to zero.
-    let function_coverage = FunctionCoverageCollector::unused(
-        instance,
-        function_coverage_info,
-        tcx.coverage_ids_info(instance.def),
-    );
-
+    let function_coverage =
+        FunctionCoverage::new_unused(function_coverage_info, tcx.coverage_ids_info(instance.def));
     cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index c2fcb33f98bc..82b6677e2038 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -13,7 +13,7 @@ use tracing::{debug, instrument};
 
 use crate::builder::Builder;
 use crate::common::CodegenCx;
-use crate::coverageinfo::map_data::FunctionCoverageCollector;
+use crate::coverageinfo::map_data::FunctionCoverage;
 use crate::llvm;
 
 pub(crate) mod ffi;
@@ -24,8 +24,7 @@ mod mapgen;
 /// Extra per-CGU context/state needed for coverage instrumentation.
 pub(crate) struct CguCoverageContext<'ll, 'tcx> {
     /// Coverage data for each instrumented function identified by DefId.
-    pub(crate) function_coverage_map:
-        RefCell, FunctionCoverageCollector<'tcx>>>,
+    pub(crate) function_coverage_map: RefCell, FunctionCoverage<'tcx>>>,
     pub(crate) pgo_func_name_var_map: RefCell, &'ll llvm::Value>>,
     pub(crate) mcdc_condition_bitmap_map: RefCell, Vec<&'ll llvm::Value>>>,
 
@@ -42,9 +41,7 @@ impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
         }
     }
 
-    fn take_function_coverage_map(
-        &self,
-    ) -> FxIndexMap, FunctionCoverageCollector<'tcx>> {
+    fn take_function_coverage_map(&self) -> FxIndexMap, FunctionCoverage<'tcx>> {
         self.function_coverage_map.replace(FxIndexMap::default())
     }
 
@@ -161,8 +158,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
         // This includes functions that were not partitioned into this CGU,
         // but were MIR-inlined into one of this CGU's functions.
         coverage_cx.function_coverage_map.borrow_mut().entry(instance).or_insert_with(|| {
-            FunctionCoverageCollector::new(
-                instance,
+            FunctionCoverage::new_used(
                 function_coverage_info,
                 bx.tcx.coverage_ids_info(instance.def),
             )

From 3a35fb69380d9978c2f1cb1dc26ff063927ffa41 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Sun, 8 Dec 2024 20:49:28 +1100
Subject: [PATCH 099/197] coverage: Unused functions don't need to store
 `CoverageIdsInfo`

---
 .../src/coverageinfo/map_data.rs              | 23 ++++++++++---------
 .../src/coverageinfo/mapgen.rs                |  3 +--
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
index f30a987e4a19..c5d1ebdfe7c5 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs
@@ -8,8 +8,8 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
 
 pub(crate) struct FunctionCoverage<'tcx> {
     pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo,
-    ids_info: &'tcx CoverageIdsInfo,
-    is_used: bool,
+    /// If `None`, the corresponding function is unused.
+    ids_info: Option<&'tcx CoverageIdsInfo>,
 }
 
 impl<'tcx> FunctionCoverage<'tcx> {
@@ -17,25 +17,22 @@ impl<'tcx> FunctionCoverage<'tcx> {
         function_coverage_info: &'tcx FunctionCoverageInfo,
         ids_info: &'tcx CoverageIdsInfo,
     ) -> Self {
-        Self { function_coverage_info, ids_info, is_used: true }
+        Self { function_coverage_info, ids_info: Some(ids_info) }
     }
 
-    pub(crate) fn new_unused(
-        function_coverage_info: &'tcx FunctionCoverageInfo,
-        ids_info: &'tcx CoverageIdsInfo,
-    ) -> Self {
-        Self { function_coverage_info, ids_info, is_used: false }
+    pub(crate) fn new_unused(function_coverage_info: &'tcx FunctionCoverageInfo) -> Self {
+        Self { function_coverage_info, ids_info: None }
     }
 
     /// Returns true for a used (called) function, and false for an unused function.
     pub(crate) fn is_used(&self) -> bool {
-        self.is_used
+        self.ids_info.is_some()
     }
 
     /// Return the source hash, generated from the HIR node structure, and used to indicate whether
     /// or not the source code structure changed between different compilations.
     pub(crate) fn source_hash(&self) -> u64 {
-        if self.is_used { self.function_coverage_info.function_source_hash } else { 0 }
+        if self.is_used() { self.function_coverage_info.function_source_hash } else { 0 }
     }
 
     /// Convert this function's coverage expression data into a form that can be
@@ -78,6 +75,10 @@ impl<'tcx> FunctionCoverage<'tcx> {
     }
 
     fn is_zero_term(&self, term: CovTerm) -> bool {
-        !self.is_used || self.ids_info.is_zero_term(term)
+        match self.ids_info {
+            Some(ids_info) => ids_info.is_zero_term(term),
+            // This function is unused, so all coverage counters/expressions are zero.
+            None => true,
+        }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 593b986389bf..a6c3caf9e2b5 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -531,7 +531,6 @@ fn add_unused_function_coverage<'tcx>(
     );
 
     // An unused function's mappings will all be rewritten to map to zero.
-    let function_coverage =
-        FunctionCoverage::new_unused(function_coverage_info, tcx.coverage_ids_info(instance.def));
+    let function_coverage = FunctionCoverage::new_unused(function_coverage_info);
     cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage);
 }

From 477b722fe1126ce3aa61757687b8685f1cf9b43f Mon Sep 17 00:00:00 2001
From: Prajwal S N 
Date: Sun, 8 Dec 2024 18:21:15 +0530
Subject: [PATCH 100/197] docs: better examples for `std::ops::ControlFlow`

Signed-off-by: Prajwal S N 
---
 library/core/src/ops/control_flow.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index c4429b3cd7d4..c8fcee5c140f 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -141,8 +141,8 @@ impl ControlFlow {
     /// ```
     /// use std::ops::ControlFlow;
     ///
-    /// assert!(ControlFlow::::Break(3).is_break());
-    /// assert!(!ControlFlow::::Continue(3).is_break());
+    /// assert!(ControlFlow::<&str, i32>::Break("Stop right there!").is_break());
+    /// assert!(!ControlFlow::<&str, i32>::Continue(3).is_break());
     /// ```
     #[inline]
     #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
@@ -157,8 +157,8 @@ impl ControlFlow {
     /// ```
     /// use std::ops::ControlFlow;
     ///
-    /// assert!(!ControlFlow::::Break(3).is_continue());
-    /// assert!(ControlFlow::::Continue(3).is_continue());
+    /// assert!(!ControlFlow::<&str, i32>::Break("Stop right there!").is_continue());
+    /// assert!(ControlFlow::<&str, i32>::Continue(3).is_continue());
     /// ```
     #[inline]
     #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
@@ -174,8 +174,8 @@ impl ControlFlow {
     /// ```
     /// use std::ops::ControlFlow;
     ///
-    /// assert_eq!(ControlFlow::::Break(3).break_value(), Some(3));
-    /// assert_eq!(ControlFlow::::Continue(3).break_value(), None);
+    /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").break_value(), Some("Stop right there!"));
+    /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).break_value(), None);
     /// ```
     #[inline]
     #[stable(feature = "control_flow_enum", since = "1.83.0")]
@@ -205,8 +205,8 @@ impl ControlFlow {
     /// ```
     /// use std::ops::ControlFlow;
     ///
-    /// assert_eq!(ControlFlow::::Break(3).continue_value(), None);
-    /// assert_eq!(ControlFlow::::Continue(3).continue_value(), Some(3));
+    /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").continue_value(), None);
+    /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).continue_value(), Some(3));
     /// ```
     #[inline]
     #[stable(feature = "control_flow_enum", since = "1.83.0")]

From ee300059c5493ea2798803fa9a1389a682fec669 Mon Sep 17 00:00:00 2001
From: Chayim Refael Friedman 
Date: Sun, 8 Dec 2024 15:02:14 +0200
Subject: [PATCH 101/197] Fix a test that didn't test what it should

That is, fix the helper function and disable the tests for now.
---
 .../hir-def/src/nameres/tests/incremental.rs  | 90 ++++++++++---------
 1 file changed, 46 insertions(+), 44 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index d920c1082662..e54b0fb78f82 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -8,7 +8,8 @@ fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change:
     let krate = {
         let crate_graph = db.crate_graph();
         // Some of these tests use minicore/proc-macros which will be injected as the first crate
-        crate_graph.iter().last().unwrap()
+        let krate = crate_graph.iter().next().unwrap();
+        krate
     };
     {
         let events = db.log_executed(|| {
@@ -120,28 +121,29 @@ fn f() { foo }
     );
 }
 
-#[test]
-fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
-    check_def_map_is_not_recomputed(
-        r"
-//- proc_macros: identity
-//- /lib.rs
-mod foo;
+// #[test]
+// fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
+//     check_def_map_is_not_recomputed(
+//         r"
+// //- proc_macros: identity
+// //- /lib.rs
+// mod foo;
 
-//- /foo/mod.rs
-pub mod bar;
+// //- /foo/mod.rs
+// pub mod bar;
+
+// //- /foo/bar.rs
+// $0
+// #[proc_macros::identity]
+// fn f() {}
+// ",
+//         r"
+// #[proc_macros::identity(foo)]
+// fn f() {}
+// ",
+//     );
+// }
 
-//- /foo/bar.rs
-$0
-#[proc_macros::identity]
-fn f() {}
-",
-        r"
-#[proc_macros::identity(foo)]
-fn f() {}
-",
-    );
-}
 #[test]
 fn typing_inside_macro_heavy_file_should_not_invalidate_def_map() {
     check_def_map_is_not_recomputed(
@@ -198,31 +200,31 @@ pub struct S {}
     );
 }
 
-#[test]
-fn typing_inside_a_derive_should_not_invalidate_def_map() {
-    check_def_map_is_not_recomputed(
-        r"
-//- proc_macros: derive_identity
-//- minicore:derive
-//- /lib.rs
-mod foo;
+// #[test]
+// fn typing_inside_a_derive_should_not_invalidate_def_map() {
+//     check_def_map_is_not_recomputed(
+//         r"
+// //- proc_macros: derive_identity
+// //- minicore:derive
+// //- /lib.rs
+// mod foo;
 
-//- /foo/mod.rs
-pub mod bar;
+// //- /foo/mod.rs
+// pub mod bar;
 
-//- /foo/bar.rs
-$0
-#[derive(proc_macros::DeriveIdentity)]
-#[allow()]
-struct S;
-",
-        r"
-#[derive(proc_macros::DeriveIdentity)]
-#[allow(dead_code)]
-struct S;
-",
-    );
-}
+// //- /foo/bar.rs
+// $0
+// #[derive(proc_macros::DeriveIdentity)]
+// #[allow()]
+// struct S;
+// ",
+//         r"
+// #[derive(proc_macros::DeriveIdentity)]
+// #[allow(dead_code)]
+// struct S;
+// ",
+//     );
+// }
 
 #[test]
 fn typing_inside_a_function_should_not_invalidate_item_expansions() {

From c4d7f1d29f05e9655e3827529ba4da3438e3e1fb Mon Sep 17 00:00:00 2001
From: onur-ozkan 
Date: Sun, 8 Dec 2024 18:27:22 +0300
Subject: [PATCH 102/197] implement `TargetSelection::is_cygwin` function

Signed-off-by: onur-ozkan 
---
 src/bootstrap/src/core/config/config.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index b06147055f2a..a07d1597746c 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -565,6 +565,12 @@ impl TargetSelection {
         self.ends_with("windows-gnu")
     }
 
+    pub fn is_cygwin(&self) -> bool {
+        self.is_windows() &&
+        // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html
+        env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin"))
+    }
+
     /// Path to the file defining the custom target, if any.
     pub fn filepath(&self) -> Option<&Path> {
         self.file.as_ref().map(Path::new)

From d3b53408789ad749b027a1932459e22bc2685622 Mon Sep 17 00:00:00 2001
From: onur-ozkan 
Date: Sun, 8 Dec 2024 18:27:46 +0300
Subject: [PATCH 103/197] handle cygwin environments in `install::sanitize_sh`

Signed-off-by: onur-ozkan 
---
 src/bootstrap/src/core/build_steps/install.rs | 25 ++++++++++---------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 0ce86eadbce6..b6862c2d5c4a 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -21,9 +21,9 @@ const SHELL: &str = "sh";
 
 /// We have to run a few shell scripts, which choke quite a bit on both `\`
 /// characters and on `C:\` paths, so normalize both of them away.
-fn sanitize_sh(path: &Path) -> String {
+fn sanitize_sh(path: &Path, is_cygwin: bool) -> String {
     let path = path.to_str().unwrap().replace('\\', "/");
-    return change_drive(unc_to_lfs(&path)).unwrap_or(path);
+    return if is_cygwin { path } else { change_drive(unc_to_lfs(&path)).unwrap_or(path) };
 
     fn unc_to_lfs(s: &str) -> &str {
         s.strip_prefix("//?/").unwrap_or(s)
@@ -71,6 +71,7 @@ fn install_sh(
     let prefix = default_path(&builder.config.prefix, "/usr/local");
     let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
     let destdir_env = env::var_os("DESTDIR").map(PathBuf::from);
+    let is_cygwin = builder.config.build.is_cygwin();
 
     // Sanity checks on the write access of user.
     //
@@ -103,14 +104,14 @@ fn install_sh(
 
     let mut cmd = command(SHELL);
     cmd.current_dir(&empty_dir)
-        .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
-        .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
-        .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir)))
-        .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir)))
-        .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir)))
-        .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir)))
-        .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
-        .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
+        .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"), is_cygwin))
+        .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix, is_cygwin)))
+        .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir, is_cygwin)))
+        .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir, is_cygwin)))
+        .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir, is_cygwin)))
+        .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir, is_cygwin)))
+        .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir, is_cygwin)))
+        .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir, is_cygwin)))
         .arg("--disable-ldconfig");
     cmd.run(builder);
     t!(fs::remove_dir_all(&empty_dir));
@@ -120,7 +121,7 @@ fn default_path(config: &Option, default: &str) -> PathBuf {
     config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
 }
 
-fn prepare_dir(destdir_env: &Option, mut path: PathBuf) -> String {
+fn prepare_dir(destdir_env: &Option, mut path: PathBuf, is_cygwin: bool) -> String {
     // The DESTDIR environment variable is a standard way to install software in a subdirectory
     // while keeping the original directory structure, even if the prefix or other directories
     // contain absolute paths.
@@ -146,7 +147,7 @@ fn prepare_dir(destdir_env: &Option, mut path: PathBuf) -> String {
         assert!(path.is_absolute(), "could not make the path relative");
     }
 
-    sanitize_sh(&path)
+    sanitize_sh(&path, is_cygwin)
 }
 
 macro_rules! install {

From 2d8a871d4b6e1d636ac7c44742c54551e0d3fc09 Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Sun, 8 Dec 2024 18:18:03 +0000
Subject: [PATCH 104/197] Downgrade cc

---
 Cargo.lock                    | 4 ++--
 library/Cargo.lock            | 4 ++--
 src/tools/rustbook/Cargo.lock | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 89e7d70d839a..28478876a27a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -405,9 +405,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 490c989300f5..03c2356e542a 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -42,9 +42,9 @@ checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 3d35779be90f..bab818899fbc 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.2"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
+checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
 dependencies = [
  "shlex",
 ]

From c199c49aef61be2b483399b62e01fd0736035ccb Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Sun, 8 Dec 2024 18:57:04 +0000
Subject: [PATCH 105/197] Use SourceMap to load debugger visualizer files

---
 compiler/rustc_passes/src/debugger_visualizer.rs | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index fec149c8c432..062d56a79a0b 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -1,7 +1,6 @@
 //! Detecting usage of the `#[debugger_visualizer]` attribute.
 
 use rustc_ast::Attribute;
-use rustc_data_structures::sync::Lrc;
 use rustc_expand::base::resolve_path;
 use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
 use rustc_middle::query::{LocalCrate, Providers};
@@ -49,10 +48,10 @@ impl DebuggerVisualizerCollector<'_> {
                 }
             };
 
-            match std::fs::read(&file) {
-                Ok(contents) => {
+            match self.sess.source_map().load_binary_file(&file) {
+                Ok((source, _)) => {
                     self.visualizers.push(DebuggerVisualizerFile::new(
-                        Lrc::from(contents),
+                        source,
                         visualizer_type,
                         file,
                     ));

From 1220f393cc7a48001ce9080b3e863b15de260c7e Mon Sep 17 00:00:00 2001
From: Sayantan Chakraborty <142906350+sayantn@users.noreply.github.com>
Date: Mon, 9 Dec 2024 00:41:35 +0530
Subject: [PATCH 106/197] Add the `power8-crypto` target feature

---
 compiler/rustc_codegen_llvm/src/llvm_util.rs | 3 +++
 compiler/rustc_target/src/target_features.rs | 1 +
 tests/ui/check-cfg/target_feature.stderr     | 1 +
 3 files changed, 5 insertions(+)

diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index db2b03d9aeda..07eb89e60413 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -230,6 +230,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("v9")),
         ("sparc", "v8plus") if get_version().0 < 19 => None,
+        ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")),
         (_, s) => Some(LLVMFeature::new(s)),
     }
 }
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 67c047dddfcf..3a1306072658 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -412,6 +412,7 @@ const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
     ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]),
     ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]),
+    ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
     ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]),
     ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]),
     ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]),
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index 2674a97a551e..3df1545cd4aa 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -153,6 +153,7 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
 `popcnt`
 `power10-vector`
 `power8-altivec`
+`power8-crypto`
 `power8-vector`
 `power9-altivec`
 `power9-vector`

From 30e3d23f0ef3ed7d43c096d768cc6386986d86f2 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Mon, 18 Nov 2024 18:11:13 -0500
Subject: [PATCH 107/197] fix: Map new replacement nodes to their mutable
 equivalents in `SyntaxEditor`

---
 .../crates/ide-assists/src/handlers/flip_binexpr.rs       | 5 ++---
 .../crates/ide-assists/src/handlers/flip_comma.rs         | 5 ++---
 .../crates/ide-assists/src/handlers/flip_trait_bound.rs   | 4 ++--
 .../crates/ide-assists/src/handlers/reorder_fields.rs     | 7 +++----
 .../crates/ide-assists/src/handlers/reorder_impl_items.rs | 8 ++++----
 .../crates/ide-assists/src/handlers/sort_items.rs         | 7 +++----
 .../crates/syntax/src/syntax_editor/edit_algo.rs          | 6 ++++++
 7 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
index 601fd29f8e7c..818a868fe344 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs
@@ -52,9 +52,8 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
             if let FlipAction::FlipAndReplaceOp(binary_op) = action {
                 editor.replace(op_token, make.token(binary_op))
             };
-            // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-            editor.replace(lhs.syntax(), rhs.syntax().clone_for_update());
-            editor.replace(rhs.syntax(), lhs.syntax().clone_for_update());
+            editor.replace(lhs.syntax(), rhs.syntax());
+            editor.replace(rhs.syntax(), lhs.syntax());
             editor.add_mappings(make.finish_with_mappings());
             builder.add_file_edits(ctx.file_id(), editor);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
index 490a9ee3c04d..95e035c05379 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs
@@ -39,13 +39,12 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         return None;
     }
 
-    // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
     let prev = match prev {
-        SyntaxElement::Node(node) => node.clone_for_update().syntax_element(),
+        SyntaxElement::Node(node) => node.syntax_element(),
         _ => prev,
     };
     let next = match next {
-        SyntaxElement::Node(node) => node.clone_for_update().syntax_element(),
+        SyntaxElement::Node(node) => node.syntax_element(),
         _ => next,
     };
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
index 03366bd8616c..298e5bd82c98 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
@@ -37,8 +37,8 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
         target,
         |builder| {
             let mut editor = builder.make_editor(parent.syntax());
-            editor.replace(before.clone(), after.clone_for_update());
-            editor.replace(after.clone(), before.clone_for_update());
+            editor.replace(before.clone(), after.clone());
+            editor.replace(after, before);
             builder.add_file_edits(ctx.file_id(), editor);
         },
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 4d3e85ab1b20..972303c2a041 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -92,10 +92,9 @@ fn replace(
     fields: impl Iterator,
     sorted_fields: impl IntoIterator,
 ) {
-    fields.zip(sorted_fields).for_each(|(field, sorted_field)| {
-        // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-        editor.replace(field.syntax(), sorted_field.syntax().clone_for_update())
-    });
+    fields
+        .zip(sorted_fields)
+        .for_each(|(field, sorted_field)| editor.replace(field.syntax(), sorted_field.syntax()));
 }
 
 fn compute_fields_ranks(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index d7fa8826125b..eb1d538f8743 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -101,10 +101,10 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         |builder| {
             let mut editor = builder.make_editor(&parent_node);
 
-            assoc_items.into_iter().zip(sorted).for_each(|(old, new)| {
-                // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-                editor.replace(old.syntax(), new.clone_for_update().syntax())
-            });
+            assoc_items
+                .into_iter()
+                .zip(sorted)
+                .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
 
             builder.add_file_edits(ctx.file_id(), editor);
         },
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
index 7307325e496c..54e16d4d80a4 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs
@@ -133,10 +133,9 @@ impl AddRewrite for Assists {
             |builder| {
                 let mut editor = builder.make_editor(target);
 
-                old.into_iter().zip(new).for_each(|(old, new)| {
-                    // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us
-                    editor.replace(old.syntax(), new.clone_for_update().syntax())
-                });
+                old.into_iter()
+                    .zip(new)
+                    .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax()));
 
                 builder.add_file_edits(builder.file_id, editor)
             },
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
index 71b69dbec1d6..57ecbe57019b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -155,6 +155,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
                     }
                 };
             }
+            Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(new_target))) => {
+                *target = tree_mutator.make_syntax_mut(target);
+                if new_target.ancestors().any(|node| node == tree_mutator.immutable) {
+                    *new_target = new_target.clone_for_update();
+                }
+            }
             Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
                 *target = tree_mutator.make_element_mut(target);
             }

From dd28c40c295778fc3c3cb945c443efc6ec86ee2e Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Thu, 5 Dec 2024 12:49:04 +1100
Subject: [PATCH 108/197] Use `BitSet` in `SparseBitMatrix`.

A `ChunkedBitSet` has to be at least 2048 bits for it to outperform a
`BitSet`, because that's the chunk size. The largest `SparseBitMatrix`
encountered when compiling the compiler and the entire rustc-perf
benchmark suite is less than 600 bits.

This change is a tiny perf win, but the motivation is more about
avoiding uses of `ChunkedBitSet` outside of `MixedBitSet`.

The test change is necessary to avoid hitting the ` as
BitRelations>>::subtract` method that has
`unimplemented!` in its body and isn't otherwise used.
---
 compiler/rustc_index/src/bit_set.rs       | 20 ++++++++++----------
 compiler/rustc_index/src/bit_set/tests.rs |  6 +++---
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 41bd47ea6d06..aba1e9382969 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -1529,7 +1529,7 @@ impl fmt::Debug for BitMatrix {
 /// sparse representation.
 ///
 /// Initially, every row has no explicit representation. If any bit within a
-/// row is set, the entire row is instantiated as `Some()`.
+/// row is set, the entire row is instantiated as `Some()`.
 /// Furthermore, any previously uninstantiated rows prior to it will be
 /// instantiated as `None`. Those prior rows may themselves become fully
 /// instantiated later on if any of their bits are set.
@@ -1543,7 +1543,7 @@ where
     C: Idx,
 {
     num_columns: usize,
-    rows: IndexVec>>,
+    rows: IndexVec>>,
 }
 
 impl SparseBitMatrix {
@@ -1552,10 +1552,10 @@ impl SparseBitMatrix {
         Self { num_columns, rows: IndexVec::new() }
     }
 
-    fn ensure_row(&mut self, row: R) -> &mut ChunkedBitSet {
-        // Instantiate any missing rows up to and including row `row` with an empty ChunkedBitSet.
-        // Then replace row `row` with a full ChunkedBitSet if necessary.
-        self.rows.get_or_insert_with(row, || ChunkedBitSet::new_empty(self.num_columns))
+    fn ensure_row(&mut self, row: R) -> &mut BitSet {
+        // Instantiate any missing rows up to and including row `row` with an empty `BitSet`.
+        // Then replace row `row` with a full `BitSet` if necessary.
+        self.rows.get_or_insert_with(row, || BitSet::new_empty(self.num_columns))
     }
 
     /// Sets the cell at `(row, column)` to true. Put another way, insert
@@ -1629,7 +1629,7 @@ impl SparseBitMatrix {
         self.row(row).into_iter().flat_map(|r| r.iter())
     }
 
-    pub fn row(&self, row: R) -> Option<&ChunkedBitSet> {
+    pub fn row(&self, row: R) -> Option<&BitSet> {
         self.rows.get(row)?.as_ref()
     }
 
@@ -1639,7 +1639,7 @@ impl SparseBitMatrix {
     /// Returns true if the row was changed.
     pub fn intersect_row(&mut self, row: R, set: &Set) -> bool
     where
-        ChunkedBitSet: BitRelations,
+        BitSet: BitRelations,
     {
         match self.rows.get_mut(row) {
             Some(Some(row)) => row.intersect(set),
@@ -1653,7 +1653,7 @@ impl SparseBitMatrix {
     /// Returns true if the row was changed.
     pub fn subtract_row(&mut self, row: R, set: &Set) -> bool
     where
-        ChunkedBitSet: BitRelations,
+        BitSet: BitRelations,
     {
         match self.rows.get_mut(row) {
             Some(Some(row)) => row.subtract(set),
@@ -1667,7 +1667,7 @@ impl SparseBitMatrix {
     /// Returns true if the row was changed.
     pub fn union_row(&mut self, row: R, set: &Set) -> bool
     where
-        ChunkedBitSet: BitRelations,
+        BitSet: BitRelations,
     {
         self.ensure_row(row).union(set)
     }
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index 3f9198ce37f1..f61423239793 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -503,15 +503,15 @@ fn sparse_matrix_operations() {
     matrix.insert(2, 99);
     matrix.insert(4, 0);
 
-    let mut disjoint: ChunkedBitSet = ChunkedBitSet::new_empty(100);
+    let mut disjoint: BitSet = BitSet::new_empty(100);
     disjoint.insert(33);
 
-    let mut superset = ChunkedBitSet::new_empty(100);
+    let mut superset = BitSet::new_empty(100);
     superset.insert(22);
     superset.insert(75);
     superset.insert(33);
 
-    let mut subset = ChunkedBitSet::new_empty(100);
+    let mut subset = BitSet::new_empty(100);
     subset.insert(22);
 
     // SparseBitMatrix::remove

From 34f45f0d8f0eb4a3dde0123a8daafc3c7f7e59f3 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Thu, 5 Dec 2024 15:03:17 +1100
Subject: [PATCH 109/197] Use `MixedBitSet` instead of `ChunkedBitSet` in
 `fmt.rs`.

Just minimizing uses of `ChunkedBitSet`.
---
 compiler/rustc_mir_dataflow/src/framework/fmt.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
index 186172b3b86b..faf2c411ddef 100644
--- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -85,8 +85,8 @@ where
         let size = self.domain_size();
         assert_eq!(size, old.domain_size());
 
-        let mut set_in_self = ChunkedBitSet::new_empty(size);
-        let mut cleared_in_self = ChunkedBitSet::new_empty(size);
+        let mut set_in_self = MixedBitSet::new_empty(size);
+        let mut cleared_in_self = MixedBitSet::new_empty(size);
 
         for i in (0..size).map(T::new) {
             match (self.contains(i), old.contains(i)) {
@@ -112,8 +112,8 @@ where
         let size = self.domain_size();
         assert_eq!(size, old.domain_size());
 
-        let mut set_in_self = ChunkedBitSet::new_empty(size);
-        let mut cleared_in_self = ChunkedBitSet::new_empty(size);
+        let mut set_in_self = MixedBitSet::new_empty(size);
+        let mut cleared_in_self = MixedBitSet::new_empty(size);
 
         for i in (0..size).map(T::new) {
             match (self.contains(i), old.contains(i)) {
@@ -179,8 +179,8 @@ where
 }
 
 fn fmt_diff(
-    inserted: &ChunkedBitSet,
-    removed: &ChunkedBitSet,
+    inserted: &MixedBitSet,
+    removed: &MixedBitSet,
     ctxt: &C,
     f: &mut fmt::Formatter<'_>,
 ) -> fmt::Result

From fa6ceba208fed892648679342fbf444d68385195 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Thu, 5 Dec 2024 15:05:42 +1100
Subject: [PATCH 110/197] Remove `ChunkedBitSet` impls that are no longer
 needed.

`ChunkedBitSet` is no longer used directly by dataflow analyses, with
`MixedBitSet` replacing it in those contexts.
---
 .../src/framework/lattice.rs                   |  8 +-------
 .../rustc_mir_dataflow/src/framework/mod.rs    | 18 +-----------------
 2 files changed, 2 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 852099e2ac82..e063eaf74bd4 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -40,7 +40,7 @@
 
 use std::iter;
 
-use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet};
+use rustc_index::bit_set::{BitSet, MixedBitSet};
 use rustc_index::{Idx, IndexVec};
 
 use crate::framework::BitSetExt;
@@ -126,12 +126,6 @@ impl JoinSemiLattice for BitSet {
     }
 }
 
-impl JoinSemiLattice for ChunkedBitSet {
-    fn join(&mut self, other: &Self) -> bool {
-        self.union(other)
-    }
-}
-
 impl JoinSemiLattice for MixedBitSet {
     fn join(&mut self, other: &Self) -> bool {
         self.union(other)
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 40fb22014e5b..caff2a81ff30 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -35,7 +35,7 @@
 use std::cmp::Ordering;
 
 use rustc_data_structures::work_queue::WorkQueue;
-use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet};
+use rustc_index::bit_set::{BitSet, MixedBitSet};
 use rustc_index::{Idx, IndexVec};
 use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
@@ -71,12 +71,6 @@ impl BitSetExt for BitSet {
     }
 }
 
-impl BitSetExt for ChunkedBitSet {
-    fn contains(&self, elem: T) -> bool {
-        self.contains(elem)
-    }
-}
-
 impl BitSetExt for MixedBitSet {
     fn contains(&self, elem: T) -> bool {
         self.contains(elem)
@@ -333,16 +327,6 @@ impl GenKill for BitSet {
     }
 }
 
-impl GenKill for ChunkedBitSet {
-    fn gen_(&mut self, elem: T) {
-        self.insert(elem);
-    }
-
-    fn kill(&mut self, elem: T) {
-        self.remove(elem);
-    }
-}
-
 impl GenKill for MixedBitSet {
     fn gen_(&mut self, elem: T) {
         self.insert(elem);

From 999aed4bff113924393ca55f3d6498d5c723f037 Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Sun, 8 Dec 2024 21:39:48 -0700
Subject: [PATCH 111/197] Add URL to test cases

---
 tests/rustdoc-ui/issues/issue-101076.rs | 1 +
 tests/rustdoc-ui/issues/issue-102986.rs | 1 +
 tests/rustdoc-ui/issues/issue-103997.rs | 1 +
 tests/rustdoc-ui/issues/issue-105334.rs | 1 +
 tests/rustdoc-ui/issues/issue-105737.rs | 1 +
 tests/rustdoc-ui/issues/issue-105742.rs | 1 +
 tests/rustdoc-ui/issues/issue-106213.rs | 1 +
 tests/rustdoc-ui/issues/issue-107918.rs | 1 +
 tests/rustdoc-ui/issues/issue-110900.rs | 1 +
 9 files changed, 9 insertions(+)

diff --git a/tests/rustdoc-ui/issues/issue-101076.rs b/tests/rustdoc-ui/issues/issue-101076.rs
index f9b93c408fd6..0c9a8b9175b3 100644
--- a/tests/rustdoc-ui/issues/issue-101076.rs
+++ b/tests/rustdoc-ui/issues/issue-101076.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+// https://github.com/rust-lang/rust/issues/101076
 
 const _: () = {
     #[macro_export]
diff --git a/tests/rustdoc-ui/issues/issue-102986.rs b/tests/rustdoc-ui/issues/issue-102986.rs
index 001784ac2856..8fcbfffe1724 100644
--- a/tests/rustdoc-ui/issues/issue-102986.rs
+++ b/tests/rustdoc-ui/issues/issue-102986.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/102986
 struct Struct {
     y: (typeof("hey"),),
     //~^ `typeof` is a reserved keyword but unimplemented
diff --git a/tests/rustdoc-ui/issues/issue-103997.rs b/tests/rustdoc-ui/issues/issue-103997.rs
index ebd1d2e4447d..b6ba4e48cffd 100644
--- a/tests/rustdoc-ui/issues/issue-103997.rs
+++ b/tests/rustdoc-ui/issues/issue-103997.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+// https://github.com/rust-lang/rust/issues/103997
 
 pub fn foo() {}
 
diff --git a/tests/rustdoc-ui/issues/issue-105334.rs b/tests/rustdoc-ui/issues/issue-105334.rs
index ee1adc6a0291..f18f0456fdde 100644
--- a/tests/rustdoc-ui/issues/issue-105334.rs
+++ b/tests/rustdoc-ui/issues/issue-105334.rs
@@ -1,2 +1,3 @@
+// https://github.com/rust-lang/rust/issues/105334
 impl Vec< br##"*.."## > {}
 //~^ ERROR
diff --git a/tests/rustdoc-ui/issues/issue-105737.rs b/tests/rustdoc-ui/issues/issue-105737.rs
index 154f069d8ffa..651fd9ab4b8b 100644
--- a/tests/rustdoc-ui/issues/issue-105737.rs
+++ b/tests/rustdoc-ui/issues/issue-105737.rs
@@ -1,3 +1,4 @@
+// https://github.com/rust-lang/rust/issues/105737
 impl Vec {}
 //~^ ERROR
 
diff --git a/tests/rustdoc-ui/issues/issue-105742.rs b/tests/rustdoc-ui/issues/issue-105742.rs
index bd8ec4e8b589..027574923c7a 100644
--- a/tests/rustdoc-ui/issues/issue-105742.rs
+++ b/tests/rustdoc-ui/issues/issue-105742.rs
@@ -1,4 +1,5 @@
 //@ compile-flags: -Znormalize-docs
+// https://github.com/rust-lang/rust/issues/105742
 use std::ops::Index;
 
 pub fn next<'a, T>(s: &'a mut dyn SVec) {
diff --git a/tests/rustdoc-ui/issues/issue-106213.rs b/tests/rustdoc-ui/issues/issue-106213.rs
index 5c3a83902523..c954162589d9 100644
--- a/tests/rustdoc-ui/issues/issue-106213.rs
+++ b/tests/rustdoc-ui/issues/issue-106213.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: --document-private-items
 //@ edition:2021
+// https://github.com/rust-lang/rust/issues/106213
 
 fn use_avx() -> dyn  {
     //~^ ERROR at least one trait is required for an object type
diff --git a/tests/rustdoc-ui/issues/issue-107918.rs b/tests/rustdoc-ui/issues/issue-107918.rs
index 19d53f84cb66..ec35b52e33b0 100644
--- a/tests/rustdoc-ui/issues/issue-107918.rs
+++ b/tests/rustdoc-ui/issues/issue-107918.rs
@@ -2,6 +2,7 @@
 //@ compile-flags: --document-private-items
 //@ build-pass
 //@ only-linux
+// https://github.com/rust-lang/rust/issues/107918
 
 #![no_std]
 #![no_main]
diff --git a/tests/rustdoc-ui/issues/issue-110900.rs b/tests/rustdoc-ui/issues/issue-110900.rs
index 5a8961670833..4fa60f8878d1 100644
--- a/tests/rustdoc-ui/issues/issue-110900.rs
+++ b/tests/rustdoc-ui/issues/issue-110900.rs
@@ -1,4 +1,5 @@
 //@ check-pass
+// https://github.com/rust-lang/rust/issues/110900
 
 #![crate_type="lib"]
 

From b5318549c701771bde8b06709a69d7e3eb860c1f Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Sun, 8 Dec 2024 21:59:23 -0700
Subject: [PATCH 112/197] rustdoc: rename `issue-\d+.rs` tests to have
 meaningful names

---
 ...7918.rs => duplicate-panic-impl-107918.rs} |   0
 ...s => ice-associated-type-bounds-110900.rs} |   0
 ...issue-106213.rs => ice-bare-dyn-106213.rs} |   0
 ...6213.stderr => ice-bare-dyn-106213.stderr} |   2 +-
 ...42.rs => ice-generic-type-alias-105742.rs} |   0
 ...r => ice-generic-type-alias-105742.stderr} | 148 +++++++++---------
 ...05737.rs => ice-impl-fn-generic-105737.rs} |   0
 ...derr => ice-impl-fn-generic-105737.stderr} |   2 +-
 ...cro-hidden-exported-macro-defid-101076.rs} |   0
 ...s => ice-placeholder-type-alias-106226.rs} |   0
 ... ice-placeholder-type-alias-106226.stderr} |   2 +-
 ...{issue-105334.rs => ice-raw-str-105334.rs} |   0
 ...05334.stderr => ice-raw-str-105334.stderr} |   2 +-
 .../{issue-102986.rs => ice-typeof-102986.rs} |   0
 ...102986.stderr => ice-typeof-102986.stderr} |   2 +-
 ...03997.rs => ice-unresolved-self-103997.rs} |   0
 ...derr => ice-unresolved-self-103997.stderr} |   2 +-
 17 files changed, 80 insertions(+), 80 deletions(-)
 rename tests/rustdoc-ui/issues/{issue-107918.rs => duplicate-panic-impl-107918.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-110900.rs => ice-associated-type-bounds-110900.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-106213.rs => ice-bare-dyn-106213.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-106213.stderr => ice-bare-dyn-106213.stderr} (85%)
 rename tests/rustdoc-ui/issues/{issue-105742.rs => ice-generic-type-alias-105742.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-105742.stderr => ice-generic-type-alias-105742.stderr} (84%)
 rename tests/rustdoc-ui/issues/{issue-105737.rs => ice-impl-fn-generic-105737.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-105737.stderr => ice-impl-fn-generic-105737.stderr} (87%)
 rename tests/rustdoc-ui/issues/{issue-101076.rs => ice-macro-hidden-exported-macro-defid-101076.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-106226.rs => ice-placeholder-type-alias-106226.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-106226.stderr => ice-placeholder-type-alias-106226.stderr} (84%)
 rename tests/rustdoc-ui/issues/{issue-105334.rs => ice-raw-str-105334.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-105334.stderr => ice-raw-str-105334.stderr} (85%)
 rename tests/rustdoc-ui/issues/{issue-102986.rs => ice-typeof-102986.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-102986.stderr => ice-typeof-102986.stderr} (90%)
 rename tests/rustdoc-ui/issues/{issue-103997.rs => ice-unresolved-self-103997.rs} (100%)
 rename tests/rustdoc-ui/issues/{issue-103997.stderr => ice-unresolved-self-103997.stderr} (83%)

diff --git a/tests/rustdoc-ui/issues/issue-107918.rs b/tests/rustdoc-ui/issues/duplicate-panic-impl-107918.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-107918.rs
rename to tests/rustdoc-ui/issues/duplicate-panic-impl-107918.rs
diff --git a/tests/rustdoc-ui/issues/issue-110900.rs b/tests/rustdoc-ui/issues/ice-associated-type-bounds-110900.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-110900.rs
rename to tests/rustdoc-ui/issues/ice-associated-type-bounds-110900.rs
diff --git a/tests/rustdoc-ui/issues/issue-106213.rs b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-106213.rs
rename to tests/rustdoc-ui/issues/ice-bare-dyn-106213.rs
diff --git a/tests/rustdoc-ui/issues/issue-106213.stderr b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.stderr
similarity index 85%
rename from tests/rustdoc-ui/issues/issue-106213.stderr
rename to tests/rustdoc-ui/issues/ice-bare-dyn-106213.stderr
index fa79fe2e71c1..b029fee510ee 100644
--- a/tests/rustdoc-ui/issues/issue-106213.stderr
+++ b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.stderr
@@ -1,5 +1,5 @@
 error[E0224]: at least one trait is required for an object type
-  --> $DIR/issue-106213.rs:4:17
+  --> $DIR/ice-bare-dyn-106213.rs:5:17
    |
 LL | fn use_avx() -> dyn  {
    |                 ^^^
diff --git a/tests/rustdoc-ui/issues/issue-105742.rs b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-105742.rs
rename to tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs
diff --git a/tests/rustdoc-ui/issues/issue-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
similarity index 84%
rename from tests/rustdoc-ui/issues/issue-105742.stderr
rename to tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
index 0f09d637f38f..06a1cf6b118d 100644
--- a/tests/rustdoc-ui/issues/issue-105742.stderr
+++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr
@@ -1,11 +1,11 @@
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -15,13 +15,13 @@ LL |     ::Item<'a>,
    |                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -31,13 +31,13 @@ LL |     ::Item,
    |                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -47,13 +47,13 @@ LL |     Output = ::Item<'a>,
    |                                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -63,13 +63,13 @@ LL |     Output = ::Item,
    |                                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -79,13 +79,13 @@ LL |     Output = ::Item<'a>> as SVec>::Item,
    |                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -95,13 +95,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -111,13 +111,13 @@ LL |     Output = ::Item> as SVec>::Item<'a>,
    |                                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -127,13 +127,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:4:40
+  --> $DIR/ice-generic-type-alias-105742.rs:5:40
    |
 LL | pub fn next<'a, T>(s: &'a mut dyn SVec) {
    |                                        ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -143,13 +143,13 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec = T, Output = T>) {
    |                                            ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:4:40
+  --> $DIR/ice-generic-type-alias-105742.rs:5:40
    |
 LL | pub fn next<'a, T>(s: &'a mut dyn SVec) {
    |                                        ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -159,13 +159,13 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec = T, Output = T>) {
    |                                            +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -176,13 +176,13 @@ LL |     ::Item<'a>,
    |                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -193,13 +193,13 @@ LL |     ::Item,
    |                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -210,13 +210,13 @@ LL |     Output = ::Item<'a>,
    |                                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -227,13 +227,13 @@ LL |     Output = ::Item,
    |                                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -244,13 +244,13 @@ LL |     Output = ::Item<'a>> as SVec>::Item,
    |                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -261,13 +261,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -278,13 +278,13 @@ LL |     Output = ::Item> as SVec>::Item<'a>,
    |                                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -295,13 +295,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                                  +++
 
 error[E0038]: the trait `SVec` cannot be made into an object
-  --> $DIR/issue-105742.rs:4:31
+  --> $DIR/ice-generic-type-alias-105742.rs:5:31
    |
 LL | pub fn next<'a, T>(s: &'a mut dyn SVec) {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit 
-  --> $DIR/issue-105742.rs:14:17
+  --> $DIR/ice-generic-type-alias-105742.rs:15:17
    |
 LL |    pub trait SVec: Index<
    |  ____________----__^
@@ -329,13 +329,13 @@ LL | pub fn next<'a, T>(s: &'a mut impl SVec) {
    |                               ~~~~
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -346,13 +346,13 @@ LL |     ::Item<'a>,
    |                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -363,13 +363,13 @@ LL |     ::Item,
    |                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -380,13 +380,13 @@ LL |     Output = ::Item<'a>,
    |                                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -397,13 +397,13 @@ LL |     Output = ::Item,
    |                                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -414,13 +414,13 @@ LL |     Output = ::Item<'a>> as SVec>::Item,
    |                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -431,13 +431,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -448,13 +448,13 @@ LL |     Output = ::Item> as SVec>::Item<'a>,
    |                                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -465,13 +465,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -482,13 +482,13 @@ LL |     ::Item<'a>,
    |                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:15:21
+  --> $DIR/ice-generic-type-alias-105742.rs:16:21
    |
 LL |     ::Item,
    |                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -499,13 +499,13 @@ LL |     ::Item,
    |                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -516,13 +516,13 @@ LL |     Output = ::Item<'a>,
    |                                         ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:26:37
+  --> $DIR/ice-generic-type-alias-105742.rs:27:37
    |
 LL |     Output = ::Item,
    |                                     ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -533,13 +533,13 @@ LL |     Output = ::Item,
    |                                         +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -550,13 +550,13 @@ LL |     Output = ::Item<'a>> as SVec>::Item,
    |                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:30
+  --> $DIR/ice-generic-type-alias-105742.rs:38:30
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -567,13 +567,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -584,13 +584,13 @@ LL |     Output = ::Item> as SVec>::Item<'a>,
    |                                                  ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:37:46
+  --> $DIR/ice-generic-type-alias-105742.rs:38:46
    |
 LL |     Output = ::Item> as SVec>::Item,
    |                                              ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
@@ -601,13 +601,13 @@ LL |     Output = ::Item> as SVec>::Item,
    |                                                  +++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:61:38
+  --> $DIR/ice-generic-type-alias-105742.rs:62:38
    |
 LL |     fn len(&self) -> ::Item;
    |                                      ^^^^ expected 1 lifetime argument
    |
 note: associated type defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^ --
@@ -617,13 +617,13 @@ LL |     fn len(&self) -> ::Item<'_>;
    |                                          ++++
 
 error[E0107]: missing generics for associated type `SVec::Item`
-  --> $DIR/issue-105742.rs:61:38
+  --> $DIR/ice-generic-type-alias-105742.rs:62:38
    |
 LL |     fn len(&self) -> ::Item;
    |                                      ^^^^ expected 1 generic argument
    |
 note: associated type defined here, with 1 generic parameter: `T`
-  --> $DIR/issue-105742.rs:59:10
+  --> $DIR/ice-generic-type-alias-105742.rs:60:10
    |
 LL |     type Item<'a, T>;
    |          ^^^^     -
diff --git a/tests/rustdoc-ui/issues/issue-105737.rs b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-105737.rs
rename to tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.rs
diff --git a/tests/rustdoc-ui/issues/issue-105737.stderr b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.stderr
similarity index 87%
rename from tests/rustdoc-ui/issues/issue-105737.stderr
rename to tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.stderr
index 2c63c345e46a..49cbebc91d98 100644
--- a/tests/rustdoc-ui/issues/issue-105737.stderr
+++ b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.stderr
@@ -1,5 +1,5 @@
 error[E0747]: constant provided when a type was expected
-  --> $DIR/issue-105737.rs:1:10
+  --> $DIR/ice-impl-fn-generic-105737.rs:2:10
    |
 LL | impl Vec {}
    |          ^^^
diff --git a/tests/rustdoc-ui/issues/issue-101076.rs b/tests/rustdoc-ui/issues/ice-macro-hidden-exported-macro-defid-101076.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-101076.rs
rename to tests/rustdoc-ui/issues/ice-macro-hidden-exported-macro-defid-101076.rs
diff --git a/tests/rustdoc-ui/issues/issue-106226.rs b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-106226.rs
rename to tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.rs
diff --git a/tests/rustdoc-ui/issues/issue-106226.stderr b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.stderr
similarity index 84%
rename from tests/rustdoc-ui/issues/issue-106226.stderr
rename to tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.stderr
index 4d063b461883..e90809254504 100644
--- a/tests/rustdoc-ui/issues/issue-106226.stderr
+++ b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.stderr
@@ -1,5 +1,5 @@
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
-  --> $DIR/issue-106226.rs:2:11
+  --> $DIR/ice-placeholder-type-alias-106226.rs:2:11
    |
 LL | type F = [_; ()];
    |           ^ not allowed in type signatures
diff --git a/tests/rustdoc-ui/issues/issue-105334.rs b/tests/rustdoc-ui/issues/ice-raw-str-105334.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-105334.rs
rename to tests/rustdoc-ui/issues/ice-raw-str-105334.rs
diff --git a/tests/rustdoc-ui/issues/issue-105334.stderr b/tests/rustdoc-ui/issues/ice-raw-str-105334.stderr
similarity index 85%
rename from tests/rustdoc-ui/issues/issue-105334.stderr
rename to tests/rustdoc-ui/issues/ice-raw-str-105334.stderr
index d992b219b3bc..2096757fbb98 100644
--- a/tests/rustdoc-ui/issues/issue-105334.stderr
+++ b/tests/rustdoc-ui/issues/ice-raw-str-105334.stderr
@@ -1,5 +1,5 @@
 error[E0747]: constant provided when a type was expected
-  --> $DIR/issue-105334.rs:1:11
+  --> $DIR/ice-raw-str-105334.rs:2:11
    |
 LL | impl Vec< br##"*.."## > {}
    |           ^^^^^^^^^^^
diff --git a/tests/rustdoc-ui/issues/issue-102986.rs b/tests/rustdoc-ui/issues/ice-typeof-102986.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-102986.rs
rename to tests/rustdoc-ui/issues/ice-typeof-102986.rs
diff --git a/tests/rustdoc-ui/issues/issue-102986.stderr b/tests/rustdoc-ui/issues/ice-typeof-102986.stderr
similarity index 90%
rename from tests/rustdoc-ui/issues/issue-102986.stderr
rename to tests/rustdoc-ui/issues/ice-typeof-102986.stderr
index d91f93f394a5..20dbb2661bc2 100644
--- a/tests/rustdoc-ui/issues/issue-102986.stderr
+++ b/tests/rustdoc-ui/issues/ice-typeof-102986.stderr
@@ -1,5 +1,5 @@
 error[E0516]: `typeof` is a reserved keyword but unimplemented
-  --> $DIR/issue-102986.rs:2:9
+  --> $DIR/ice-typeof-102986.rs:3:9
    |
 LL |     y: (typeof("hey"),),
    |         ^^^^^^^^^^^^^ reserved keyword
diff --git a/tests/rustdoc-ui/issues/issue-103997.rs b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.rs
similarity index 100%
rename from tests/rustdoc-ui/issues/issue-103997.rs
rename to tests/rustdoc-ui/issues/ice-unresolved-self-103997.rs
diff --git a/tests/rustdoc-ui/issues/issue-103997.stderr b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.stderr
similarity index 83%
rename from tests/rustdoc-ui/issues/issue-103997.stderr
rename to tests/rustdoc-ui/issues/ice-unresolved-self-103997.stderr
index c06db91496f8..9cb64079c618 100644
--- a/tests/rustdoc-ui/issues/issue-103997.stderr
+++ b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.stderr
@@ -1,5 +1,5 @@
 warning: unresolved link to `Self::foo`
-  --> $DIR/issue-103997.rs:5:13
+  --> $DIR/ice-unresolved-self-103997.rs:6:13
    |
 LL | /// [`foo`](Self::foo)
    |             ^^^^^^^^^ no item named `Self` in scope

From 3fc7101b966822ffb3b77106a16af8f806fb2001 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Wed, 30 Oct 2024 12:03:08 +0100
Subject: [PATCH 113/197] Fix config guard lock for ratoml tests

---
 .../crates/load-cargo/src/lib.rs              |  4 +-
 .../crates/rust-analyzer/src/config.rs        | 25 ++++------
 .../crates/rust-analyzer/src/global_state.rs  | 10 ++--
 .../crates/rust-analyzer/src/reload.rs        |  4 +-
 .../rust-analyzer/tests/slow-tests/ratoml.rs  | 29 +++--------
 .../rust-analyzer/tests/slow-tests/support.rs | 48 +++++++++++++------
 6 files changed, 58 insertions(+), 62 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index ab8a780363d9..cf26845b1191 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -156,7 +156,7 @@ impl ProjectFolders {
     pub fn new(
         workspaces: &[ProjectWorkspace],
         global_excludes: &[AbsPathBuf],
-        user_config_dir_path: Option<&'static AbsPath>,
+        user_config_dir_path: Option<&AbsPath>,
     ) -> ProjectFolders {
         let mut res = ProjectFolders::default();
         let mut fsc = FileSetConfig::builder();
@@ -302,7 +302,7 @@ impl ProjectFolders {
                 p
             };
 
-            let file_set_roots: Vec = vec![VfsPath::from(ratoml_path.to_owned())];
+            let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())];
             let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]);
 
             res.watch.push(res.load.len());
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 921c9b991c5a..694748f82f33 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -3,11 +3,7 @@
 //! Of particular interest is the `feature_flags` hash map: while other fields
 //! configure the server itself, feature flags are passed into analysis, and
 //! tweak things like automatic insertion of `()` in completions.
-use std::{
-    env, fmt, iter,
-    ops::Not,
-    sync::{LazyLock, OnceLock},
-};
+use std::{env, fmt, iter, ops::Not, sync::OnceLock};
 
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
@@ -805,16 +801,13 @@ impl std::ops::Deref for Config {
 
 impl Config {
     /// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux.
-    pub fn user_config_dir_path() -> Option<&'static AbsPath> {
-        static USER_CONFIG_PATH: LazyLock> = LazyLock::new(|| {
-            let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
-                std::path::PathBuf::from(path)
-            } else {
-                dirs::config_dir()?.join("rust-analyzer")
-            };
-            Some(AbsPathBuf::assert_utf8(user_config_path))
-        });
-        USER_CONFIG_PATH.as_deref()
+    pub fn user_config_dir_path() -> Option {
+        let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") {
+            std::path::PathBuf::from(path)
+        } else {
+            dirs::config_dir()?.join("rust-analyzer")
+        };
+        Some(AbsPathBuf::assert_utf8(user_config_path))
     }
 
     pub fn same_source_root_parent_map(
@@ -1254,7 +1247,7 @@ pub struct NotificationsConfig {
     pub cargo_toml_not_found: bool,
 }
 
-#[derive(Deserialize, Serialize, Debug, Clone)]
+#[derive(Debug, Clone)]
 pub enum RustfmtConfig {
     Rustfmt { extra_args: Vec, enable_range_formatting: bool },
     CustomCommand { command: String, args: Vec },
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 8d5536e1b094..5f8357028403 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
@@ -392,13 +392,13 @@ impl GlobalState {
             || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
         {
             let config_change = {
-                let user_config_path = {
-                    let mut p = Config::user_config_dir_path().unwrap().to_path_buf();
+                let user_config_path = (|| {
+                    let mut p = Config::user_config_dir_path()?;
                     p.push("rust-analyzer.toml");
-                    p
-                };
+                    Some(p)
+                })();
 
-                let user_config_abs_path = Some(user_config_path.as_path());
+                let user_config_abs_path = user_config_path.as_deref();
 
                 let mut change = ConfigChange::default();
                 let db = self.analysis_host.raw_database();
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 b0b622035282..4549735fef84 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -590,7 +590,7 @@ impl GlobalState {
             }
 
             watchers.extend(
-                iter::once(Config::user_config_dir_path())
+                iter::once(Config::user_config_dir_path().as_deref())
                     .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref)))
                     .flatten()
                     .map(|glob_pattern| lsp_types::FileSystemWatcher {
@@ -616,7 +616,7 @@ impl GlobalState {
         let project_folders = ProjectFolders::new(
             &self.workspaces,
             &files_config.exclude,
-            Config::user_config_dir_path().to_owned(),
+            Config::user_config_dir_path().as_deref(),
         );
 
         if (self.proc_macro_clients.is_empty() || !same_workspaces)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index 623a9f76d14e..5dfaf0d36503 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -30,23 +30,6 @@ impl RatomlTest {
         fixtures: Vec<&str>,
         roots: Vec<&str>,
         client_config: Option,
-    ) -> Self {
-        RatomlTest::new_with_lock(fixtures, roots, client_config, false)
-    }
-
-    fn new_locked(
-        fixtures: Vec<&str>,
-        roots: Vec<&str>,
-        client_config: Option,
-    ) -> Self {
-        RatomlTest::new_with_lock(fixtures, roots, client_config, true)
-    }
-
-    fn new_with_lock(
-        fixtures: Vec<&str>,
-        roots: Vec<&str>,
-        client_config: Option,
-        prelock: bool,
     ) -> Self {
         let tmp_dir = TestDir::new();
         let tmp_path = tmp_dir.path().to_owned();
@@ -63,7 +46,7 @@ impl RatomlTest {
             project = project.with_config(client_config);
         }
 
-        let server = project.server_with_lock(prelock).wait_until_workspace_is_loaded();
+        let server = project.server_with_lock(true).wait_until_workspace_is_loaded();
 
         let mut case = Self { urls: vec![], server, tmp_path };
         let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::>();
@@ -89,7 +72,7 @@ impl RatomlTest {
         let mut spl = spl.into_iter();
         if let Some(first) = spl.next() {
             if first == "$$CONFIG_DIR$$" {
-                path = Config::user_config_dir_path().unwrap().to_path_buf().into();
+                path = Config::user_config_dir_path().unwrap().into();
             } else {
                 path = path.join(first);
             }
@@ -307,7 +290,7 @@ fn ratoml_user_config_detected() {
         return;
     }
 
-    let server = RatomlTest::new_locked(
+    let server = RatomlTest::new(
         vec![
             r#"
 //- /$$CONFIG_DIR$$/rust-analyzer.toml
@@ -343,7 +326,7 @@ fn ratoml_create_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -382,7 +365,7 @@ fn ratoml_modify_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
@@ -423,7 +406,7 @@ fn ratoml_delete_user_config() {
         return;
     }
 
-    let mut server = RatomlTest::new_locked(
+    let mut server = RatomlTest::new(
         vec![
             r#"
 //- /p1/Cargo.toml
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 86137e3f2ccb..5a88a5515c7f 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
@@ -1,7 +1,7 @@
 use std::{
     cell::{Cell, RefCell},
     env, fs,
-    sync::Once,
+    sync::{Once, OnceLock},
     time::Duration,
 };
 
@@ -140,13 +140,36 @@ impl Project<'_> {
     /// if there is a path to config dir in the test fixture. However, in certain cases we create a
     /// file in the config dir after server is run, something where our naive approach comes short.
     /// Using a `prelock` allows us to force a lock when we know we need it.
-    pub(crate) fn server_with_lock(self, prelock: bool) -> Server {
-        static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
+    pub(crate) fn server_with_lock(self, config_lock: bool) -> Server {
+        static CONFIG_DIR_LOCK: OnceLock<(Utf8PathBuf, Mutex<()>)> = OnceLock::new();
 
-        let mut config_dir_guard = if prelock {
-            let v = Some(CONFIG_DIR_LOCK.lock());
-            env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
-            v
+        let config_dir_guard = if config_lock {
+            Some({
+                let (path, mutex) = CONFIG_DIR_LOCK.get_or_init(|| {
+                    let value = TestDir::new().keep().path().to_owned();
+                    env::set_var("__TEST_RA_USER_CONFIG_DIR", &value);
+                    (value, Mutex::new(()))
+                });
+                #[allow(dyn_drop)]
+                (mutex.lock(), {
+                    Box::new({
+                        struct Dropper(Utf8PathBuf);
+                        impl Drop for Dropper {
+                            fn drop(&mut self) {
+                                for entry in fs::read_dir(&self.0).unwrap() {
+                                    let path = entry.unwrap().path();
+                                    if path.is_file() {
+                                        fs::remove_file(path).unwrap();
+                                    } else if path.is_dir() {
+                                        fs::remove_dir_all(path).unwrap();
+                                    }
+                                }
+                            }
+                        }
+                        Dropper(path.clone())
+                    }) as Box
+                })
+            })
         } else {
             None
         };
@@ -185,11 +208,6 @@ impl Project<'_> {
 
         for entry in fixture {
             if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") {
-                if config_dir_guard.is_none() {
-                    config_dir_guard = Some(CONFIG_DIR_LOCK.lock());
-                    env::set_var("__TEST_RA_USER_CONFIG_DIR", TestDir::new().path());
-                }
-
                 let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]);
                 fs::create_dir_all(path.parent().unwrap()).unwrap();
                 fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
@@ -293,12 +311,14 @@ pub(crate) struct Server {
     client: Connection,
     /// XXX: remove the tempdir last
     dir: TestDir,
-    _config_dir_guard: Option>,
+    #[allow(dyn_drop)]
+    _config_dir_guard: Option<(MutexGuard<'static, ()>, Box)>,
 }
 
 impl Server {
+    #[allow(dyn_drop)]
     fn new(
-        config_dir_guard: Option>,
+        config_dir_guard: Option<(MutexGuard<'static, ()>, Box)>,
         dir: TestDir,
         config: Config,
     ) -> Server {

From 4148b5345d1c33d801108ea9cc098f7544646ba3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= 
Date: Mon, 9 Dec 2024 11:17:17 +0200
Subject: [PATCH 114/197] Remove unstable attributes in minicore

---
 src/tools/rust-analyzer/crates/test-utils/src/minicore.rs | 4 ----
 1 file changed, 4 deletions(-)

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 f5c8466cb9f0..99dfabe174ee 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -728,7 +728,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl AsyncFnMut for &F
             where
                 F: AsyncFn,
@@ -746,7 +745,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a F
             where
                 F: AsyncFn,
@@ -759,7 +757,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl AsyncFnMut for &mut F
             where
                 F: AsyncFnMut,
@@ -777,7 +774,6 @@ pub mod ops {
                 }
             }
 
-            #[unstable(feature = "async_fn_traits", issue = "none")]
             impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce for &'a mut F
             where
                 F: AsyncFnMut,

From 1fcbb1e338f50e752a64c561838aaa7eb111e039 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <39484203+jieyouxu@users.noreply.github.com>
Date: Mon, 9 Dec 2024 17:31:16 +0800
Subject: [PATCH 115/197] Revert #131669 due to ICEs

Revert  due to ICE
reports:

-  (real-world)
-  (fuzzing)

The changes can be re-landed with those cases addressed.

This reverts commit 703bb982303ecab02fec593899639b4c3faecddd, reversing
changes made to f415c07494b98e4559e4b13a9c5f867b0e6b2444.
---
 compiler/rustc_lint/messages.ftl              |  13 +-
 compiler/rustc_lint/src/lints.rs              |  45 +--
 compiler/rustc_lint/src/types.rs              | 372 +++---------------
 ...extern-C-non-FFI-safe-arg-ice-52334.stderr |   2 -
 .../extern/extern-C-str-arg-ice-80125.stderr  |   2 -
 tests/ui/lint/extern-C-fnptr-lints-slices.rs  |   2 +-
 .../lint/extern-C-fnptr-lints-slices.stderr   |   7 +-
 tests/ui/lint/lint-ctypes-73249-2.stderr      |   1 -
 tests/ui/lint/lint-ctypes-94223.stderr        |  26 +-
 tests/ui/lint/lint-ctypes-cstr.rs             |   4 +-
 tests/ui/lint/lint-ctypes-cstr.stderr         |  11 +-
 tests/ui/lint/lint-ctypes-fn.rs               |   6 +-
 tests/ui/lint/lint-ctypes-fn.stderr           |  22 +-
 tests/ui/lint/lint-ctypes.rs                  |  35 +-
 tests/ui/lint/lint-ctypes.stderr              | 123 +++---
 15 files changed, 181 insertions(+), 490 deletions(-)

diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 422629cd11d0..49e6b763590b 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -359,6 +359,7 @@ lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stab
 lint_improper_ctypes_array_help = consider passing a pointer to the array
 
 lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
+lint_improper_ctypes_box = box cannot be represented as a single pointer
 
 lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 
@@ -376,9 +377,7 @@ lint_improper_ctypes_enum_repr_help =
 lint_improper_ctypes_enum_repr_reason = enum has no representation hint
 lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
 
-lint_improper_ctypes_fnptr_indirect_reason = the function pointer to `{$ty}` is FFI-unsafe due to `{$inner_ty}`
 lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
-
 lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
 lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
 
@@ -389,11 +388,7 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent
 lint_improper_ctypes_pat_help = consider using the base type instead
 
 lint_improper_ctypes_pat_reason = pattern types have no C equivalent
-
-lint_improper_ctypes_sized_ptr_to_unsafe_type =
-    this reference (`{$ty}`) is ABI-compatible with a C pointer, but `{$inner_ty}` itself does not have a C layout
-
-lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead
+lint_improper_ctypes_slice_help = consider using a raw pointer instead
 
 lint_improper_ctypes_slice_reason = slices have no C equivalent
 lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
@@ -419,10 +414,6 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
 lint_improper_ctypes_union_layout_reason = this union has unspecified layout
 lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
 
-lint_improper_ctypes_unsized_box = this box for an unsized type contains metadata, which makes it incompatible with a C pointer
-lint_improper_ctypes_unsized_ptr = this pointer to an unsized type contains metadata, which makes it incompatible with a C pointer
-lint_improper_ctypes_unsized_ref = this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
-
 lint_incomplete_include =
     include macro expected single expression in source
 
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 9fa263799ebf..20822f23bf15 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1851,44 +1851,13 @@ pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> {
     pub right: Span,
 }
 
-pub(crate) struct ImproperCTypesLayer<'a> {
-    pub ty: Ty<'a>,
-    pub inner_ty: Option>,
-    pub note: DiagMessage,
-    pub span_note: Option,
-    pub help: Option,
-}
-
-impl<'a> Subdiagnostic for ImproperCTypesLayer<'a> {
-    fn add_to_diag_with>(
-        self,
-        diag: &mut Diag<'_, G>,
-        f: &F,
-    ) {
-        diag.arg("ty", self.ty);
-        if let Some(ty) = self.inner_ty {
-            diag.arg("inner_ty", ty);
-        }
-
-        if let Some(help) = self.help {
-            let msg = f(diag, help.into());
-            diag.help(msg);
-        }
-
-        let msg = f(diag, self.note.into());
-        diag.note(msg);
-        if let Some(note) = self.span_note {
-            let msg = f(diag, fluent::lint_note.into());
-            diag.span_note(note, msg);
-        };
-    }
-}
-
 pub(crate) struct ImproperCTypes<'a> {
     pub ty: Ty<'a>,
     pub desc: &'a str,
     pub label: Span,
-    pub reasons: Vec>,
+    pub help: Option,
+    pub note: DiagMessage,
+    pub span_note: Option,
 }
 
 // Used because of the complexity of Option, DiagMessage, and Option
@@ -1898,8 +1867,12 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> {
         diag.arg("ty", self.ty);
         diag.arg("desc", self.desc);
         diag.span_label(self.label, fluent::lint_label);
-        for reason in self.reasons.into_iter() {
-            diag.subdiagnostic(reason);
+        if let Some(help) = self.help {
+            diag.help(help);
+        }
+        diag.note(self.note);
+        if let Some(note) = self.span_note {
+            diag.span_note(note, fluent::lint_note);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 90d44371ab5a..33650be056dd 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -22,10 +22,10 @@ mod improper_ctypes;
 use crate::lints::{
     AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
     AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
-    AtomicOrderingStore, ImproperCTypes, ImproperCTypesLayer, InvalidAtomicOrderingDiag,
-    InvalidNanComparisons, InvalidNanComparisonsSuggestion,
-    UnpredictableFunctionPointerComparisons, UnpredictableFunctionPointerComparisonsSuggestion,
-    UnusedComparisons, VariantSizeDifferencesDiag,
+    AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
+    InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
+    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
+    VariantSizeDifferencesDiag,
 };
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
 
@@ -727,109 +727,7 @@ struct CTypesVisitorState<'tcx> {
 enum FfiResult<'tcx> {
     FfiSafe,
     FfiPhantom(Ty<'tcx>),
-    FfiUnsafe {
-        ty: Ty<'tcx>,
-        reason: DiagMessage,
-        help: Option,
-    },
-    FfiUnsafeWrapper {
-        ty: Ty<'tcx>,
-        reason: DiagMessage,
-        help: Option,
-        wrapped: Box>,
-    },
-}
-
-/// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it
-#[derive(Clone, Copy)]
-enum TypeSizedness {
-    /// type of definite size (pointers are C-compatible)
-    Definite,
-    /// unsized type because it includes an opaque/foreign type (pointers are C-compatible)
-    UnsizedWithExternType,
-    /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible)
-    UnsizedWithMetadata,
-}
-
-/// Is this type unsized because it contains (or is) a foreign type?
-/// (Returns Err if the type happens to be sized after all)
-fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> TypeSizedness {
-    let tcx = cx.tcx;
-
-    if ty.is_sized(tcx, cx.typing_env()) {
-        TypeSizedness::Definite
-    } else {
-        match ty.kind() {
-            ty::Slice(_) => TypeSizedness::UnsizedWithMetadata,
-            ty::Str => TypeSizedness::UnsizedWithMetadata,
-            ty::Dynamic(..) => TypeSizedness::UnsizedWithMetadata,
-            ty::Foreign(..) => TypeSizedness::UnsizedWithExternType,
-            // While opaque types are checked for earlier, if a projection in a struct field
-            // normalizes to an opaque type, then it will reach this branch.
-            ty::Alias(ty::Opaque, ..) => todo!("We... don't know enough about this type yet?"),
-            ty::Adt(def, args) => {
-                // for now assume: boxes and phantoms don't mess with this
-                match def.adt_kind() {
-                    AdtKind::Union | AdtKind::Enum => {
-                        bug!("unions and enums are necessarily sized")
-                    }
-                    AdtKind::Struct => {
-                        if let Some(sym::cstring_type | sym::cstr_type) =
-                            tcx.get_diagnostic_name(def.did())
-                        {
-                            return TypeSizedness::UnsizedWithMetadata;
-                        }
-                        // FIXME: how do we deal with non-exhaustive unsized structs/unions?
-
-                        if def.non_enum_variant().fields.is_empty() {
-                            bug!("an empty struct is necessarily sized");
-                        }
-
-                        let variant = def.non_enum_variant();
-
-                        // only the last field may be unsized
-                        let n_fields = variant.fields.len();
-                        let last_field = &variant.fields[(n_fields - 1).into()];
-                        let field_ty = last_field.ty(cx.tcx, args);
-                        let field_ty = cx
-                            .tcx
-                            .try_normalize_erasing_regions(cx.typing_env(), field_ty)
-                            .unwrap_or(field_ty);
-                        match get_type_sizedness(cx, field_ty) {
-                            s @ (TypeSizedness::UnsizedWithMetadata
-                            | TypeSizedness::UnsizedWithExternType) => s,
-                            TypeSizedness::Definite => {
-                                bug!("failed to find the reason why struct `{:?}` is unsized", ty)
-                            }
-                        }
-                    }
-                }
-            }
-            ty::Tuple(tuple) => {
-                // only the last field may be unsized
-                let n_fields = tuple.len();
-                let field_ty: Ty<'tcx> = tuple[n_fields - 1];
-                //let field_ty = last_field.ty(cx.tcx, args);
-                let field_ty = cx
-                    .tcx
-                    .try_normalize_erasing_regions(cx.typing_env(), field_ty)
-                    .unwrap_or(field_ty);
-                match get_type_sizedness(cx, field_ty) {
-                    s @ (TypeSizedness::UnsizedWithMetadata
-                    | TypeSizedness::UnsizedWithExternType) => s,
-                    TypeSizedness::Definite => {
-                        bug!("failed to find the reason why tuple `{:?}` is unsized", ty)
-                    }
-                }
-            }
-            ty => {
-                bug!(
-                    "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}`",
-                    ty
-                )
-            }
-        }
-    }
+    FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option },
 }
 
 pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
@@ -866,7 +764,7 @@ fn ty_is_known_nonnull<'tcx>(
     match ty.kind() {
         ty::FnPtr(..) => true,
         ty::Ref(..) => true,
-        ty::Adt(def, _) if def.is_box() => true,
+        ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
         ty::Adt(def, args) if def.repr().transparent() && !def.is_union() => {
             let marked_non_null = nonnull_optimization_guaranteed(tcx, *def);
 
@@ -1035,13 +933,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the type is array and emit an unsafe type lint.
     fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         if let ty::Array(..) = ty.kind() {
-            self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
+            self.emit_ffi_unsafe_type_lint(
                 ty,
-                note: fluent::lint_improper_ctypes_array_reason,
-                help: Some(fluent::lint_improper_ctypes_array_help),
-                inner_ty: None,
-                span_note: None,
-            }]);
+                sp,
+                fluent::lint_improper_ctypes_array_reason,
+                Some(fluent::lint_improper_ctypes_array_help),
+            );
             true
         } else {
             false
@@ -1098,9 +995,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
                 FfiSafe => false,
                 // `()` fields are FFI-safe!
-                FfiUnsafe { ty, .. } | FfiUnsafeWrapper { ty, .. } if ty.is_unit() => false,
+                FfiUnsafe { ty, .. } if ty.is_unit() => false,
                 FfiPhantom(..) => true,
-                r @ (FfiUnsafe { .. } | FfiUnsafeWrapper { .. }) => return r,
+                r @ FfiUnsafe { .. } => return r,
             }
         }
 
@@ -1134,47 +1031,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
         match *ty.kind() {
             ty::Adt(def, args) => {
-                if let Some(inner_ty) = ty.boxed_ty() {
-                    if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite =
-                        get_type_sizedness(self.cx, inner_ty)
-                    {
-                        // discussion on declaration vs definition:
-                        // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm
-                        // of this `match *ty.kind()` block
-                        if matches!(self.mode, CItemKind::Definition) {
-                            return FfiSafe;
-                        } else {
-                            let inner_res = self.check_type_for_ffi(acc, inner_ty);
-                            return match inner_res {
-                                FfiUnsafe { .. } | FfiUnsafeWrapper { .. } => FfiUnsafeWrapper {
-                                    ty,
-                                    reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type,
-                                    wrapped: Box::new(inner_res),
-                                    help: None,
-                                },
-                                _ => inner_res,
-                            };
-                        }
+                if let Some(boxed) = ty.boxed_ty()
+                    && matches!(self.mode, CItemKind::Definition)
+                {
+                    if boxed.is_sized(tcx, self.cx.typing_env()) {
+                        return FfiSafe;
                     } else {
-                        let help = match inner_ty.kind() {
-                            ty::Str => Some(fluent::lint_improper_ctypes_str_help),
-                            ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help),
-                            ty::Adt(def, _)
-                                if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)
-                                    && matches!(
-                                        tcx.get_diagnostic_name(def.did()),
-                                        Some(sym::cstring_type | sym::cstr_type)
-                                    )
-                                    && !acc.base_ty.is_mutable_ptr() =>
-                            {
-                                Some(fluent::lint_improper_ctypes_cstr_help)
-                            }
-                            _ => None,
-                        };
                         return FfiUnsafe {
                             ty,
-                            reason: fluent::lint_improper_ctypes_unsized_box,
-                            help,
+                            reason: fluent::lint_improper_ctypes_box,
+                            help: None,
                         };
                     }
                 }
@@ -1330,6 +1196,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 help: Some(fluent::lint_improper_ctypes_tuple_help),
             },
 
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
+                if {
+                    matches!(self.mode, CItemKind::Definition)
+                        && ty.is_sized(self.cx.tcx, self.cx.typing_env())
+                } =>
+            {
+                FfiSafe
+            }
+
             ty::RawPtr(ty, _)
                 if match ty.kind() {
                     ty::Tuple(tuple) => tuple.is_empty(),
@@ -1339,70 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
-            ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => {
-                if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite =
-                    get_type_sizedness(self.cx, inner_ty)
-                {
-                    // there's a nuance on what this lint should do for
-                    // function definitions (`extern "C" fn fn_name(...) {...}`)
-                    // versus declarations (`unsafe extern "C" {fn fn_name(...);}`).
-                    // This is touched upon in https://github.com/rust-lang/rust/issues/66220
-                    // and https://github.com/rust-lang/rust/pull/72700
-                    //
-                    // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer
-                    // (which has a stable layout) but points to FFI-unsafe type, is it safe?
-                    // On one hand, the function's ABI will match that of a similar C-declared function API,
-                    // on the other, dereferencing the pointer on the other side of the FFI boundary will be painful.
-                    // In this code, the opinion on is split between function declarations and function definitions,
-                    // with the idea that at least one side of the FFI boundary needs to treat the pointee as an opaque type.
-                    // For declarations, we see this as unsafe, but for definitions, we see this as safe.
-                    //
-                    // For extern function declarations, the actual definition of the function is written somewhere else,
-                    // meaning the declaration is free to express this opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void (opaque callee-side)
-                    // For extern function definitions, however, in the case where the type is opaque caller-side, it is not opaque callee-side,
-                    // and having the full type information is necessary to compile the function.
-                    if matches!(self.mode, CItemKind::Definition) {
-                        return FfiSafe;
-                    } else if matches!(ty.kind(), ty::RawPtr(..))
-                        && matches!(inner_ty.kind(), ty::Tuple(tuple) if tuple.is_empty())
-                    {
-                        FfiSafe
-                    } else {
-                        let inner_res = self.check_type_for_ffi(acc, inner_ty);
-                        return match inner_res {
-                            FfiSafe => inner_res,
-                            _ => FfiUnsafeWrapper {
-                                ty,
-                                reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type,
-                                wrapped: Box::new(inner_res),
-                                help: None,
-                            },
-                        };
-                    }
-                } else {
-                    let help = match inner_ty.kind() {
-                        ty::Str => Some(fluent::lint_improper_ctypes_str_help),
-                        ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help),
-                        ty::Adt(def, _)
-                            if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union)
-                                && matches!(
-                                    tcx.get_diagnostic_name(def.did()),
-                                    Some(sym::cstring_type | sym::cstr_type)
-                                )
-                                && !acc.base_ty.is_mutable_ptr() =>
-                        {
-                            Some(fluent::lint_improper_ctypes_cstr_help)
-                        }
-                        _ => None,
-                    };
-                    let reason = match ty.kind() {
-                        ty::RawPtr(..) => fluent::lint_improper_ctypes_unsized_ptr,
-                        ty::Ref(..) => fluent::lint_improper_ctypes_unsized_ref,
-                        _ => unreachable!(),
-                    };
-                    FfiUnsafe { ty, reason, help }
-                }
-            }
+            ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
 
             ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
 
@@ -1420,14 +1232,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 for arg in sig.inputs() {
                     match self.check_type_for_ffi(acc, *arg) {
                         FfiSafe => {}
-                        r => {
-                            return FfiUnsafeWrapper {
-                                ty,
-                                reason: fluent::lint_improper_ctypes_fnptr_indirect_reason,
-                                help: None,
-                                wrapped: Box::new(r),
-                            };
-                        }
+                        r => return r,
                     }
                 }
 
@@ -1436,15 +1241,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     return FfiSafe;
                 }
 
-                match self.check_type_for_ffi(acc, ret_ty) {
-                    r @ (FfiSafe | FfiPhantom(_)) => r,
-                    r => FfiUnsafeWrapper {
-                        ty: ty.clone(),
-                        reason: fluent::lint_improper_ctypes_fnptr_indirect_reason,
-                        help: None,
-                        wrapped: Box::new(r),
-                    },
-                }
+                self.check_type_for_ffi(acc, ret_ty)
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1481,7 +1278,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         &mut self,
         ty: Ty<'tcx>,
         sp: Span,
-        mut reasons: Vec>,
+        note: DiagMessage,
+        help: Option,
     ) {
         let lint = match self.mode {
             CItemKind::Declaration => IMPROPER_CTYPES,
@@ -1491,17 +1289,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             CItemKind::Declaration => "block",
             CItemKind::Definition => "fn",
         };
-        for reason in reasons.iter_mut() {
-            reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
-                && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
-            {
-                Some(sp)
-            } else {
-                None
-            };
-        }
-
-        self.cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, reasons });
+        let span_note = if let ty::Adt(def, _) = ty.kind()
+            && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
+        {
+            Some(sp)
+        } else {
+            None
+        };
+        self.cx.emit_span_lint(lint, sp, ImproperCTypes {
+            ty,
+            desc,
+            label: sp,
+            help,
+            note,
+            span_note,
+        });
     }
 
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
@@ -1530,13 +1332,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             .visit_with(&mut ProhibitOpaqueTypes)
             .break_value()
         {
-            self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
-                ty,
-                note: fluent::lint_improper_ctypes_opaque,
-                span_note: Some(sp),
-                help: None,
-                inner_ty: None,
-            }]);
+            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
             true
         } else {
             false
@@ -1575,71 +1371,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         match self.check_type_for_ffi(&mut acc, ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
-                self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
+                self.emit_ffi_unsafe_type_lint(
                     ty,
-                    note: fluent::lint_improper_ctypes_only_phantomdata,
-                    span_note: None, // filled later
-                    help: None,
-                    inner_ty: None,
-                }]);
+                    sp,
+                    fluent::lint_improper_ctypes_only_phantomdata,
+                    None,
+                );
             }
             FfiResult::FfiUnsafe { ty, reason, help } => {
-                self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
-                    ty,
-                    help,
-                    note: reason,
-                    span_note: None, // filled later
-                    inner_ty: None,
-                }]);
-            }
-            ffir @ FfiResult::FfiUnsafeWrapper { .. } => {
-                let mut ffiresult_recursor = ControlFlow::Continue(&ffir);
-                let mut cimproper_layers: Vec> = vec![];
-
-                // this whole while block converts the arbitrarily-deep
-                // FfiResult stack to an ImproperCTypesLayer Vec
-                while let ControlFlow::Continue(ref ffir_rec) = ffiresult_recursor {
-                    match ffir_rec {
-                        FfiResult::FfiPhantom(ty) => {
-                            if let Some(layer) = cimproper_layers.last_mut() {
-                                layer.inner_ty = Some(ty.clone());
-                            }
-                            cimproper_layers.push(ImproperCTypesLayer {
-                                ty: ty.clone(),
-                                inner_ty: None,
-                                help: None,
-                                note: fluent::lint_improper_ctypes_only_phantomdata,
-                                span_note: None, // filled later
-                            });
-                            ffiresult_recursor = ControlFlow::Break(());
-                        }
-                        FfiResult::FfiUnsafe { ty, reason, help }
-                        | FfiResult::FfiUnsafeWrapper { ty, reason, help, .. } => {
-                            if let Some(layer) = cimproper_layers.last_mut() {
-                                layer.inner_ty = Some(ty.clone());
-                            }
-                            cimproper_layers.push(ImproperCTypesLayer {
-                                ty: ty.clone(),
-                                inner_ty: None,
-                                help: help.clone(),
-                                note: reason.clone(),
-                                span_note: None, // filled later
-                            });
-
-                            if let FfiResult::FfiUnsafeWrapper { wrapped, .. } = ffir_rec {
-                                ffiresult_recursor = ControlFlow::Continue(wrapped.as_ref());
-                            } else {
-                                ffiresult_recursor = ControlFlow::Break(());
-                            }
-                        }
-                        FfiResult::FfiSafe => {
-                            bug!("malformed FfiResult stack: it should be unsafe all the way down")
-                        }
-                    };
-                }
-                // should always have at least one type
-                let last_ty = cimproper_layers.last().unwrap().ty.clone();
-                self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers);
+                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
         }
     }
diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
index b5c718ec3814..044c1ae2dd42 100644
--- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
+++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr
@@ -4,7 +4,6 @@ warning: `extern` fn uses type `CStr`, which is not FFI-safe
 LL | type Foo = extern "C" fn(::std::ffi::CStr);
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr`
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes_definitions)]` on by default
@@ -15,7 +14,6 @@ warning: `extern` block uses type `CStr`, which is not FFI-safe
 LL |     fn meh(blah: Foo);
    |                  ^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr`
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
    = note: `#[warn(improper_ctypes)]` on by default
diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
index f2ee21c31665..ebd6cec6ecd3 100644
--- a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
+++ b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr
@@ -4,7 +4,6 @@ warning: `extern` fn uses type `str`, which is not FFI-safe
 LL | type ExternCallback = extern "C" fn(*const u8, u32, str);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str`
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
    = note: `#[warn(improper_ctypes_definitions)]` on by default
@@ -15,7 +14,6 @@ warning: `extern` fn uses type `str`, which is not FFI-safe
 LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct {
    |                                            ^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str`
    = help: consider using `*const u8` and a length instead
    = note: string slices have no C equivalent
 
diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.rs b/tests/ui/lint/extern-C-fnptr-lints-slices.rs
index 4e3832ab1b67..0c35eb37a489 100644
--- a/tests/ui/lint/extern-C-fnptr-lints-slices.rs
+++ b/tests/ui/lint/extern-C-fnptr-lints-slices.rs
@@ -3,7 +3,7 @@
 // It's an improper ctype (a slice) arg in an extern "C" fnptr.
 
 pub type F = extern "C" fn(&[u8]);
-//~^ ERROR: `extern` fn uses type `&[u8]`, which is not FFI-safe
+//~^ ERROR: `extern` fn uses type `[u8]`, which is not FFI-safe
 
 
 fn main() {}
diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
index c0923dd96c8c..d13f93ca96f2 100644
--- a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
+++ b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr
@@ -1,12 +1,11 @@
-error: `extern` fn uses type `&[u8]`, which is not FFI-safe
+error: `extern` fn uses type `[u8]`, which is not FFI-safe
   --> $DIR/extern-C-fnptr-lints-slices.rs:5:14
    |
 LL | pub type F = extern "C" fn(&[u8]);
    |              ^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
 note: the lint level is defined here
   --> $DIR/extern-C-fnptr-lints-slices.rs:1:8
    |
diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/lint-ctypes-73249-2.stderr
index f035cdb213ef..ef30a406969d 100644
--- a/tests/ui/lint/lint-ctypes-73249-2.stderr
+++ b/tests/ui/lint/lint-ctypes-73249-2.stderr
@@ -4,7 +4,6 @@ error: `extern` block uses type `Qux`, which is not FFI-safe
 LL |     fn lint_me() -> A<()>;
    |                     ^^^^^ not FFI-safe
    |
-   = note: this reference (`&Qux`) is ABI-compatible with a C pointer, but `Qux` itself does not have a C layout
    = note: opaque types have no C equivalent
 note: the lint level is defined here
   --> $DIR/lint-ctypes-73249-2.rs:2:9
diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr
index 4bebca69b7f3..bd127cf60044 100644
--- a/tests/ui/lint/lint-ctypes-94223.stderr
+++ b/tests/ui/lint/lint-ctypes-94223.stderr
@@ -4,8 +4,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad(f: extern "C" fn([u8])) {}
    |               ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 note: the lint level is defined here
   --> $DIR/lint-ctypes-94223.rs:2:9
@@ -19,8 +18,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad_twice(f: Result) {}
    |                            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -29,8 +27,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | pub fn bad_twice(f: Result) {}
    |                                                 ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -39,8 +36,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | struct BadStruct(extern "C" fn([u8]));
    |                  ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -49,8 +45,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -59,8 +54,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL |     A(extern "C" fn([u8])),
    |       ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `[u8]`, which is not FFI-safe
@@ -69,8 +63,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe
 LL | type Foo = extern "C" fn([u8]);
    |            ^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]`
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
+   = help: consider using a raw pointer instead
    = note: slices have no C equivalent
 
 error: `extern` fn uses type `Option<&::FooType>`, which is not FFI-safe
@@ -79,7 +72,6 @@ error: `extern` fn uses type `Option<&::FooType>`, which is not F
 LL | pub type Foo2 = extern "C" fn(Option<&::FooType>);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `for<'a> extern "C" fn(Option<&'a ::FooType>)` is FFI-unsafe due to `Option<&::FooType>`
    = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
    = note: enum has no representation hint
 
@@ -89,7 +81,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -104,7 +95,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD_TWICE: Result = Ok(f);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -119,7 +109,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub static BAD_TWICE: Result = Ok(f);
    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
@@ -134,7 +123,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
 LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe`
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs
index c4de5a44a962..b04decd0bcac 100644
--- a/tests/ui/lint/lint-ctypes-cstr.rs
+++ b/tests/ui/lint/lint-ctypes-cstr.rs
@@ -8,7 +8,7 @@ extern "C" {
     //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
     //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
     fn take_cstr_ref(s: &CStr);
-    //~^ ERROR `extern` block uses type `&CStr`, which is not FFI-safe
+    //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
     //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
     fn take_cstring(s: CString);
     //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
@@ -27,7 +27,7 @@ extern "C" {
 }
 
 extern "C" fn rust_take_cstr_ref(s: &CStr) {}
-//~^ ERROR `extern` fn uses type `&CStr`, which is not FFI-safe
+//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe
 //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
 extern "C" fn rust_take_cstring(s: CString) {}
 //~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe
diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr
index da15b748f211..8957758d5773 100644
--- a/tests/ui/lint/lint-ctypes-cstr.stderr
+++ b/tests/ui/lint/lint-ctypes-cstr.stderr
@@ -12,14 +12,14 @@ note: the lint level is defined here
 LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^
 
-error: `extern` block uses type `&CStr`, which is not FFI-safe
+error: `extern` block uses type `CStr`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:10:25
    |
 LL |     fn take_cstr_ref(s: &CStr);
    |                         ^^^^^ not FFI-safe
    |
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: `CStr`/`CString` do not have a guaranteed layout
 
 error: `extern` block uses type `CString`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:13:24
@@ -36,7 +36,6 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn take_cstring_ref(s: &CString);
    |                            ^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`&CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
    = note: `CStr`/`CString` do not have a guaranteed layout
 
@@ -46,7 +45,6 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn no_special_help_for_mut_cstring(s: *mut CString);
    |                                           ^^^^^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`*mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
@@ -56,18 +54,17 @@ error: `extern` block uses type `CString`, which is not FFI-safe
 LL |     fn no_special_help_for_mut_cstring_ref(s: &mut CString);
    |                                               ^^^^^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`&mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 
-error: `extern` fn uses type `&CStr`, which is not FFI-safe
+error: `extern` fn uses type `CStr`, which is not FFI-safe
   --> $DIR/lint-ctypes-cstr.rs:29:37
    |
 LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
    |                                     ^^^^^ not FFI-safe
    |
    = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: `CStr`/`CString` do not have a guaranteed layout
 note: the lint level is defined here
   --> $DIR/lint-ctypes-cstr.rs:2:26
    |
diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs
index e16ff9573fd1..73820c86d1a0 100644
--- a/tests/ui/lint/lint-ctypes-fn.rs
+++ b/tests/ui/lint/lint-ctypes-fn.rs
@@ -68,10 +68,10 @@ pub extern "C" fn ptr_unit(p: *const ()) { }
 pub extern "C" fn ptr_tuple(p: *const ((),)) { }
 
 pub extern "C" fn slice_type(p: &[u32]) { }
-//~^ ERROR: uses type `&[u32]`
+//~^ ERROR: uses type `[u32]`
 
 pub extern "C" fn str_type(p: &str) { }
-//~^ ERROR: uses type `&str`
+//~^ ERROR: uses type `str`
 
 pub extern "C" fn box_type(p: Box) { }
 
@@ -124,7 +124,7 @@ pub extern "C" fn transparent_i128(p: TransparentI128) { }
 //~^ ERROR: uses type `i128`
 
 pub extern "C" fn transparent_str(p: TransparentStr) { }
-//~^ ERROR: uses type `&str`
+//~^ ERROR: uses type `str`
 
 pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
 
diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr
index c86c02c80064..a62533a4be17 100644
--- a/tests/ui/lint/lint-ctypes-fn.stderr
+++ b/tests/ui/lint/lint-ctypes-fn.stderr
@@ -1,25 +1,25 @@
-error: `extern` fn uses type `&[u32]`, which is not FFI-safe
+error: `extern` fn uses type `[u32]`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:70:33
    |
 LL | pub extern "C" fn slice_type(p: &[u32]) { }
    |                                 ^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
 note: the lint level is defined here
   --> $DIR/lint-ctypes-fn.rs:2:9
    |
 LL | #![deny(improper_ctypes_definitions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: `extern` fn uses type `&str`, which is not FFI-safe
+error: `extern` fn uses type `str`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:73:31
    |
 LL | pub extern "C" fn str_type(p: &str) { }
    |                               ^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: string slices have no C equivalent
 
 error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:80:34
@@ -27,8 +27,7 @@ error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
 LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
    |                                  ^^^^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
-   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:83:35
@@ -36,8 +35,7 @@ error: `extern` fn uses type `Box`, which is not FFI-safe
 LL | pub extern "C" fn boxed_string(p: Box) { }
    |                                   ^^^^^^^^ not FFI-safe
    |
-   = help: consider using `*const u8` and a length instead
-   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `Box`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:86:34
@@ -45,7 +43,7 @@ error: `extern` fn uses type `Box`, which is not FFI-safe
 LL | pub extern "C" fn boxed_trait(p: Box) { }
    |                                  ^^^^^^^^^^^^^^ not FFI-safe
    |
-   = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: box cannot be represented as a single pointer
 
 error: `extern` fn uses type `char`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:89:32
@@ -151,14 +149,14 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` fn uses type `&str`, which is not FFI-safe
+error: `extern` fn uses type `str`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:126:38
    |
 LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
    |                                      ^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: string slices have no C equivalent
 
 error: `extern` fn uses type `PhantomData`, which is not FFI-safe
   --> $DIR/lint-ctypes-fn.rs:172:43
diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs
index 8c516ab8428b..dae07930aba6 100644
--- a/tests/ui/lint/lint-ctypes.rs
+++ b/tests/ui/lint/lint-ctypes.rs
@@ -1,5 +1,4 @@
 #![feature(rustc_private)]
-#![feature(extern_types)]
 
 #![allow(private_interfaces)]
 #![deny(improper_ctypes)]
@@ -7,9 +6,7 @@
 use std::cell::UnsafeCell;
 use std::marker::PhantomData;
 use std::ffi::{c_int, c_uint};
-use std::fmt::Debug;
 
-unsafe extern "C" {type UnsizedOpaque;}
 trait Bar { }
 trait Mirror { type It: ?Sized; }
 impl Mirror for T { type It = Self; }
@@ -23,7 +20,7 @@ pub type I32Pair = (i32, i32);
 #[repr(C)]
 pub struct ZeroSize;
 pub type RustFn = fn();
-pub type RustBoxRet = extern "C" fn() -> Box;
+pub type RustBadRet = extern "C" fn() -> Box;
 pub type CVoidRet = ();
 pub struct Foo;
 #[repr(transparent)]
@@ -31,7 +28,7 @@ pub struct TransparentI128(i128);
 #[repr(transparent)]
 pub struct TransparentStr(&'static str);
 #[repr(transparent)]
-pub struct TransparentBoxFn(RustBoxRet);
+pub struct TransparentBadFn(RustBadRet);
 #[repr(transparent)]
 pub struct TransparentInt(u32);
 #[repr(transparent)]
@@ -42,16 +39,6 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
 pub struct TransparentUnit(f32, PhantomData);
 #[repr(transparent)]
 pub struct TransparentCustomZst(i32, ZeroSize);
-#[repr(C)]
-pub struct UnsizedStructBecauseForeign {
-    sized: u32,
-    unszd: UnsizedOpaque,
-}
-#[repr(C)]
-pub struct UnsizedStructBecauseDyn {
-    sized: u32,
-    unszd: dyn Debug,
-}
 
 #[repr(C)]
 pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData);
@@ -61,14 +48,15 @@ extern "C" {
     pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
     pub fn ptr_unit(p: *const ());
     pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)`
-    pub fn slice_type(p: &[u32]); //~ ERROR: uses type `&[u32]`
-    pub fn str_type(p: &str); //~ ERROR: uses type `&str`
-    pub fn box_type(p: Box);
+    pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
+    pub fn str_type(p: &str); //~ ERROR: uses type `str`
+    pub fn box_type(p: Box); //~ ERROR uses type `Box`
     pub fn opt_box_type(p: Option>);
+    //~^ ERROR uses type `Option>`
     pub fn char_type(p: char); //~ ERROR uses type `char`
     pub fn i128_type(p: i128); //~ ERROR uses type `i128`
     pub fn u128_type(p: u128); //~ ERROR uses type `u128`
-    pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `&dyn Bar`
+    pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
     pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
     pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
     pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
@@ -78,15 +66,12 @@ extern "C" {
         -> ::std::marker::PhantomData; //~ ERROR uses type `PhantomData`
     pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()`
     pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()`
-    pub fn fn_contained(p: RustBoxRet);
+    pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box`
     pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
-    pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `&str`
-    pub fn transparent_fn(p: TransparentBoxFn);
+    pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
+    pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box`
     pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
 
-    pub fn struct_unsized_ptr_no_metadata(p: &UnsizedStructBecauseForeign);
-    pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); //~ ERROR uses type `&UnsizedStructBecauseDyn`
-
     pub fn no_niche_a(a: Option>);
     //~^ ERROR: uses type `Option>`
     pub fn no_niche_b(b: Option>);
diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr
index 8580a10b2153..2c81c7b8e4b6 100644
--- a/tests/ui/lint/lint-ctypes.stderr
+++ b/tests/ui/lint/lint-ctypes.stderr
@@ -1,68 +1,83 @@
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:60:28
+  --> $DIR/lint-ctypes.rs:47:28
    |
 LL |     pub fn ptr_type1(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:28:1
+  --> $DIR/lint-ctypes.rs:25:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/lint-ctypes.rs:5:9
+  --> $DIR/lint-ctypes.rs:4:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `Foo`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:61:28
+  --> $DIR/lint-ctypes.rs:48:28
    |
 LL |     pub fn ptr_type2(size: *const Foo);
    |                            ^^^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout
    = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
    = note: this struct has unspecified layout
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:28:1
+  --> $DIR/lint-ctypes.rs:25:1
    |
 LL | pub struct Foo;
    | ^^^^^^^^^^^^^^
 
 error: `extern` block uses type `((),)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:63:25
+  --> $DIR/lint-ctypes.rs:50:25
    |
 LL |     pub fn ptr_tuple(p: *const ((),));
    |                         ^^^^^^^^^^^^ not FFI-safe
    |
-   = note: this reference (`*const ((),)`) is ABI-compatible with a C pointer, but `((),)` itself does not have a C layout
    = help: consider using a struct instead
    = note: tuples have unspecified layout
 
-error: `extern` block uses type `&[u32]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:64:26
+error: `extern` block uses type `[u32]`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:51:26
    |
 LL |     pub fn slice_type(p: &[u32]);
    |                          ^^^^^^ not FFI-safe
    |
-   = help: consider using a raw pointer to the slice's first element (and a length) instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = help: consider using a raw pointer instead
+   = note: slices have no C equivalent
 
-error: `extern` block uses type `&str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:65:24
+error: `extern` block uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:52:24
    |
 LL |     pub fn str_type(p: &str);
    |                        ^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: string slices have no C equivalent
+
+error: `extern` block uses type `Box`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:53:24
+   |
+LL |     pub fn box_type(p: Box);
+   |                        ^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
+error: `extern` block uses type `Option>`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:54:28
+   |
+LL |     pub fn opt_box_type(p: Option>);
+   |                            ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+   = note: enum has no representation hint
 
 error: `extern` block uses type `char`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:68:25
+  --> $DIR/lint-ctypes.rs:56:25
    |
 LL |     pub fn char_type(p: char);
    |                         ^^^^ not FFI-safe
@@ -71,7 +86,7 @@ LL |     pub fn char_type(p: char);
    = note: the `char` type has no C equivalent
 
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:69:25
+  --> $DIR/lint-ctypes.rs:57:25
    |
 LL |     pub fn i128_type(p: i128);
    |                         ^^^^ not FFI-safe
@@ -79,23 +94,23 @@ LL |     pub fn i128_type(p: i128);
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:70:25
+  --> $DIR/lint-ctypes.rs:58:25
    |
 LL |     pub fn u128_type(p: u128);
    |                         ^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `&dyn Bar`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:71:26
+error: `extern` block uses type `dyn Bar`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:59:26
    |
 LL |     pub fn trait_type(p: &dyn Bar);
    |                          ^^^^^^^^ not FFI-safe
    |
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: trait objects have no C equivalent
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:72:26
+  --> $DIR/lint-ctypes.rs:60:26
    |
 LL |     pub fn tuple_type(p: (i32, i32));
    |                          ^^^^^^^^^^ not FFI-safe
@@ -104,7 +119,7 @@ LL |     pub fn tuple_type(p: (i32, i32));
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:73:27
+  --> $DIR/lint-ctypes.rs:61:27
    |
 LL |     pub fn tuple_type2(p: I32Pair);
    |                           ^^^^^^^ not FFI-safe
@@ -113,7 +128,7 @@ LL |     pub fn tuple_type2(p: I32Pair);
    = note: tuples have unspecified layout
 
 error: `extern` block uses type `ZeroSize`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:74:25
+  --> $DIR/lint-ctypes.rs:62:25
    |
 LL |     pub fn zero_size(p: ZeroSize);
    |                         ^^^^^^^^ not FFI-safe
@@ -121,26 +136,26 @@ LL |     pub fn zero_size(p: ZeroSize);
    = help: consider adding a member to this struct
    = note: this struct has no fields
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:24:1
+  --> $DIR/lint-ctypes.rs:21:1
    |
 LL | pub struct ZeroSize;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:75:33
+  --> $DIR/lint-ctypes.rs:63:33
    |
 LL |     pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: composed only of `PhantomData`
 note: the type is defined here
-  --> $DIR/lint-ctypes.rs:57:1
+  --> $DIR/lint-ctypes.rs:44:1
    |
 LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `PhantomData`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:78:12
+  --> $DIR/lint-ctypes.rs:66:12
    |
 LL |         -> ::std::marker::PhantomData;
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -148,7 +163,7 @@ LL |         -> ::std::marker::PhantomData;
    = note: composed only of `PhantomData`
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:79:23
+  --> $DIR/lint-ctypes.rs:67:23
    |
 LL |     pub fn fn_type(p: RustFn);
    |                       ^^^^^^ not FFI-safe
@@ -157,7 +172,7 @@ LL |     pub fn fn_type(p: RustFn);
    = note: this function pointer has Rust-specific calling convention
 
 error: `extern` block uses type `fn()`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:80:24
+  --> $DIR/lint-ctypes.rs:68:24
    |
 LL |     pub fn fn_type2(p: fn());
    |                        ^^^^ not FFI-safe
@@ -165,25 +180,43 @@ LL |     pub fn fn_type2(p: fn());
    = help: consider using an `extern fn(...) -> ...` function pointer instead
    = note: this function pointer has Rust-specific calling convention
 
+error: `extern` block uses type `Box`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:69:28
+   |
+LL |     pub fn fn_contained(p: RustBadRet);
+   |                            ^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
+
 error: `extern` block uses type `i128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:82:32
+  --> $DIR/lint-ctypes.rs:70:32
    |
 LL |     pub fn transparent_i128(p: TransparentI128);
    |                                ^^^^^^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: `extern` block uses type `&str`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:83:31
+error: `extern` block uses type `str`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:71:31
    |
 LL |     pub fn transparent_str(p: TransparentStr);
    |                               ^^^^^^^^^^^^^^ not FFI-safe
    |
    = help: consider using `*const u8` and a length instead
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
+   = note: string slices have no C equivalent
+
+error: `extern` block uses type `Box`, which is not FFI-safe
+  --> $DIR/lint-ctypes.rs:72:30
+   |
+LL |     pub fn transparent_fn(p: TransparentBadFn);
+   |                              ^^^^^^^^^^^^^^^^ not FFI-safe
+   |
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+   = note: this struct has unspecified layout
 
 error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:85:27
+  --> $DIR/lint-ctypes.rs:73:27
    |
 LL |     pub fn raw_array(arr: [u8; 8]);
    |                           ^^^^^^^ not FFI-safe
@@ -191,16 +224,8 @@ LL |     pub fn raw_array(arr: [u8; 8]);
    = help: consider passing a pointer to the array
    = note: passing raw arrays by value is not FFI-safe
 
-error: `extern` block uses type `&UnsizedStructBecauseDyn`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:88:47
-   |
-LL |     pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn);
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer
-
 error: `extern` block uses type `Option>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:90:26
+  --> $DIR/lint-ctypes.rs:75:26
    |
 LL |     pub fn no_niche_a(a: Option>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -209,7 +234,7 @@ LL |     pub fn no_niche_a(a: Option>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `Option>`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:92:26
+  --> $DIR/lint-ctypes.rs:77:26
    |
 LL |     pub fn no_niche_b(b: Option>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -218,7 +243,7 @@ LL |     pub fn no_niche_b(b: Option>);
    = note: enum has no representation hint
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:95:34
+  --> $DIR/lint-ctypes.rs:80:34
    |
 LL |     pub static static_u128_type: u128;
    |                                  ^^^^ not FFI-safe
@@ -226,12 +251,12 @@ LL |     pub static static_u128_type: u128;
    = note: 128-bit integers don't currently have a known stable ABI
 
 error: `extern` block uses type `u128`, which is not FFI-safe
-  --> $DIR/lint-ctypes.rs:96:40
+  --> $DIR/lint-ctypes.rs:81:40
    |
 LL |     pub static static_u128_array_type: [u128; 16];
    |                                        ^^^^^^^^^^ not FFI-safe
    |
    = note: 128-bit integers don't currently have a known stable ABI
 
-error: aborting due to 24 previous errors
+error: aborting due to 27 previous errors
 

From 38bfd88db788210d2481e3c74b2c63006f658cc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?=
 <39484203+jieyouxu@users.noreply.github.com>
Date: Mon, 9 Dec 2024 17:39:08 +0800
Subject: [PATCH 116/197] Add regression test for #134060

Mostly just to check that the lint impl doesn't ICE from an easy case.
---
 .../improper_ctypes_definitions_ice_134060.rs     | 15 +++++++++++++++
 .../improper_ctypes_definitions_ice_134060.stderr | 12 ++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 tests/ui/lint/improper_ctypes_definitions_ice_134060.rs
 create mode 100644 tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr

diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs b/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs
new file mode 100644
index 000000000000..b30be9967368
--- /dev/null
+++ b/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs
@@ -0,0 +1,15 @@
+//! Regression test for  due to impl bug from
+//! . This test should be adjusted in favor of more
+//! comprehensive coverage when the changes are to be relanded, as this is a basic sanity check to
+//! check that the fuzzed example from #134060 doesn't ICE.
+
+//@ check-pass
+
+#![crate_type = "lib"]
+
+pub trait Foo {
+    extern "C" fn foo_(&self, _: ()) -> i64 {
+        //~^ WARN `extern` fn uses type `()`, which is not FFI-safe
+        0
+    }
+}
diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr b/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr
new file mode 100644
index 000000000000..f6ac9a92cd5f
--- /dev/null
+++ b/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr
@@ -0,0 +1,12 @@
+warning: `extern` fn uses type `()`, which is not FFI-safe
+  --> $DIR/improper_ctypes_definitions_ice_134060.rs:11:34
+   |
+LL |     extern "C" fn foo_(&self, _: ()) -> i64 {
+   |                                  ^^ not FFI-safe
+   |
+   = help: consider using a struct instead
+   = note: tuples have unspecified layout
+   = note: `#[warn(improper_ctypes_definitions)]` on by default
+
+warning: 1 warning emitted
+

From b9f809a4b512034297a01ebeb0428fc7988007b0 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 09:48:54 +0100
Subject: [PATCH 117/197] Rename test fixture crates to ra_test_fixture

---
 .../crates/hir-def/src/body/tests.rs          |   3 +-
 .../hir-def/src/macro_expansion_tests/mod.rs  |   3 +-
 .../crates/hir-def/src/nameres/tests.rs       |   4 +-
 .../hir-def/src/nameres/tests/incremental.rs  |  13 +-
 .../crates/hir-def/src/test_db.rs             |  13 +
 .../generate_documentation_template.rs        |  20 +-
 .../crates/ide-assists/src/tests/generated.rs |   2 +-
 .../crates/ide/src/hover/tests.rs             | 744 +++++++++---------
 .../crates/test-fixture/src/lib.rs            |   2 +-
 9 files changed, 407 insertions(+), 397 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index 82d46d2e492c..8f0109158454 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -1,6 +1,5 @@
 mod block;
 
-use base_db::SourceDatabase;
 use expect_test::{expect, Expect};
 use test_fixture::WithFixture;
 
@@ -11,7 +10,7 @@ use super::*;
 fn lower(ra_fixture: &str) -> (TestDB, Arc, DefWithBodyId) {
     let db = TestDB::with_files(ra_fixture);
 
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     let def_map = db.crate_def_map(krate);
     let mut fn_def = None;
     'outer: for (_, module) in def_map.modules() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index d5b94f0ae443..0475e40c5b2a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,7 +16,6 @@ mod proc_macros;
 
 use std::{iter, ops::Range, sync};
 
-use base_db::SourceDatabase;
 use expect_test::Expect;
 use hir_expand::{
     db::ExpandDatabase,
@@ -63,7 +62,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         },
     )];
     let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     let def_map = db.crate_def_map(krate);
     let local_id = DefMap::ROOT;
     let module = def_map.module_id(local_id);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index e1e30e5cec9a..32c158415ba6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -13,13 +13,13 @@ use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
 
 fn compute_crate_def_map(ra_fixture: &str) -> Arc {
     let db = TestDB::with_files(ra_fixture);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     db.crate_def_map(krate)
 }
 
 fn render_crate_def_map(ra_fixture: &str) -> String {
     let db = TestDB::with_files(ra_fixture);
-    let krate = db.crate_graph().iter().next().unwrap();
+    let krate = db.fetch_test_crate();
     db.crate_def_map(krate).dump(&db)
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index e54b0fb78f82..1cfbabca28cd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -1,16 +1,11 @@
-use base_db::{SourceDatabase, SourceDatabaseFileInputExt as _};
+use base_db::SourceDatabaseFileInputExt as _;
 use test_fixture::WithFixture;
 
 use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId};
 
 fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
     let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
-    let krate = {
-        let crate_graph = db.crate_graph();
-        // Some of these tests use minicore/proc-macros which will be injected as the first crate
-        let krate = crate_graph.iter().next().unwrap();
-        krate
-    };
+    let krate = db.fetch_test_crate();
     {
         let events = db.log_executed(|| {
             db.crate_def_map(krate);
@@ -121,6 +116,8 @@ fn f() { foo }
     );
 }
 
+// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is
+// not currently the case.
 // #[test]
 // fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() {
 //     check_def_map_is_not_recomputed(
@@ -200,6 +197,8 @@ pub struct S {}
     );
 }
 
+// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is
+// not currently the case.
 // #[test]
 // fn typing_inside_a_derive_should_not_invalidate_def_map() {
 //     check_def_map_is_not_recomputed(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 0c36c88fb093..54e6c1fd206d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -78,6 +78,19 @@ impl FileLoader for TestDB {
 }
 
 impl TestDB {
+    pub(crate) fn fetch_test_crate(&self) -> CrateId {
+        let crate_graph = self.crate_graph();
+        let it = crate_graph
+            .iter()
+            .find(|&idx| {
+                crate_graph[idx].display_name.as_ref().map(|it| it.canonical_name().as_str())
+                    == Some("ra_test_fixture")
+            })
+            .or_else(|| crate_graph.iter().next())
+            .unwrap();
+        it
+    }
+
     pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
         for &krate in self.relevant_crates(file_id).iter() {
             let crate_def_map = self.crate_def_map(krate);
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 c5c70c9f8eb6..862be791d173 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
@@ -88,7 +88,7 @@ pub(crate) fn generate_documentation_template(
 // /// # Examples
 // ///
 // /// ```
-// /// use test::add;
+// /// use ra_test_fixture::add;
 // ///
 // /// assert_eq!(add(a, b), );
 // /// ```
@@ -596,7 +596,7 @@ pub fn noop_with_param(_a: i32) {}
 /// # Examples
 ///
 /// ```
-/// use test::noop_with_param;
+/// use ra_test_fixture::noop_with_param;
 ///
 /// noop_with_param(_a);
 /// ```
@@ -641,7 +641,7 @@ pub unsafe fn noop_unsafe() {}
 /// # Examples
 ///
 /// ```
-/// use test::noop_unsafe;
+/// use ra_test_fixture::noop_unsafe;
 ///
 /// unsafe { noop_unsafe() };
 /// ```
@@ -758,7 +758,7 @@ pub fn returns_a_value$0() -> i32 {
 /// # Examples
 ///
 /// ```
-/// use test::returns_a_value;
+/// use ra_test_fixture::returns_a_value;
 ///
 /// assert_eq!(returns_a_value(), );
 /// ```
@@ -807,7 +807,7 @@ pub fn modifies_a_value$0(a: &mut i32) {
 /// # Examples
 ///
 /// ```
-/// use test::modifies_a_value;
+/// use ra_test_fixture::modifies_a_value;
 ///
 /// let mut a = ;
 /// modifies_a_value(&mut a);
@@ -836,7 +836,7 @@ pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 {
 /// # Examples
 ///
 /// ```
-/// use test::sum3;
+/// use ra_test_fixture::sum3;
 ///
 /// let result = sum3(a, b, c);
 /// assert_eq!(result, );
@@ -868,7 +868,7 @@ pub mod a {
         /// # Examples
         ///
         /// ```
-        /// use test::a::b::noop;
+        /// use ra_test_fixture::a::b::noop;
         ///
         /// noop();
         /// ```
@@ -898,7 +898,7 @@ impl MyStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyStruct;
+    /// use ra_test_fixture::MyStruct;
     ///
     /// MyStruct::noop();
     /// ```
@@ -1169,7 +1169,7 @@ impl MyGenericStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyGenericStruct;
+    /// use ra_test_fixture::MyGenericStruct;
     ///
     /// let my_generic_struct = ;
     /// my_generic_struct.consume();
@@ -1199,7 +1199,7 @@ impl MyGenericStruct {
     /// # Examples
     ///
     /// ```
-    /// use test::MyGenericStruct;
+    /// use ra_test_fixture::MyGenericStruct;
     ///
     /// let mut my_generic_struct = ;
     /// my_generic_struct.modify(new_value);
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 eef4da55e94a..69ea200db169 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
@@ -1392,7 +1392,7 @@ pub fn add(a: i32, b: i32) -> i32 { a + b }
 /// # Examples
 ///
 /// ```
-/// use test::add;
+/// use ra_test_fixture::add;
 ///
 /// assert_eq!(add(a, b), );
 /// ```
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 1c08514a6721..ea18b89c5c92 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -288,7 +288,7 @@ m!(ab$0c);
             *abc*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -301,7 +301,7 @@ m!(ab$0c);
             ---
 
             ```rust
-            test::module
+            ra_test_fixture::module
             ```
 
             ```rust
@@ -327,7 +327,7 @@ fn main() {
 "#,
         expect![[r#"
             *foo*
-            test
+            ra_test_fixture
 
             pub fn foo() -> u32
         "#]],
@@ -487,7 +487,7 @@ fn main() {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -500,7 +500,7 @@ fn main() {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -583,7 +583,7 @@ fn main() { let foo_test = fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -605,7 +605,7 @@ fn main() { f$0oo(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -627,7 +627,7 @@ fn main() { m::f$0oo(); }
             *foo*
 
             ```rust
-            test::m
+            ra_test_fixture::m
             ```
 
             ```rust
@@ -649,7 +649,7 @@ fn main() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -667,7 +667,7 @@ fn main() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -691,7 +691,7 @@ fn main() { let foo_test = fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -715,7 +715,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -743,7 +743,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -776,7 +776,7 @@ fn main() { }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -801,7 +801,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -830,7 +830,7 @@ fn main() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -852,7 +852,7 @@ fn main() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -880,7 +880,7 @@ fn main() {
             *0*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -900,7 +900,7 @@ fn foo(foo: Foo) {
             *0*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -920,7 +920,7 @@ struct Foo$0(pub u32) where u32: Copy;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -946,7 +946,7 @@ struct Foo$0 { field: u32 }
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -968,7 +968,7 @@ struct Foo$0 where u32: Copy { field: u32 }
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -998,7 +998,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1023,7 +1023,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1046,7 +1046,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1072,7 +1072,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1093,7 +1093,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1116,7 +1116,7 @@ fn hover_record_struct_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1141,7 +1141,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1162,7 +1162,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1183,7 +1183,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1204,7 +1204,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1225,7 +1225,7 @@ fn hover_record_variant_limit() {
             *A*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -1248,7 +1248,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1270,7 +1270,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1292,7 +1292,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1311,7 +1311,7 @@ fn hover_enum_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1339,7 +1339,7 @@ fn hover_enum_limit() {
             *Enum*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1371,7 +1371,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1393,7 +1393,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1415,7 +1415,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1434,7 +1434,7 @@ fn hover_union_limit() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1458,7 +1458,7 @@ struct Foo$0 where u32: Copy;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1484,7 +1484,7 @@ type Fo$0o: Trait = S where T: Trait;
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1504,7 +1504,7 @@ fn hover_const_static() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1522,7 +1522,7 @@ const foo$0: u32 = {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1540,7 +1540,7 @@ const foo$0: u32 = {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1555,7 +1555,7 @@ const foo$0: u32 = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1573,7 +1573,7 @@ const foo$0: u32 = {
             *BAR*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1591,7 +1591,7 @@ fn hover_unsigned_max_const() {
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1612,7 +1612,7 @@ fn hover_eval_complex_constants() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -1667,16 +1667,16 @@ use Option::Some;
 fn main() { So$0me(12); }
 "#,
         expect![[r#"
-                *Some*
+            *Some*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                Some(T)
-                ```
-            "#]],
+            ```rust
+            Some(T)
+            ```
+        "#]],
     );
 
     check(
@@ -1711,20 +1711,20 @@ enum Option {
 }
 "#,
         expect![[r#"
-                *None*
+            *None*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                None
-                ```
+            ```rust
+            None
+            ```
 
-                ---
+            ---
 
-                The None variant
-            "#]],
+            The None variant
+        "#]],
     );
 
     check(
@@ -1738,20 +1738,20 @@ fn main() {
 }
 "#,
         expect![[r#"
-                *Some*
+            *Some*
 
-                ```rust
-                test::Option
-                ```
+            ```rust
+            ra_test_fixture::Option
+            ```
 
-                ```rust
-                Some(T)
-                ```
+            ```rust
+            Some(T)
+            ```
 
-                ---
+            ---
 
-                The Some variant
-            "#]],
+            The Some variant
+        "#]],
     );
 }
 
@@ -1885,7 +1885,7 @@ fn main() { let foo_test = wrapper::Thing::new$0(); }
             *new*
 
             ```rust
-            test::wrapper::Thing
+            ra_test_fixture::wrapper::Thing
             ```
 
             ```rust
@@ -1916,7 +1916,7 @@ fn main() {
             *C*
 
             ```rust
-            test::X
+            ra_test_fixture::X
             ```
 
             ```rust
@@ -1936,18 +1936,18 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing {
-                    x: u32,
-                }
-                ```
-            "#]],
+            ```rust
+            struct Thing {
+                x: u32,
+            }
+            ```
+        "#]],
     );
     check_hover_fields_limit(
         None,
@@ -1958,16 +1958,16 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing
-                ```
-            "#]],
+            ```rust
+            struct Thing
+            ```
+        "#]],
     );
     check(
         r#"
@@ -1977,18 +1977,18 @@ impl Thing {
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                struct Thing {
-                    x: u32,
-                }
-                ```
-            "#]],
+            ```rust
+            struct Thing {
+                x: u32,
+            }
+            ```
+        "#]],
     );
     check(
         r#"
@@ -2001,7 +2001,7 @@ impl Thing {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2022,7 +2022,7 @@ impl Thing {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2042,7 +2042,7 @@ impl usize {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2060,7 +2060,7 @@ impl fn() -> usize {
             *Self*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2103,7 +2103,7 @@ fn f() { fo$0o!(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2128,7 +2128,7 @@ fn f() { fo$0o!(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2172,7 +2172,7 @@ id! {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2194,7 +2194,7 @@ fn foo$0() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2252,7 +2252,7 @@ fn foo() { let a = id!([0u32, bar$0()] ); }
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2278,7 +2278,7 @@ fn foo() {
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2302,7 +2302,7 @@ fn foo(Foo { b$0ar }: &Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -2334,7 +2334,7 @@ fn bar() { fo$0o(); }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2356,7 +2356,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2370,7 +2370,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2385,7 +2385,7 @@ fn test_hover_function_show_qualifiers() {
             *foo*
 
             ```rust
-            test::m
+            ra_test_fixture::m
             ```
 
             ```rust
@@ -2403,7 +2403,7 @@ fn test_hover_function_show_types() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2426,7 +2426,7 @@ fn main() { foo$0; }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2446,7 +2446,7 @@ fn main() { foo$0; }
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2464,7 +2464,7 @@ fn test_hover_function_pointer_show_identifiers() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2486,7 +2486,7 @@ fn test_hover_function_pointer_no_identifier() {
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2601,16 +2601,16 @@ mod my { pub struct Bar; }
 fn my() {}
 "#,
         expect![[r#"
-                *my*
+            *my*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod my
-                ```
-            "#]],
+            ```rust
+            mod my
+            ```
+        "#]],
     );
 }
 
@@ -2636,7 +2636,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2672,7 +2672,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2701,7 +2701,7 @@ fn foo() { let bar = Ba$0r; }
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2729,7 +2729,7 @@ pub struct B$0ar
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2760,7 +2760,7 @@ pub struct B$0ar
             *Bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2809,7 +2809,7 @@ pub fn fo$0o() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2853,7 +2853,7 @@ fn test_hover_layout_of_variant() {
             *Variant1*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -2878,7 +2878,7 @@ fn test_hover_layout_of_variant_generic() {
             *None*
 
             ```rust
-            test::Option
+            ra_test_fixture::Option
             ```
 
             ```rust
@@ -2899,7 +2899,7 @@ struct S$0(core::marker::PhantomData);
             *S*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2924,7 +2924,7 @@ fn test_hover_layout_of_enum() {
             *Foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -2949,7 +2949,7 @@ fn test_hover_no_memory_layout() {
             *field_a*
 
             ```rust
-            test::Foo
+            ra_test_fixture::Foo
             ```
 
             ```rust
@@ -3003,7 +3003,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); }
             *foo*
 
             ```rust
-            test::Bar
+            ra_test_fixture::Bar
             ```
 
             ```rust
@@ -3041,7 +3041,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); }
             *foo*
 
             ```rust
-            test::Bar
+            ra_test_fixture::Bar
             ```
 
             ```rust
@@ -3069,7 +3069,7 @@ fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } }
             *foo*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -3267,7 +3267,7 @@ fn main() { let s$0t = S{ f1:0 }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3300,7 +3300,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Arg",
+                            mod_path: "ra_test_fixture::Arg",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3313,7 +3313,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3359,7 +3359,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Arg",
+                            mod_path: "ra_test_fixture::Arg",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3372,7 +3372,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3408,7 +3408,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::A",
+                            mod_path: "ra_test_fixture::A",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3421,7 +3421,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3434,7 +3434,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::M::C",
+                            mod_path: "ra_test_fixture::M::C",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3468,7 +3468,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3502,7 +3502,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3515,7 +3515,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3549,7 +3549,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3562,7 +3562,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3599,7 +3599,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3612,7 +3612,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3625,7 +3625,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S1",
+                            mod_path: "ra_test_fixture::S1",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3638,7 +3638,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3669,7 +3669,7 @@ fn foo(ar$0g: &impl Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3703,7 +3703,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3716,7 +3716,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3729,7 +3729,7 @@ fn foo(ar$0g: &impl Foo + Bar) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3816,7 +3816,7 @@ fn foo(ar$0g: &impl Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3829,7 +3829,7 @@ fn foo(ar$0g: &impl Foo) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3866,7 +3866,7 @@ fn main() { let s$0t = foo(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3879,7 +3879,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3892,7 +3892,7 @@ fn main() { let s$0t = foo(); }
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3923,7 +3923,7 @@ fn foo(ar$0g: &dyn Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3955,7 +3955,7 @@ fn foo(ar$0g: &dyn Foo) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -3968,7 +3968,7 @@ fn foo(ar$0g: &dyn Foo) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4003,7 +4003,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::B",
+                            mod_path: "ra_test_fixture::B",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4016,7 +4016,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::DynTrait",
+                            mod_path: "ra_test_fixture::DynTrait",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4029,7 +4029,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::ImplTrait",
+                            mod_path: "ra_test_fixture::ImplTrait",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4042,7 +4042,7 @@ fn foo(a$0rg: &impl ImplTrait>>>) {}
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S",
+                            mod_path: "ra_test_fixture::S",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4084,7 +4084,7 @@ fn main() { let s$0t = test().get(); }
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4117,7 +4117,7 @@ impl Foo {}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Bar",
+                            mod_path: "ra_test_fixture::Bar",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4149,7 +4149,7 @@ fn foo(t: T$0){}
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4182,7 +4182,7 @@ impl Foo {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -4257,7 +4257,7 @@ fn main() {
             ---
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -4282,7 +4282,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4307,7 +4307,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4333,7 +4333,7 @@ struct S$0T(T);
             *ST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4527,21 +4527,21 @@ mod Foo$0 {
 }
 "#,
         expect![[r#"
-                *Foo*
+            *Foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod Foo
-                ```
+            ```rust
+            mod Foo
+            ```
 
-                ---
+            ---
 
-                Be quick;
-                time is mana
-            "#]],
+            Be quick;
+            time is mana
+        "#]],
     );
 }
 
@@ -4558,21 +4558,21 @@ mod Foo$0 {
 }
 "#,
         expect![[r#"
-                *Foo*
+            *Foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod Foo
-                ```
+            ```rust
+            mod Foo
+            ```
 
-                ---
+            ---
 
-                Be quick;
-                time is mana
-            "#]],
+            Be quick;
+            time is mana
+        "#]],
     );
 }
 
@@ -4592,7 +4592,7 @@ fn foo$0() {}
             *foo*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4902,7 +4902,7 @@ type Fo$0o2 = Foo<2>;
             *Foo2*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -4948,7 +4948,7 @@ enum E {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -4977,7 +4977,7 @@ enum E {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5007,7 +5007,7 @@ enum E {
             *B*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5037,7 +5037,7 @@ enum E {
             *B*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5074,7 +5074,7 @@ fn main() {
             *B*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5111,7 +5111,7 @@ fn main() {
             *AA*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5138,7 +5138,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5167,7 +5167,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5199,7 +5199,7 @@ fn main() {
             *B*
 
             ```rust
-            test::T
+            ra_test_fixture::T
             ```
 
             ```rust
@@ -5222,7 +5222,7 @@ const FOO$0: usize = 1 << 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5243,7 +5243,7 @@ const FOO$0: usize = (1 << 3) + (1 << 2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5265,7 +5265,7 @@ const FOO$0: usize = 2 - 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5287,7 +5287,7 @@ const FOO$0: i32 = 2 - 3;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5308,7 +5308,7 @@ const FOO$0: &str = "bar";
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5330,7 +5330,7 @@ const FOO$0: char = 'a';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5352,7 +5352,7 @@ const FOO$0: char = '\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5374,7 +5374,7 @@ const FOO$0: u8 = b'a';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5396,7 +5396,7 @@ const FOO$0: u8 = b'\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5418,7 +5418,7 @@ const FOO$0: u8 = b'\x61';
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5440,7 +5440,7 @@ const FOO$0: f32 = 1f32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5462,7 +5462,7 @@ const FOO$0: &i32 = &2;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5484,7 +5484,7 @@ const FOO$0: f64 = 1.0f64;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5512,7 +5512,7 @@ const FOO$0: f64 = expf64(1.2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5530,7 +5530,7 @@ const FOO$0: f32 = 1.9999999403953552_f32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5552,7 +5552,7 @@ const FOO$0: f16 = -1.0f16;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5573,7 +5573,7 @@ const FOO$0: f128 = -1.0f128;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5604,7 +5604,7 @@ const FOO$0: Enum = VX;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5621,7 +5621,7 @@ const FOO$0: Option = Some(2);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5638,7 +5638,7 @@ const FOO$0: Option<&i32> = Some(2).as_ref();
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5661,7 +5661,7 @@ const FOO$0: &dyn Debug = &2i32;
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5682,7 +5682,7 @@ const FOO$0: &[i32] = &[1, 2, 3 + 4];
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5699,7 +5699,7 @@ const FOO$0: &[i32; 5] = &[12; 5];
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5720,7 +5720,7 @@ const FOO$0: (&i32, &[i32], &i32) = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5743,7 +5743,7 @@ const FOO$0: Tree = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5763,7 +5763,7 @@ const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]);
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5783,7 +5783,7 @@ const FOO$0: &str = "foo";
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5806,7 +5806,7 @@ const FOO$0: X = X {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5825,7 +5825,7 @@ const FOO$0: (&str, &str) = {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5856,7 +5856,7 @@ fn test() {
             *FOO*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -5883,7 +5883,7 @@ fn foo() {
             *FOO*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5912,7 +5912,7 @@ fn foo(e: E) {
             *A*
 
             ```rust
-            test::E
+            ra_test_fixture::E
             ```
 
             ```rust
@@ -5942,7 +5942,7 @@ pub fn the_function() -> AA {
             *CONST*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -5984,20 +5984,20 @@ mod foo$0;
 //! For the horde!
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod foo
-                ```
+            ```rust
+            mod foo
+            ```
 
-                ---
+            ---
 
-                For the horde!
-            "#]],
+            For the horde!
+        "#]],
     );
 }
 
@@ -6013,20 +6013,20 @@ mod foo {
 use foo::bar::{self$0};
 "#,
         expect![[r#"
-                *self*
+            *self*
 
-                ```rust
-                test::foo
-                ```
+            ```rust
+            ra_test_fixture::foo
+            ```
 
-                ```rust
-                mod bar
-                ```
+            ```rust
+            mod bar
+            ```
 
-                ---
+            ---
 
-                But this should appear
-            "#]],
+            But this should appear
+        "#]],
     )
 }
 
@@ -6166,7 +6166,7 @@ fn main() {
             *bar*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6200,7 +6200,7 @@ pub fn gimme() -> theitem::TheItem {
             *[`TheItem`]*
 
             ```rust
-            test::theitem
+            ra_test_fixture::theitem
             ```
 
             ```rust
@@ -6248,7 +6248,7 @@ impl T1 for Foo {
             *Bar*
 
             ```rust
-            test::t2::T2
+            ra_test_fixture::t2::T2
             ```
 
             ```rust
@@ -6270,7 +6270,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6291,7 +6291,7 @@ trait A {
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6310,7 +6310,7 @@ trait A where
             *Assoc*
 
             ```rust
-            test::A
+            ra_test_fixture::A
             ```
 
             ```rust
@@ -6572,12 +6572,12 @@ fn hover_rename() {
 use self as foo$0;
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
     check(
         r#"
@@ -6585,16 +6585,16 @@ mod bar {}
 use bar::{self as foo$0};
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                test
-                ```
+            ```rust
+            ra_test_fixture
+            ```
 
-                ```rust
-                mod bar
-                ```
-            "#]],
+            ```rust
+            mod bar
+            ```
+        "#]],
     );
     check(
         r#"
@@ -6603,24 +6603,24 @@ mod bar {
 }
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
     check(
         r#"
 use crate as foo$0;
 "#,
         expect![[r#"
-                *foo*
+            *foo*
 
-                ```rust
-                extern crate test
-                ```
-            "#]],
+            ```rust
+            extern crate ra_test_fixture
+            ```
+        "#]],
     );
 }
 
@@ -6645,7 +6645,7 @@ identity!{
             *Copy*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6669,7 +6669,7 @@ struct Foo;
             *Copy*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -6691,7 +6691,7 @@ struct Foo;
             *Copy*
 
             ```rust
-            test::foo
+            ra_test_fixture::foo
             ```
 
             ```rust
@@ -6910,7 +6910,7 @@ fn foo() {
                 GoToType(
                     [
                         HoverGotoTypeData {
-                            mod_path: "test::Foo",
+                            mod_path: "ra_test_fixture::Foo",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -7110,7 +7110,7 @@ foo_macro!(
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7119,7 +7119,7 @@ foo_macro!(
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7135,7 +7135,7 @@ pub struct Foo(i32);
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7144,7 +7144,7 @@ pub struct Foo(i32);
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7160,7 +7160,7 @@ pub struct Foo(T);
             *[`Foo`]*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7169,7 +7169,7 @@ pub struct Foo(T);
 
             ---
 
-            Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html)
+            Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html)
         "#]],
     );
 }
@@ -7259,7 +7259,7 @@ enum Enum {
             *RecordV*
 
             ```rust
-            test::Enum
+            ra_test_fixture::Enum
             ```
 
             ```rust
@@ -7285,7 +7285,7 @@ enum Enum {
             *field*
 
             ```rust
-            test::RecordV
+            ra_test_fixture::RecordV
             ```
 
             ```rust
@@ -7315,7 +7315,7 @@ impl T for () {
             *func*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7341,7 +7341,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7360,7 +7360,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7383,7 +7383,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7406,7 +7406,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7433,7 +7433,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7460,7 +7460,7 @@ impl T$0 for () {}
             *T*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7529,7 +7529,7 @@ fn f() {
             ***
 
             ```rust
-            test::Struct
+            ra_test_fixture::Struct
             ```
 
             ```rust
@@ -7558,7 +7558,7 @@ fn main() { $0V; }
             *V*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7585,7 +7585,7 @@ fn main() { $0V; }
             *V*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -7765,7 +7765,7 @@ fn test() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7794,7 +7794,7 @@ fn test() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7824,7 +7824,7 @@ mod m {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7854,7 +7854,7 @@ fn test() {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7883,7 +7883,7 @@ fn test() {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7913,7 +7913,7 @@ mod m {
             *A*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -7936,7 +7936,7 @@ fn test() {
             *f*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -8091,7 +8091,7 @@ fn main() {
             *foo*
 
             ```rust
-            test::S
+            ra_test_fixture::S
             ```
 
             ```rust
@@ -8573,7 +8573,7 @@ impl Iterator for S {
             *S*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8595,7 +8595,7 @@ extern "C" {
             *STATIC*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8613,7 +8613,7 @@ extern "C" {
             *fun*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8631,7 +8631,7 @@ extern "C" {
             *Ty*
 
             ```rust
-            test::
+            ra_test_fixture::
             ```
 
             ```rust
@@ -8731,7 +8731,7 @@ impl Iterator for S {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::Notable",
+                            mod_path: "ra_test_fixture::Notable",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -8744,7 +8744,7 @@ impl Iterator for S {
                             },
                         },
                         HoverGotoTypeData {
-                            mod_path: "test::S2",
+                            mod_path: "ra_test_fixture::S2",
                             nav: NavigationTarget {
                                 file_id: FileId(
                                     0,
@@ -8775,7 +8775,7 @@ struct Pedro$0<'a> {
             *Pedro*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8962,7 +8962,7 @@ fn test_hover_function_with_pat_param() {
             *test_1*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8978,7 +8978,7 @@ fn test_hover_function_with_pat_param() {
             *test_2*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -8994,7 +8994,7 @@ fn test_hover_function_with_pat_param() {
             *test_3*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9010,7 +9010,7 @@ fn test_hover_function_with_pat_param() {
             *test_4*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9026,7 +9026,7 @@ fn test_hover_function_with_pat_param() {
             *test_5*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9042,7 +9042,7 @@ fn test_hover_function_with_pat_param() {
             *test_6*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9058,7 +9058,7 @@ fn test_hover_function_with_pat_param() {
             *test_7*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9074,7 +9074,7 @@ fn test_hover_function_with_pat_param() {
             *test_8*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9090,7 +9090,7 @@ fn test_hover_function_with_pat_param() {
             *test_9*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9106,7 +9106,7 @@ fn test_hover_function_with_pat_param() {
             *test_10*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9122,7 +9122,7 @@ fn test_hover_function_with_pat_param() {
             *test_10*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9148,7 +9148,7 @@ mod m {
             *C*
 
             ```rust
-            test::m::m2
+            ra_test_fixture::m::m2
             ```
 
             ```rust
@@ -9173,17 +9173,17 @@ macro_rules! foo {
 foo!(BAR_$0);
 "#,
         expect![[r#"
-        *BAR_*
+            *BAR_*
 
-        ```rust
-        test
-        ```
+            ```rust
+            ra_test_fixture
+            ```
 
-        ```rust
-        pub static BAR_: {error} = Foo::new(||{
-            crate;
-        })
-        ```
+            ```rust
+            pub static BAR_: {error} = Foo::new(||{
+                crate;
+            })
+            ```
         "#]],
     );
 }
@@ -9202,7 +9202,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9235,7 +9235,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9269,7 +9269,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9301,7 +9301,7 @@ type A$0 = B;
             *A*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9362,7 +9362,7 @@ trait Compat$0 {}
             *Compat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9384,7 +9384,7 @@ trait UnCompat$0 {
             *UnCompat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
@@ -9407,7 +9407,7 @@ fn f
             *UnCompat*
 
             ```rust
-            test
+            ra_test_fixture
             ```
 
             ```rust
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 593e31c2fbb8..889a7d10adad 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -236,7 +236,7 @@ impl ChangeFixture {
             crate_graph.add_crate_root(
                 crate_root,
                 Edition::CURRENT,
-                Some(CrateName::new("test").unwrap().into()),
+                Some(CrateName::new("ra_test_fixture").unwrap().into()),
                 None,
                 From::from(default_cfg.clone()),
                 Some(From::from(default_cfg)),

From 770265d0578e5146092681bb252f29f0023d5028 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 11:42:51 +0100
Subject: [PATCH 118/197] Remove patch sysroot cfg-if hack

---
 .../rust-analyzer/crates/base-db/src/input.rs | 23 ---------
 .../crates/project-model/src/workspace.rs     | 48 +++++++------------
 2 files changed, 18 insertions(+), 53 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 57522d69321f..e86944eeb352 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -547,29 +547,6 @@ impl CrateGraph {
         None
     }
 
-    // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038.
-    // As hacky as it gets.
-    pub fn patch_cfg_if(&mut self) -> bool {
-        // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works
-        let cfg_if =
-            self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone());
-        let std = self.hacky_find_crate("std").next();
-        match (cfg_if, std) {
-            (Some(cfg_if), Some(std)) => {
-                self.arena[cfg_if].dependencies.clear();
-                self.arena[std]
-                    .dependencies
-                    .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if));
-                true
-            }
-            _ => false,
-        }
-    }
-
-    fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator + 'a {
-        self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name))
-    }
-
     /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies.
     /// Returns a mapping from old crate ids to new crate ids.
     pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec> {
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 f5ba71fcd05f..988eff9be447 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -747,17 +747,14 @@ impl ProjectWorkspace {
         let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered();
 
         let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
-        let ((mut crate_graph, proc_macros), sysroot) = match kind {
-            ProjectWorkspaceKind::Json(project) => (
-                project_json_to_crate_graph(
-                    rustc_cfg.clone(),
-                    load,
-                    project,
-                    sysroot,
-                    extra_env,
-                    cfg_overrides,
-                ),
+        let (crate_graph, proc_macros) = match kind {
+            ProjectWorkspaceKind::Json(project) => project_json_to_crate_graph(
+                rustc_cfg.clone(),
+                load,
+                project,
                 sysroot,
+                extra_env,
+                cfg_overrides,
             ),
             ProjectWorkspaceKind::Cargo {
                 cargo,
@@ -766,20 +763,17 @@ impl ProjectWorkspace {
                 cargo_config_extra_env: _,
                 error: _,
                 set_test,
-            } => (
-                cargo_to_crate_graph(
-                    load,
-                    rustc.as_ref().map(|a| a.as_ref()).ok(),
-                    cargo,
-                    sysroot,
-                    rustc_cfg.clone(),
-                    cfg_overrides,
-                    build_scripts,
-                    *set_test,
-                ),
+            } => cargo_to_crate_graph(
+                load,
+                rustc.as_ref().map(|a| a.as_ref()).ok(),
+                cargo,
                 sysroot,
+                rustc_cfg.clone(),
+                cfg_overrides,
+                build_scripts,
+                *set_test,
             ),
-            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => (
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => {
                 if let Some((cargo, build_scripts, _)) = cargo_script {
                     cargo_to_crate_graph(
                         &mut |path| load(path),
@@ -800,16 +794,10 @@ impl ProjectWorkspace {
                         cfg_overrides,
                         *set_test,
                     )
-                },
-                sysroot,
-            ),
+                }
+            }
         };
 
-        if matches!(sysroot.mode(), SysrootMode::Stitched(_)) && crate_graph.patch_cfg_if() {
-            debug!("Patched std to depend on cfg-if")
-        } else {
-            debug!("Did not patch std to depend on cfg-if")
-        }
         (crate_graph, proc_macros)
     }
 

From 4f148903946cfe771cfa2bce92cb9e3d2a706b21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= 
Date: Mon, 9 Dec 2024 12:07:11 +0100
Subject: [PATCH 119/197] Configure renovatebot

---
 .github/renovate.json5 | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 .github/renovate.json5

diff --git a/.github/renovate.json5 b/.github/renovate.json5
new file mode 100644
index 000000000000..87f5f103ddfc
--- /dev/null
+++ b/.github/renovate.json5
@@ -0,0 +1,14 @@
+{
+  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+  // Let Renovatebot keep an opened issue that tracks our dependencies
+  "dependencyDashboard": true,
+  // Disable "normal" package updates
+  "enabledManagers": [],
+  // Update lockfiles once per week
+  "lockFileMaintenance": {
+    "enabled": true,
+    "schedule": [
+      "before 5am on Tuesday"
+    ]
+  }
+}

From 15d7331a013ef4b5519d51bc323bbf7b54746d63 Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Tue, 3 Dec 2024 20:21:19 +0000
Subject: [PATCH 120/197] bootstrap: `print{,ln}!` -> `eprint{,ln}!`

---
 src/bootstrap/src/bin/main.rs                 | 20 +++----
 src/bootstrap/src/bin/rustc.rs                |  2 +-
 src/bootstrap/src/core/build_steps/check.rs   |  2 +-
 src/bootstrap/src/core/build_steps/compile.rs | 10 ++--
 src/bootstrap/src/core/build_steps/dist.rs    |  2 +-
 src/bootstrap/src/core/build_steps/format.rs  |  6 +-
 src/bootstrap/src/core/build_steps/setup.rs   | 46 +++++++-------
 src/bootstrap/src/core/build_steps/suggest.rs |  2 +-
 src/bootstrap/src/core/build_steps/test.rs    |  6 +-
 src/bootstrap/src/core/builder/cargo.rs       |  2 +-
 src/bootstrap/src/core/builder/mod.rs         | 14 +++--
 src/bootstrap/src/core/config/config.rs       | 60 +++++++++----------
 src/bootstrap/src/core/config/flags.rs        |  4 +-
 src/bootstrap/src/core/download.rs            | 26 ++++----
 src/bootstrap/src/core/sanity.rs              |  4 +-
 src/bootstrap/src/lib.rs                      | 28 ++++-----
 src/bootstrap/src/utils/cc_detect.rs          | 10 ++--
 src/bootstrap/src/utils/helpers.rs            |  6 +-
 src/bootstrap/src/utils/metrics.rs            |  2 +-
 src/bootstrap/src/utils/render_tests.rs       | 50 ++++++++--------
 src/bootstrap/src/utils/tarball.rs            |  2 +-
 21 files changed, 154 insertions(+), 150 deletions(-)

diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs
index ee813de1c9e2..74dfe2e7ec80 100644
--- a/src/bootstrap/src/bin/main.rs
+++ b/src/bootstrap/src/bin/main.rs
@@ -48,9 +48,9 @@ fn main() {
             err => {
                 drop(err);
                 if let Ok(pid) = pid {
-                    println!("WARNING: build directory locked by process {pid}, waiting for lock");
+                    eprintln!("WARNING: build directory locked by process {pid}, waiting for lock");
                 } else {
-                    println!("WARNING: build directory locked, waiting for lock");
+                    eprintln!("WARNING: build directory locked, waiting for lock");
                 }
                 let mut lock = t!(build_lock.write());
                 t!(lock.write(process::id().to_string().as_ref()));
@@ -70,13 +70,13 @@ fn main() {
     // changelog warning, not the `x.py setup` message.
     let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. });
     if suggest_setup {
-        println!("WARNING: you have not made a `config.toml`");
-        println!(
+        eprintln!("WARNING: you have not made a `config.toml`");
+        eprintln!(
             "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \
             `cp config.example.toml config.toml`"
         );
     } else if let Some(suggestion) = &changelog_suggestion {
-        println!("{suggestion}");
+        eprintln!("{suggestion}");
     }
 
     let pre_commit = config.src.join(".git").join("hooks").join("pre-commit");
@@ -86,13 +86,13 @@ fn main() {
     Build::new(config).build();
 
     if suggest_setup {
-        println!("WARNING: you have not made a `config.toml`");
-        println!(
+        eprintln!("WARNING: you have not made a `config.toml`");
+        eprintln!(
             "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \
             `cp config.example.toml config.toml`"
         );
     } else if let Some(suggestion) = &changelog_suggestion {
-        println!("{suggestion}");
+        eprintln!("{suggestion}");
     }
 
     // Give a warning if the pre-commit script is in pre-commit and not pre-push.
@@ -102,14 +102,14 @@ fn main() {
     if fs::read_to_string(pre_commit).is_ok_and(|contents| {
         contents.contains("https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570")
     }) {
-        println!(
+        eprintln!(
             "WARNING: You have the pre-push script installed to .git/hooks/pre-commit. \
                   Consider moving it to .git/hooks/pre-push instead, which runs less often."
         );
     }
 
     if suggest_setup || changelog_suggestion.is_some() {
-        println!("NOTE: this message was printed twice to make it more likely to be seen");
+        eprintln!("NOTE: this message was printed twice to make it more likely to be seen");
     }
 
     if dump_bootstrap_shims {
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 88595ff7e519..e57ed488f973 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -306,7 +306,7 @@ fn main() {
         // should run on success, after this block.
     }
     if verbose > 0 {
-        println!("\nDid not run successfully: {status}\n{cmd:?}\n-------------");
+        eprintln!("\nDid not run successfully: {status}\n{cmd:?}\n-------------");
     }
 
     if let Some(mut on_fail) = on_fail {
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index d46c0ab7fefc..2af2e83db8f7 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -287,7 +287,7 @@ impl Step for CodegenBackend {
     fn run(self, builder: &Builder<'_>) {
         // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved
         if builder.build.config.vendor && self.backend == "gcc" {
-            println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
+            eprintln!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled.");
             return;
         }
 
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 0cacd6e4f37a..4419b11ac197 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1611,7 +1611,7 @@ impl Step for Sysroot {
         let sysroot = sysroot_dir(compiler.stage);
 
         builder
-            .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
+            .verbose(|| eprintln!("Removing sysroot {} to avoid caching bugs", sysroot.display()));
         let _ = fs::remove_dir_all(&sysroot);
         t!(fs::create_dir_all(&sysroot));
 
@@ -1681,7 +1681,7 @@ impl Step for Sysroot {
                     return true;
                 }
                 if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) {
-                    builder.verbose_than(1, || println!("ignoring {}", path.display()));
+                    builder.verbose_than(1, || eprintln!("ignoring {}", path.display()));
                     false
                 } else {
                     true
@@ -2240,7 +2240,7 @@ pub fn stream_cargo(
         cargo.arg(arg);
     }
 
-    builder.verbose(|| println!("running: {cargo:?}"));
+    builder.verbose(|| eprintln!("running: {cargo:?}"));
 
     if builder.config.dry_run() {
         return true;
@@ -2261,12 +2261,12 @@ pub fn stream_cargo(
             Ok(msg) => {
                 if builder.config.json_output {
                     // Forward JSON to stdout.
-                    println!("{line}");
+                    eprintln!("{line}");
                 }
                 cb(msg)
             }
             // If this was informational, just print it out and continue
-            Err(_) => println!("{line}"),
+            Err(_) => eprintln!("{line}"),
         }
     }
 
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 0c739115165e..57fce206f954 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -2080,7 +2080,7 @@ fn maybe_install_llvm(
     {
         let mut cmd = command(llvm_config);
         cmd.arg("--libfiles");
-        builder.verbose(|| println!("running {cmd:?}"));
+        builder.verbose(|| eprintln!("running {cmd:?}"));
         let files = cmd.run_capture_stdout(builder).stdout();
         let build_llvm_out = &builder.llvm_out(builder.config.build);
         let target_llvm_out = &builder.llvm_out(target);
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 29a96f776728..d32e06d8748a 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -107,10 +107,10 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
         if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() };
     if len <= 10 {
         for path in paths {
-            println!("fmt: {verb} {adjective}file {path}");
+            eprintln!("fmt: {verb} {adjective}file {path}");
         }
     } else {
-        println!("fmt: {verb} {len} {adjective}files");
+        eprintln!("fmt: {verb} {len} {adjective}files");
     }
 }
 
@@ -199,7 +199,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
                 match get_modified_rs_files(build) {
                     Ok(Some(files)) => {
                         if files.is_empty() {
-                            println!("fmt info: No modified files detected for formatting.");
+                            eprintln!("fmt info: No modified files detected for formatting.");
                             return;
                         }
 
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 7ed01f25c94b..175e9982cc14 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -134,7 +134,7 @@ impl Step for Profile {
                     t!(fs::remove_file(path));
                 }
                 _ => {
-                    println!("Exiting.");
+                    eprintln!("Exiting.");
                     crate::exit!(1);
                 }
             }
@@ -184,15 +184,15 @@ pub fn setup(config: &Config, profile: Profile) {
         Profile::Dist => &["dist", "build"],
     };
 
-    println!();
+    eprintln!();
 
-    println!("To get started, try one of the following commands:");
+    eprintln!("To get started, try one of the following commands:");
     for cmd in suggestions {
-        println!("- `x.py {cmd}`");
+        eprintln!("- `x.py {cmd}`");
     }
 
     if profile != Profile::Dist {
-        println!(
+        eprintln!(
             "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
         );
     }
@@ -224,7 +224,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
     t!(fs::write(path, settings));
 
     let include_path = profile.include_path(&config.src);
-    println!("`x.py` will now use the configuration at {}", include_path.display());
+    eprintln!("`x.py` will now use the configuration at {}", include_path.display());
 }
 
 /// Creates a toolchain link for stage1 using `rustup`
@@ -256,7 +256,7 @@ impl Step for Link {
         }
 
         if !rustup_installed(builder) {
-            println!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking.");
+            eprintln!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking.");
             return;
         }
 
@@ -296,7 +296,7 @@ fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) {
     }
 
     if try_link_toolchain(builder, stage_path) {
-        println!(
+        eprintln!(
             "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
         );
     } else {
@@ -321,14 +321,14 @@ fn toolchain_is_linked(builder: &Builder<'_>) -> bool {
                 return false;
             }
             // The toolchain has already been linked.
-            println!(
+            eprintln!(
                 "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
             );
         }
         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!(
+            eprintln!(
                 "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"
             );
         }
@@ -389,12 +389,12 @@ pub fn interactive_path() -> io::Result {
         input.parse()
     }
 
-    println!("Welcome to the Rust project! What do you want to do with x.py?");
+    eprintln!("Welcome to the Rust project! What do you want to do with x.py?");
     for ((letter, _), profile) in abbrev_all() {
-        println!("{}) {}: {}", letter, profile, profile.purpose());
+        eprintln!("{}) {}: {}", letter, profile, profile.purpose());
     }
     let template = loop {
-        print!(
+        eprint!(
             "Please choose one ({}): ",
             abbrev_all().map(|((l, _), _)| l).collect::>().join("/")
         );
@@ -428,7 +428,7 @@ enum PromptResult {
 fn prompt_user(prompt: &str) -> io::Result> {
     let mut input = String::new();
     loop {
-        print!("{prompt} ");
+        eprint!("{prompt} ");
         io::stdout().flush()?;
         input.clear();
         io::stdin().read_line(&mut input)?;
@@ -490,7 +490,7 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result<
         return Ok(());
     }
 
-    println!(
+    eprintln!(
         "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
 If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
 pushing your code to ensure your code is up to par. If you decide later that this behavior is
@@ -498,7 +498,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
     );
 
     if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
-        println!("Ok, skipping installation!");
+        eprintln!("Ok, skipping installation!");
         return Ok(());
     }
     if !hooks_dir.exists() {
@@ -515,7 +515,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
             );
             return Err(e);
         }
-        Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+        Ok(_) => eprintln!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
     };
     Ok(())
 }
@@ -541,7 +541,7 @@ Select which editor you would like to set up [default: None]: ";
 
         let mut input = String::new();
         loop {
-            print!("{}", prompt_str);
+            eprint!("{}", prompt_str);
             io::stdout().flush()?;
             input.clear();
             io::stdin().read_line(&mut input)?;
@@ -656,7 +656,7 @@ impl Step for Editor {
                 if let Some(editor_kind) = editor_kind {
                     while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {}
                 } else {
-                    println!("Ok, skipping editor setup!");
+                    eprintln!("Ok, skipping editor setup!");
                 }
             }
             Err(e) => eprintln!("Could not determine the editor: {e}"),
@@ -689,7 +689,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
             mismatched_settings = Some(false);
         }
     }
-    println!(
+    eprintln!(
         "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development"
     );
 
@@ -708,7 +708,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
         Some(PromptResult::Yes) => true,
         Some(PromptResult::Print) => false,
         _ => {
-            println!("Ok, skipping settings!");
+            eprintln!("Ok, skipping settings!");
             return Ok(true);
         }
     };
@@ -735,9 +735,9 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu
             _ => "Created",
         };
         fs::write(&settings_path, editor.settings_template())?;
-        println!("{verb} `{}`", settings_filename);
+        eprintln!("{verb} `{}`", settings_filename);
     } else {
-        println!("\n{}", editor.settings_template());
+        eprintln!("\n{}", editor.settings_template());
     }
     Ok(should_create)
 }
diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs
index ba9b1b2fc331..7b2d9fff8f5f 100644
--- a/src/bootstrap/src/core/build_steps/suggest.rs
+++ b/src/bootstrap/src/core/build_steps/suggest.rs
@@ -66,6 +66,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
             build.build();
         }
     } else {
-        println!("HELP: consider using the `--run` flag to automatically run suggested tests");
+        eprintln!("HELP: consider using the `--run` flag to automatically run suggested tests");
     }
 }
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 30fdea7e19e5..380626952b25 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -471,11 +471,11 @@ impl Miri {
         // We re-use the `cargo` from above.
         cargo.arg("--print-sysroot");
 
-        builder.verbose(|| println!("running: {cargo:?}"));
+        builder.verbose(|| eprintln!("running: {cargo:?}"));
         let stdout = cargo.run_capture_stdout(builder).stdout();
         // Output is "\n".
         let sysroot = stdout.trim_end();
-        builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
+        builder.verbose(|| eprintln!("`cargo miri setup --print-sysroot` said: {sysroot:?}"));
         PathBuf::from(sysroot)
     }
 }
@@ -2488,7 +2488,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) ->
         }
     }
 
-    builder.verbose(|| println!("doc tests for: {}", markdown.display()));
+    builder.verbose(|| eprintln!("doc tests for: {}", markdown.display()));
     let mut cmd = builder.rustdoc_cmd(compiler);
     builder.add_rust_test_threads(&mut cmd);
     // allow for unstable options such as new editions
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 77f6edaabb24..38abca8b8da1 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -523,7 +523,7 @@ impl Builder<'_> {
 
         let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
         if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
-            println!("using sysroot {sysroot_str}");
+            eprintln!("using sysroot {sysroot_str}");
         }
 
         let mut rustflags = Rustflags::new(target);
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 026c26479d35..ffe3e053e724 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -392,14 +392,14 @@ impl StepDescription {
     fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
         if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) {
             if !matches!(builder.config.dry_run, DryRun::SelfCheck) {
-                println!("Skipping {pathset:?} because it is excluded");
+                eprintln!("Skipping {pathset:?} because it is excluded");
             }
             return true;
         }
 
         if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) {
             builder.verbose(|| {
-                println!(
+                eprintln!(
                     "{:?} not skipped for {:?} -- not in {:?}",
                     pathset, self.name, builder.config.skip
                 )
@@ -1437,11 +1437,11 @@ impl<'a> Builder<'a> {
                 panic!("{}", out);
             }
             if let Some(out) = self.cache.get(&step) {
-                self.verbose_than(1, || println!("{}c {:?}", "  ".repeat(stack.len()), step));
+                self.verbose_than(1, || eprintln!("{}c {:?}", "  ".repeat(stack.len()), step));
 
                 return out;
             }
-            self.verbose_than(1, || println!("{}> {:?}", "  ".repeat(stack.len()), step));
+            self.verbose_than(1, || eprintln!("{}> {:?}", "  ".repeat(stack.len()), step));
             stack.push(Box::new(step.clone()));
         }
 
@@ -1462,7 +1462,7 @@ impl<'a> Builder<'a> {
             let step_string = format!("{step:?}");
             let brace_index = step_string.find('{').unwrap_or(0);
             let type_string = type_name::();
-            println!(
+            eprintln!(
                 "[TIMING] {} {} -- {}.{:03}",
                 &type_string.strip_prefix("bootstrap::").unwrap_or(type_string),
                 &step_string[brace_index..],
@@ -1479,7 +1479,9 @@ impl<'a> Builder<'a> {
             let cur_step = stack.pop().expect("step stack empty");
             assert_eq!(cur_step.downcast_ref(), Some(&step));
         }
-        self.verbose_than(1, || println!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), step));
+        self.verbose_than(1, || {
+            eprintln!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), step)
+        });
         self.cache.put(step, out.clone());
         out
     }
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index b06147055f2a..aa5cce2fb1b6 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1293,7 +1293,7 @@ impl Config {
                     .map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids))
                 {
                     if !changes.is_empty() {
-                        println!(
+                        eprintln!(
                             "WARNING: There have been changes to x.py since you last updated:\n{}",
                             crate::human_readable_changes(&changes)
                         );
@@ -1559,7 +1559,7 @@ impl Config {
         }
 
         if cargo_clippy.is_some() && rustc.is_none() {
-            println!(
+            eprintln!(
                 "WARNING: Using `build.cargo-clippy` without `build.rustc` usually fails due to toolchain conflict."
             );
         }
@@ -1841,7 +1841,7 @@ impl Config {
 
             // FIXME: Remove this option at the end of 2024.
             if parallel_compiler.is_some() {
-                println!(
+                eprintln!(
                     "WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default"
                 );
             }
@@ -1873,7 +1873,7 @@ impl Config {
                         if available_backends.contains(&backend) {
                             panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'.");
                         } else {
-                            println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
+                            eprintln!("HELP: '{s}' for 'rust.codegen-backends' might fail. \
                                 Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
                                 In this case, it would be referred to as '{backend}'.");
                         }
@@ -1902,7 +1902,7 @@ impl Config {
         // tests may fail due to using a different channel than the one used by the compiler during tests.
         if let Some(commit) = &config.download_rustc_commit {
             if is_user_configured_rust_channel {
-                println!(
+                eprintln!(
                     "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
                 );
 
@@ -1992,10 +1992,10 @@ impl Config {
 
             if config.llvm_from_ci {
                 let warn = |option: &str| {
-                    println!(
+                    eprintln!(
                         "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build."
                     );
-                    println!(
+                    eprintln!(
                         "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false."
                     );
                 };
@@ -2014,12 +2014,12 @@ impl Config {
                 // if they've chosen a different value.
 
                 if libzstd.is_some() {
-                    println!(
+                    eprintln!(
                         "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \
                         like almost all `llvm.*` options, will be ignored and set by the LLVM CI \
                         artifacts builder config."
                     );
-                    println!(
+                    eprintln!(
                         "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false."
                     );
                 }
@@ -2088,7 +2088,7 @@ impl Config {
                             if available_backends.contains(&backend) {
                                 panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'.");
                             } else {
-                                println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
+                                eprintln!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \
                                     Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
                                     In this case, it would be referred to as '{backend}'.");
                             }
@@ -2304,7 +2304,7 @@ impl Config {
         if self.dry_run() {
             return Ok(());
         }
-        self.verbose(|| println!("running: {cmd:?}"));
+        self.verbose(|| eprintln!("running: {cmd:?}"));
         build_helper::util::try_run(cmd, self.is_verbose())
     }
 
@@ -2479,7 +2479,7 @@ impl Config {
                         // This happens when LLVM submodule is updated in CI, we should disable ci-rustc without an error
                         // to not break CI. For non-CI environments, we should return an error.
                         if CiEnv::is_ci() {
-                            println!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled.");
+                            eprintln!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled.");
                             return None;
                         } else {
                             panic!("ERROR: LLVM submodule has changes, `download-rustc` can't be used.");
@@ -2490,8 +2490,8 @@ impl Config {
                         let ci_config_toml = match self.get_builder_toml("ci-rustc") {
                             Ok(ci_config_toml) => ci_config_toml,
                             Err(e) if e.to_string().contains("unknown field") => {
-                                println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
-                                println!("HELP: Consider rebasing to a newer commit if available.");
+                                eprintln!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
+                                eprintln!("HELP: Consider rebasing to a newer commit if available.");
                                 return None;
                             },
                             Err(e) => {
@@ -2516,7 +2516,7 @@ impl Config {
                             .is_some_and(|s| s == "1" || s == "true");
 
                         if disable_ci_rustc_if_incompatible && res.is_err() {
-                            println!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env.");
+                            eprintln!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env.");
                             return None;
                         }
 
@@ -2701,7 +2701,7 @@ impl Config {
             return;
         }
 
-        println!("Updating submodule {relative_path}");
+        eprintln!("Updating submodule {relative_path}");
         self.check_run(
             helpers::git(Some(&self.src))
                 .run_always()
@@ -2824,7 +2824,7 @@ impl Config {
             Some(StringOrBool::Bool(true)) => false,
             Some(StringOrBool::String(s)) if s == "if-unchanged" => {
                 if !self.rust_info.is_managed_git_subrepository() {
-                    println!(
+                    eprintln!(
                         "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
                     );
                     crate::exit!(1);
@@ -2857,10 +2857,10 @@ impl Config {
                 if if_unchanged {
                     return None;
                 }
-                println!("ERROR: could not find commit hash for downloading rustc");
-                println!("HELP: maybe your repository history is too shallow?");
-                println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
-                println!("HELP: or fetch enough history to include one upstream commit");
+                eprintln!("ERROR: could not find commit hash for downloading rustc");
+                eprintln!("HELP: maybe your repository history is too shallow?");
+                eprintln!("HELP: consider setting `rust.download-rustc=false` in config.toml");
+                eprintln!("HELP: or fetch enough history to include one upstream commit");
                 crate::exit!(1);
             }
         };
@@ -2899,7 +2899,7 @@ impl Config {
         let if_unchanged = || {
             if self.rust_info.is_from_tarball() {
                 // Git is needed for running "if-unchanged" logic.
-                println!(
+                eprintln!(
                     "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`."
                 );
                 return false;
@@ -2948,10 +2948,10 @@ impl Config {
         // Only commits merged by bors will have CI artifacts.
         let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
         if commit.is_empty() {
-            println!("error: could not find commit hash for downloading components from CI");
-            println!("help: maybe your repository history is too shallow?");
-            println!("help: consider disabling `{option_name}`");
-            println!("help: or fetch enough history to include one upstream commit");
+            eprintln!("error: could not find commit hash for downloading components from CI");
+            eprintln!("help: maybe your repository history is too shallow?");
+            eprintln!("help: consider disabling `{option_name}`");
+            eprintln!("help: or fetch enough history to include one upstream commit");
             crate::exit!(1);
         }
 
@@ -2963,14 +2963,14 @@ impl Config {
         if has_changes {
             if if_unchanged {
                 if self.is_verbose() {
-                    println!(
+                    eprintln!(
                         "warning: saw changes to one of {modified_paths:?} since {commit}; \
                             ignoring `{option_name}`"
                     );
                 }
                 return None;
             }
-            println!(
+            eprintln!(
                 "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}"
             );
         }
@@ -3007,7 +3007,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm(
         ($current:expr, $expected:expr) => {
             if let Some(current) = &$current {
                 if Some(current) != $expected.as_ref() {
-                    println!(
+                    eprintln!(
                         "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \
                         Current value: {:?}, Expected value(s): {}{:?}",
                         stringify!($expected).replace("_", "-"),
@@ -3112,7 +3112,7 @@ fn check_incompatible_options_for_ci_rustc(
         ($current:expr, $expected:expr, $config_section:expr) => {
             if let Some(current) = &$current {
                 if Some(current) != $expected.as_ref() {
-                    println!(
+                    eprintln!(
                         "WARNING: `{}` has no effect with `rust.download-rustc`. \
                         Current value: {:?}, Expected value(s): {}{:?}",
                         format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index bfeb811508c0..66b9f5ed84e6 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -196,12 +196,12 @@ impl Flags {
         if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
             HelpVerboseOnly::try_parse_from(normalize_args(args))
         {
-            println!("NOTE: updating submodules before printing available paths");
+            eprintln!("NOTE: updating submodules before printing available paths");
             let config = Config::parse(Self::parse(&[String::from("build")]));
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
             if let Some(s) = paths {
-                println!("{s}");
+                eprintln!("{s}");
             } else {
                 panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index db35e6907e66..05b91c518cf4 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -77,7 +77,7 @@ impl Config {
         if self.dry_run() && !cmd.run_always {
             return true;
         }
-        self.verbose(|| println!("running: {cmd:?}"));
+        self.verbose(|| eprintln!("running: {cmd:?}"));
         check_run(cmd, self.is_verbose())
     }
 
@@ -144,7 +144,7 @@ impl Config {
     /// Please see  for more information
     fn fix_bin_or_dylib(&self, fname: &Path) {
         assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true));
-        println!("attempting to patch {}", fname.display());
+        eprintln!("attempting to patch {}", fname.display());
 
         // Only build `.nix-deps` once.
         static NIX_DEPS_DIR: OnceLock = OnceLock::new();
@@ -206,7 +206,7 @@ impl Config {
     }
 
     fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
-        self.verbose(|| println!("download {url}"));
+        self.verbose(|| eprintln!("download {url}"));
         // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
         let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
         // While bootstrap itself only supports http and https downloads, downstream forks might
@@ -226,7 +226,7 @@ impl Config {
     }
 
     fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) {
-        println!("downloading {url}");
+        eprintln!("downloading {url}");
         // Try curl. If that fails and we are on windows, fallback to PowerShell.
         // options should be kept in sync with
         // src/bootstrap/src/core/download.rs
@@ -341,7 +341,7 @@ impl Config {
             short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
             let dst_path = dst.join(short_path);
             self.verbose(|| {
-                println!("extracting {} to {}", original_path.display(), dst.display())
+                eprintln!("extracting {} to {}", original_path.display(), dst.display())
             });
             if !t!(member.unpack_in(dst)) {
                 panic!("path traversal attack ??");
@@ -365,7 +365,7 @@ impl Config {
     pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool {
         use sha2::Digest;
 
-        self.verbose(|| println!("verifying {}", path.display()));
+        self.verbose(|| eprintln!("verifying {}", path.display()));
 
         if self.dry_run() {
             return false;
@@ -391,7 +391,7 @@ impl Config {
         let verified = checksum == expected;
 
         if !verified {
-            println!(
+            eprintln!(
                 "invalid checksum: \n\
                 found:    {checksum}\n\
                 expected: {expected}",
@@ -421,7 +421,7 @@ enum DownloadSource {
 /// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
 impl Config {
     pub(crate) fn download_clippy(&self) -> PathBuf {
-        self.verbose(|| println!("downloading stage0 clippy artifacts"));
+        self.verbose(|| eprintln!("downloading stage0 clippy artifacts"));
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
@@ -518,7 +518,7 @@ impl Config {
     }
 
     pub(crate) fn download_ci_rustc(&self, commit: &str) {
-        self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})"));
+        self.verbose(|| eprintln!("using downloaded stage2 artifacts from CI (commit {commit})"));
 
         let version = self.artifact_version_part(commit);
         // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the
@@ -539,7 +539,7 @@ impl Config {
 
     #[cfg(not(feature = "bootstrap-self-test"))]
     pub(crate) fn download_beta_toolchain(&self) {
-        self.verbose(|| println!("downloading stage0 beta artifacts"));
+        self.verbose(|| eprintln!("downloading stage0 beta artifacts"));
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
@@ -677,7 +677,7 @@ impl Config {
                     return;
                 } else {
                     self.verbose(|| {
-                        println!(
+                        eprintln!(
                             "ignoring cached file {} due to failed verification",
                             tarball.display()
                         )
@@ -776,10 +776,10 @@ download-rustc = false
                     t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml));
                 }
                 Err(e) if e.to_string().contains("unknown field") => {
-                    println!(
+                    eprintln!(
                         "WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled."
                     );
-                    println!("HELP: Consider rebasing to a newer commit if available.");
+                    eprintln!("HELP: Consider rebasing to a newer commit if available.");
                 }
                 Err(e) => {
                     eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}");
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index dcf68cbeeda7..71e7f40f0320 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -237,11 +237,11 @@ than building it.
                 stage0_supported_target_list.intersection(&missing_targets_hashset).collect();
 
             if !duplicated_targets.is_empty() {
-                println!(
+                eprintln!(
                     "Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list."
                 );
                 for duplicated_target in duplicated_targets {
-                    println!("  {duplicated_target}");
+                    eprintln!("  {duplicated_target}");
                 }
                 std::process::exit(1);
             }
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 0ecf61ffcd90..5f778223d7da 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -406,11 +406,11 @@ impl Build {
             .unwrap()
             .trim();
         if local_release.split('.').take(2).eq(version.split('.').take(2)) {
-            build.verbose(|| println!("auto-detected local-rebuild {local_release}"));
+            build.verbose(|| eprintln!("auto-detected local-rebuild {local_release}"));
             build.local_rebuild = true;
         }
 
-        build.verbose(|| println!("finding compilers"));
+        build.verbose(|| eprintln!("finding compilers"));
         utils::cc_detect::find(&build);
         // When running `setup`, the profile is about to change, so any requirements we have now may
         // be different on the next invocation. Don't check for them until the next time x.py is
@@ -418,7 +418,7 @@ impl Build {
         //
         // Similarly, for `setup` we don't actually need submodules or cargo metadata.
         if !matches!(build.config.cmd, Subcommand::Setup { .. }) {
-            build.verbose(|| println!("running sanity check"));
+            build.verbose(|| eprintln!("running sanity check"));
             crate::core::sanity::check(&mut build);
 
             // Make sure we update these before gathering metadata so we don't get an error about missing
@@ -436,7 +436,7 @@ impl Build {
             // Now, update all existing submodules.
             build.update_existing_submodules();
 
-            build.verbose(|| println!("learning about cargo"));
+            build.verbose(|| eprintln!("learning about cargo"));
             crate::core::metadata::build(&mut build);
         }
 
@@ -605,7 +605,7 @@ impl Build {
         let stamp = dir.join(".stamp");
         let mut cleared = false;
         if mtime(&stamp) < mtime(input) {
-            self.verbose(|| println!("Dirty - {}", dir.display()));
+            self.verbose(|| eprintln!("Dirty - {}", dir.display()));
             let _ = fs::remove_dir_all(dir);
             cleared = true;
         } else if stamp.exists() {
@@ -890,7 +890,7 @@ impl Build {
         let executed_at = std::panic::Location::caller();
 
         self.verbose(|| {
-            println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
+            eprintln!("running: {command:?} (created at {created_at}, executed at {executed_at})")
         });
 
         let cmd = command.as_command_mut();
@@ -947,7 +947,7 @@ Executed at: {executed_at}"#,
 
         let fail = |message: &str, output: CommandOutput| -> ! {
             if self.is_verbose() {
-                println!("{message}");
+                eprintln!("{message}");
             } else {
                 let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
                 // If the command captures output, the user would not see any indication that
@@ -957,16 +957,16 @@ Executed at: {executed_at}"#,
                     if let Some(stdout) =
                         output.stdout_if_present().take_if(|s| !s.trim().is_empty())
                     {
-                        println!("STDOUT:\n{stdout}\n");
+                        eprintln!("STDOUT:\n{stdout}\n");
                     }
                     if let Some(stderr) =
                         output.stderr_if_present().take_if(|s| !s.trim().is_empty())
                     {
-                        println!("STDERR:\n{stderr}\n");
+                        eprintln!("STDERR:\n{stderr}\n");
                     }
-                    println!("Command {command:?} has failed. Rerun with -v to see more details.");
+                    eprintln!("Command {command:?} has failed. Rerun with -v to see more details.");
                 } else {
-                    println!("Command has failed. Rerun with -v to see more details.");
+                    eprintln!("Command has failed. Rerun with -v to see more details.");
                 }
             }
             exit!(1);
@@ -1011,7 +1011,7 @@ Executed at: {executed_at}"#,
         match self.config.dry_run {
             DryRun::SelfCheck => (),
             DryRun::Disabled | DryRun::UserSelected => {
-                println!("{msg}");
+                eprintln!("{msg}");
             }
         }
     }
@@ -1666,7 +1666,7 @@ Executed at: {executed_at}"#,
         if self.config.dry_run() {
             return;
         }
-        self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}"));
+        self.verbose_than(1, || eprintln!("Copy/Link {src:?} to {dst:?}"));
         if src == dst {
             return;
         }
@@ -1775,7 +1775,7 @@ Executed at: {executed_at}"#,
             return;
         }
         let dst = dstdir.join(src.file_name().unwrap());
-        self.verbose_than(1, || println!("Install {src:?} to {dst:?}"));
+        self.verbose_than(1, || eprintln!("Install {src:?} to {dst:?}"));
         t!(fs::create_dir_all(dstdir));
         if !src.exists() {
             panic!("ERROR: File \"{}\" not found!", src.display());
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 0df004694522..e8d5b60948aa 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -155,15 +155,15 @@ pub fn find_target(build: &Build, target: TargetSelection) {
         build.cxx.borrow_mut().insert(target, compiler);
     }
 
-    build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
-    build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
+    build.verbose(|| eprintln!("CC_{} = {:?}", target.triple, build.cc(target)));
+    build.verbose(|| eprintln!("CFLAGS_{} = {cflags:?}", target.triple));
     if let Ok(cxx) = build.cxx(target) {
         let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
-        build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
-        build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
+        build.verbose(|| eprintln!("CXX_{} = {cxx:?}", target.triple));
+        build.verbose(|| eprintln!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
     }
     if let Some(ar) = ar {
-        build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
+        build.verbose(|| eprintln!("AR_{} = {ar:?}", target.triple));
         build.ar.borrow_mut().insert(target, ar);
     }
 
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 923cc2dfc28c..c0d52fd34305 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -135,7 +135,7 @@ impl Drop for TimeIt {
     fn drop(&mut self) {
         let time = self.1.elapsed();
         if !self.0 {
-            println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis());
+            eprintln!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis());
         }
     }
 }
@@ -267,12 +267,12 @@ pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool {
     let status = match cmd.as_command_mut().status() {
         Ok(status) => status,
         Err(e) => {
-            println!("failed to execute command: {cmd:?}\nERROR: {e}");
+            eprintln!("failed to execute command: {cmd:?}\nERROR: {e}");
             return false;
         }
     };
     if !status.success() && print_cmd_on_fail {
-        println!(
+        eprintln!(
             "\n\ncommand did not execute successfully: {cmd:?}\n\
              expected success, got: {status}\n\n"
         );
diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs
index b51fd490535a..06d3add6281f 100644
--- a/src/bootstrap/src/utils/metrics.rs
+++ b/src/bootstrap/src/utils/metrics.rs
@@ -185,7 +185,7 @@ impl BuildMetrics {
                 if version.format_version == CURRENT_FORMAT_VERSION {
                     t!(serde_json::from_slice::(&contents)).invocations
                 } else {
-                    println!(
+                    eprintln!(
                         "WARNING: overriding existing build/metrics.json, as it's not \
                          compatible with build metrics format version {CURRENT_FORMAT_VERSION}."
                     );
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index eb2c8254dc0f..7a3ec61c6da0 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -56,7 +56,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) ->
     let cmd = cmd.as_command_mut();
     cmd.stdout(Stdio::piped());
 
-    builder.verbose(|| println!("running: {cmd:?}"));
+    builder.verbose(|| eprintln!("running: {cmd:?}"));
 
     let mut process = cmd.spawn().unwrap();
 
@@ -71,7 +71,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) ->
 
     let result = process.wait_with_output().unwrap();
     if !result.status.success() && builder.is_verbose() {
-        println!(
+        eprintln!(
             "\n\ncommand did not execute successfully: {cmd:?}\n\
              expected success, got: {}",
             result.status
@@ -135,7 +135,9 @@ impl<'a> Renderer<'a> {
         if self.up_to_date_tests > 0 {
             let n = self.up_to_date_tests;
             let s = if n > 1 { "s" } else { "" };
-            println!("help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n");
+            eprintln!(
+                "help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n"
+            );
         }
     }
 
@@ -185,12 +187,12 @@ impl<'a> Renderer<'a> {
     }
 
     fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) {
-        print!("test {} ... ", test.name);
-        self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
+        eprint!("test {} ... ", test.name);
+        self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap();
         if let Some(exec_time) = test.exec_time {
-            print!(" ({exec_time:.2?})");
+            eprint!(" ({exec_time:.2?})");
         }
-        println!();
+        eprintln!();
     }
 
     fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) {
@@ -198,45 +200,45 @@ impl<'a> Renderer<'a> {
             if let Some(total) = self.tests_count {
                 let total = total.to_string();
                 let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len());
-                print!(" {executed}/{total}");
+                eprint!(" {executed}/{total}");
             }
-            println!();
+            eprintln!();
             self.terse_tests_in_line = 0;
         }
 
         self.terse_tests_in_line += 1;
-        self.builder.colored_stdout(|stdout| outcome.write_short(stdout, &test.name)).unwrap();
+        self.builder.colored_stderr(|stdout| outcome.write_short(stdout, &test.name)).unwrap();
         let _ = std::io::stdout().flush();
     }
 
     fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) {
         // The terse output doesn't end with a newline, so we need to add it ourselves.
         if !self.builder.config.verbose_tests {
-            println!();
+            eprintln!();
         }
 
         if !self.failures.is_empty() {
-            println!("\nfailures:\n");
+            eprintln!("\nfailures:\n");
             for failure in &self.failures {
                 if failure.stdout.is_some() || failure.message.is_some() {
-                    println!("---- {} stdout ----", failure.name);
+                    eprintln!("---- {} stdout ----", failure.name);
                     if let Some(stdout) = &failure.stdout {
-                        println!("{stdout}");
+                        eprintln!("{stdout}");
                     }
                     if let Some(message) = &failure.message {
-                        println!("NOTE: {message}");
+                        eprintln!("NOTE: {message}");
                     }
                 }
             }
 
-            println!("\nfailures:");
+            eprintln!("\nfailures:");
             for failure in &self.failures {
-                println!("    {}", failure.name);
+                eprintln!("    {}", failure.name);
             }
         }
 
         if !self.benches.is_empty() {
-            println!("\nbenchmarks:");
+            eprintln!("\nbenchmarks:");
 
             let mut rows = Vec::new();
             for bench in &self.benches {
@@ -251,13 +253,13 @@ impl<'a> Renderer<'a> {
             let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0);
             let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0);
             for row in &rows {
-                println!("    {:max_1$} {:>max_2$}", row.0, row.1, row.2);
+                eprintln!("    {:max_1$} {:>max_2$}", row.0, row.1, row.2);
             }
         }
 
-        print!("\ntest result: ");
-        self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap();
-        println!(
+        eprint!("\ntest result: ");
+        self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap();
+        eprintln!(
             ". {} passed; {} failed; {} ignored; {} measured; {} filtered out{time}\n",
             suite.passed,
             suite.failed,
@@ -274,7 +276,7 @@ impl<'a> Renderer<'a> {
     fn render_message(&mut self, message: Message) {
         match message {
             Message::Suite(SuiteMessage::Started { test_count }) => {
-                println!("\nrunning {test_count} tests");
+                eprintln!("\nrunning {test_count} tests");
                 self.executed_tests = 0;
                 self.terse_tests_in_line = 0;
                 self.tests_count = Some(test_count);
@@ -314,7 +316,7 @@ impl<'a> Renderer<'a> {
                 self.failures.push(outcome);
             }
             Message::Test(TestMessage::Timeout { name }) => {
-                println!("test {name} has been running for a long time");
+                eprintln!("test {name} has been running for a long time");
             }
             Message::Test(TestMessage::Started) => {} // Not useful
         }
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 3c6c7a7fa180..f60498a4872c 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -344,7 +344,7 @@ impl<'a> Tarball<'a> {
         // For `x install` tarball files aren't needed, so we can speed up the process by not producing them.
         let compression_profile = if self.builder.kind == Kind::Install {
             self.builder.verbose(|| {
-                println!("Forcing dist.compression-profile = 'no-op' for `x install`.")
+                eprintln!("Forcing dist.compression-profile = 'no-op' for `x install`.")
             });
             // "no-op" indicates that the rust-installer won't produce compressed tarball sources.
             "no-op"

From a6c462863d0a73f0925aab2c9556db8b45a6e502 Mon Sep 17 00:00:00 2001
From: clubby789 
Date: Tue, 3 Dec 2024 20:21:51 +0000
Subject: [PATCH 121/197] compiletest: `print{,ln}!` -> `eprint{,ln}!`

Co-authored-by: Jieyou Xu 
---
 src/tools/compiletest/src/compute_diff.rs     |  2 +-
 src/tools/compiletest/src/debuggers.rs        |  6 +--
 src/tools/compiletest/src/lib.rs              | 10 ++--
 src/tools/compiletest/src/runtest.rs          | 52 +++++++++----------
 .../compiletest/src/runtest/codegen_units.rs  | 22 ++++----
 .../compiletest/src/runtest/debuginfo.rs      | 10 ++--
 .../compiletest/src/runtest/incremental.rs    |  2 +-
 src/tools/compiletest/src/runtest/mir_opt.rs  |  2 +-
 .../compiletest/src/runtest/rustdoc_json.rs   |  2 +-
 src/tools/compiletest/src/runtest/ui.rs       |  4 +-
 src/tools/compiletest/src/util.rs             |  2 +-
 11 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs
index 92c80c27de03..3ace6c5b6d71 100644
--- a/src/tools/compiletest/src/compute_diff.rs
+++ b/src/tools/compiletest/src/compute_diff.rs
@@ -144,7 +144,7 @@ where
     }
 
     if !wrote_data {
-        println!("note: diff is identical to nightly rustdoc");
+        eprintln!("note: diff is identical to nightly rustdoc");
         assert!(diff_output.metadata().unwrap().len() == 0);
         return false;
     } else if verbose {
diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs
index b605bc813f19..e75c8a5993e5 100644
--- a/src/tools/compiletest/src/debuggers.rs
+++ b/src/tools/compiletest/src/debuggers.rs
@@ -20,7 +20,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> {
     }
 
     if config.remote_test_client.is_some() && !config.target.contains("android") {
-        println!(
+        eprintln!(
             "WARNING: debuginfo tests are not available when \
              testing with remote"
         );
@@ -28,7 +28,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option> {
     }
 
     if config.target.contains("android") {
-        println!(
+        eprintln!(
             "{} debug-info test uses tcp 5039 port.\
              please reserve it",
             config.target
@@ -50,7 +50,7 @@ pub(crate) fn configure_lldb(config: &Config) -> Option> {
     config.lldb_python_dir.as_ref()?;
 
     if let Some(350) = config.lldb_version {
-        println!(
+        eprintln!(
             "WARNING: The used version of LLDB (350) has a \
              known issue that breaks debuginfo tests. See \
              issue #32520 for more information. Skipping all \
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index a5a166af33b6..9acb7d393b46 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -188,8 +188,8 @@ pub fn parse_config(args: Vec) -> Config {
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
         let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
+        eprintln!("{}", opts.usage(&message));
+        eprintln!();
         panic!()
     }
 
@@ -200,8 +200,8 @@ pub fn parse_config(args: Vec) -> Config {
 
     if matches.opt_present("h") || matches.opt_present("help") {
         let message = format!("Usage: {} [OPTIONS]  [TESTNAME...]", argv0);
-        println!("{}", opts.usage(&message));
-        println!();
+        eprintln!("{}", opts.usage(&message));
+        eprintln!();
         panic!()
     }
 
@@ -508,7 +508,7 @@ pub fn run_tests(config: Arc) {
             // easy to miss which tests failed, and as such fail to reproduce
             // the failure locally.
 
-            println!(
+            eprintln!(
                 "Some tests failed in compiletest suite={}{} mode={} host={} target={}",
                 config.suite,
                 config
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 7b11bf3b1219..ca746ed8c55c 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -131,7 +131,7 @@ pub fn run(config: Arc, testpaths: &TestPaths, revision: Option<&str>) {
 
     if config.verbose {
         // We're going to be dumping a lot of info. Start on a new line.
-        print!("\n\n");
+        eprintln!("\n");
     }
     debug!("running {:?}", testpaths.file.display());
     let mut props = TestProps::from_file(&testpaths.file, revision, &config);
@@ -353,7 +353,7 @@ impl<'test> TestCx<'test> {
                 {
                     self.error(&format!("{} test did not emit an error", self.config.mode));
                     if self.config.mode == crate::common::Mode::Ui {
-                        println!("note: by default, ui tests are expected not to compile");
+                        eprintln!("note: by default, ui tests are expected not to compile");
                     }
                     proc_res.fatal(None, || ());
                 };
@@ -774,20 +774,20 @@ impl<'test> TestCx<'test> {
                 unexpected.len(),
                 not_found.len()
             ));
-            println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
+            eprintln!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline);
             if !unexpected.is_empty() {
-                println!("{}", "--- unexpected errors (from JSON output) ---".green());
+                eprintln!("{}", "--- unexpected errors (from JSON output) ---".green());
                 for error in &unexpected {
-                    println!("{}", error.render_for_expected());
+                    eprintln!("{}", error.render_for_expected());
                 }
-                println!("{}", "---".green());
+                eprintln!("{}", "---".green());
             }
             if !not_found.is_empty() {
-                println!("{}", "--- not found errors (from test file) ---".red());
+                eprintln!("{}", "--- not found errors (from test file) ---".red());
                 for error in ¬_found {
-                    println!("{}", error.render_for_expected());
+                    eprintln!("{}", error.render_for_expected());
                 }
-                println!("{}", "---\n".red());
+                eprintln!("{}", "---\n".red());
             }
             panic!("errors differ from expected");
         }
@@ -1876,18 +1876,18 @@ impl<'test> TestCx<'test> {
 
     fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
         if self.config.verbose {
-            println!("------stdout------------------------------");
-            println!("{}", out);
-            println!("------stderr------------------------------");
-            println!("{}", err);
-            println!("------------------------------------------");
+            eprintln!("------stdout------------------------------");
+            eprintln!("{}", out);
+            eprintln!("------stderr------------------------------");
+            eprintln!("{}", err);
+            eprintln!("------------------------------------------");
         }
     }
 
     fn error(&self, err: &str) {
         match self.revision {
-            Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
-            None => println!("\nerror: {}", err),
+            Some(rev) => eprintln!("\nerror in revision `{}`: {}", rev, err),
+            None => eprintln!("\nerror: {}", err),
         }
     }
 
@@ -1972,7 +1972,7 @@ impl<'test> TestCx<'test> {
         if !self.config.has_html_tidy {
             return;
         }
-        println!("info: generating a diff against nightly rustdoc");
+        eprintln!("info: generating a diff against nightly rustdoc");
 
         let suffix =
             self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
@@ -2082,7 +2082,7 @@ impl<'test> TestCx<'test> {
                 .output()
                 .unwrap();
             assert!(output.status.success());
-            println!("{}", String::from_utf8_lossy(&output.stdout));
+            eprintln!("{}", String::from_utf8_lossy(&output.stdout));
             eprintln!("{}", String::from_utf8_lossy(&output.stderr));
         } else {
             use colored::Colorize;
@@ -2496,7 +2496,7 @@ impl<'test> TestCx<'test> {
                 )"#
             )
             .replace_all(&output, |caps: &Captures<'_>| {
-                println!("{}", &caps[0]);
+                eprintln!("{}", &caps[0]);
                 caps[0].replace(r"\", "/")
             })
             .replace("\r\n", "\n")
@@ -2601,14 +2601,14 @@ impl<'test> TestCx<'test> {
         if let Err(err) = fs::write(&actual_path, &actual) {
             self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",));
         }
-        println!("Saved the actual {stream} to {actual_path:?}");
+        eprintln!("Saved the actual {stream} to {actual_path:?}");
 
         let expected_path =
             expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream);
 
         if !self.config.bless {
             if expected.is_empty() {
-                println!("normalized {}:\n{}\n", stream, actual);
+                eprintln!("normalized {}:\n{}\n", stream, actual);
             } else {
                 self.show_diff(
                     stream,
@@ -2631,10 +2631,10 @@ impl<'test> TestCx<'test> {
             if let Err(err) = fs::write(&expected_path, &actual) {
                 self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}"));
             }
-            println!("Blessing the {stream} of {test_name} in {expected_path:?}");
+            eprintln!("Blessing the {stream} of {test_name} in {expected_path:?}");
         }
 
-        println!("\nThe actual {0} differed from the expected {0}.", stream);
+        eprintln!("\nThe actual {0} differed from the expected {0}.", stream);
 
         if self.config.bless { 0 } else { 1 }
     }
@@ -2783,7 +2783,7 @@ impl<'test> TestCx<'test> {
         fs::create_dir_all(&incremental_dir).unwrap();
 
         if self.config.verbose {
-            println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+            eprintln!("init_incremental_test: incremental_dir={}", incremental_dir.display());
         }
     }
 
@@ -2841,7 +2841,7 @@ impl ProcRes {
             }
         }
 
-        println!(
+        eprintln!(
             "status: {}\ncommand: {}\n{}\n{}\n",
             self.status,
             self.cmdline,
@@ -2852,7 +2852,7 @@ impl ProcRes {
 
     pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
         if let Some(e) = err {
-            println!("\nerror: {}", e);
+            eprintln!("\nerror: {}", e);
         }
         self.print_info();
         on_failure();
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 6c866cbef21a..6acd140183d4 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -64,13 +64,13 @@ impl TestCx<'_> {
         if !missing.is_empty() {
             missing.sort();
 
-            println!("\nThese items should have been contained but were not:\n");
+            eprintln!("\nThese items should have been contained but were not:\n");
 
             for item in &missing {
-                println!("{}", item);
+                eprintln!("{}", item);
             }
 
-            println!("\n");
+            eprintln!("\n");
         }
 
         if !unexpected.is_empty() {
@@ -80,24 +80,24 @@ impl TestCx<'_> {
                 sorted
             };
 
-            println!("\nThese items were contained but should not have been:\n");
+            eprintln!("\nThese items were contained but should not have been:\n");
 
             for item in sorted {
-                println!("{}", item);
+                eprintln!("{}", item);
             }
 
-            println!("\n");
+            eprintln!("\n");
         }
 
         if !wrong_cgus.is_empty() {
             wrong_cgus.sort_by_key(|pair| pair.0.name.clone());
-            println!("\nThe following items were assigned to wrong codegen units:\n");
+            eprintln!("\nThe following items were assigned to wrong codegen units:\n");
 
             for &(ref expected_item, ref actual_item) in &wrong_cgus {
-                println!("{}", expected_item.name);
-                println!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
-                println!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
-                println!();
+                eprintln!("{}", expected_item.name);
+                eprintln!("  expected: {}", codegen_units_to_str(&expected_item.codegen_units));
+                eprintln!("  actual:   {}", codegen_units_to_str(&actual_item.codegen_units));
+                eprintln!();
             }
         }
 
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index c621c22ac993..7322e730e53f 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -260,7 +260,7 @@ impl TestCx<'_> {
                 cmdline,
             };
             if adb.kill().is_err() {
-                println!("Adb process is already finished.");
+                eprintln!("Adb process is already finished.");
             }
         } else {
             let rust_src_root =
@@ -275,7 +275,7 @@ impl TestCx<'_> {
 
             match self.config.gdb_version {
                 Some(version) => {
-                    println!("NOTE: compiletest thinks it is using GDB version {}", version);
+                    eprintln!("NOTE: compiletest thinks it is using GDB version {}", version);
 
                     if version > extract_gdb_version("7.4").unwrap() {
                         // Add the directory containing the pretty printers to
@@ -297,7 +297,7 @@ impl TestCx<'_> {
                     }
                 }
                 _ => {
-                    println!(
+                    eprintln!(
                         "NOTE: compiletest does not know which version of \
                          GDB it is using"
                     );
@@ -392,10 +392,10 @@ impl TestCx<'_> {
 
         match self.config.lldb_version {
             Some(ref version) => {
-                println!("NOTE: compiletest thinks it is using LLDB version {}", version);
+                eprintln!("NOTE: compiletest thinks it is using LLDB version {}", version);
             }
             _ => {
-                println!(
+                eprintln!(
                     "NOTE: compiletest does not know which version of \
                      LLDB it is using"
                 );
diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs
index 591aff0defeb..4f26786129bd 100644
--- a/src/tools/compiletest/src/runtest/incremental.rs
+++ b/src/tools/compiletest/src/runtest/incremental.rs
@@ -30,7 +30,7 @@ impl TestCx<'_> {
         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
 
         if self.config.verbose {
-            print!("revision={:?} props={:#?}", revision, self.props);
+            eprint!("revision={:?} props={:#?}", revision, self.props);
         }
 
         if revision.starts_with("cpass") {
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index d1ec00357449..64a2addaa28d 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -89,7 +89,7 @@ impl TestCx<'_> {
                 }
                 let expected_string = fs::read_to_string(&expected_file).unwrap();
                 if dumped_string != expected_string {
-                    print!("{}", write_diff(&expected_string, &dumped_string, 3));
+                    eprint!("{}", write_diff(&expected_string, &dumped_string, 3));
                     panic!(
                         "Actual MIR output differs from expected MIR output {}",
                         expected_file.display()
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index 31fdb0a5d13b..84376d346af3 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -29,7 +29,7 @@ impl TestCx<'_> {
 
         if !res.status.success() {
             self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| {
-                println!("Rustdoc Output:");
+                eprintln!("Rustdoc Output:");
                 proc_res.print_info();
             })
         }
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 172b1e32aad3..bc860bf18c74 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -109,10 +109,10 @@ impl TestCx<'_> {
         }
 
         if errors > 0 {
-            println!("To update references, rerun the tests and pass the `--bless` flag");
+            eprintln!("To update references, rerun the tests and pass the `--bless` flag");
             let relative_path_to_file =
                 self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap());
-            println!(
+            eprintln!(
                 "To only update this specific test, also pass `--test-args {}`",
                 relative_path_to_file.display(),
             );
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index bff02f1db9f0..7b50e62c29bb 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -30,7 +30,7 @@ fn path_div() -> &'static str {
 pub fn logv(config: &Config, s: String) {
     debug!("{}", s);
     if config.verbose {
-        println!("{}", s);
+        eprintln!("{}", s);
     }
 }
 

From d0986f45e094b011d132238563b05c09e4f1e20e Mon Sep 17 00:00:00 2001
From: DianQK 
Date: Mon, 9 Dec 2024 20:25:41 +0800
Subject: [PATCH 122/197] dataflow_const_prop: do not eval a ptr address in
 SwitchInt

---
 .../src/dataflow_const_prop.rs                |  9 +++++++--
 tests/crashes/131227.rs                       | 16 ----------------
 .../ptr-in-switch-int-issue-131227.rs         | 19 +++++++++++++++++++
 3 files changed, 26 insertions(+), 18 deletions(-)
 delete mode 100644 tests/crashes/131227.rs
 create mode 100644 tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs

diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index d017202f48bb..b94c925b1dbd 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -534,8 +534,13 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             // This allows the set of visited edges to grow monotonically with the lattice.
             FlatSet::Bottom => TerminatorEdges::None,
             FlatSet::Elem(scalar) => {
-                let choice = scalar.assert_scalar_int().to_bits_unchecked();
-                TerminatorEdges::Single(targets.target_for_value(choice))
+                if let Ok(scalar_int) = scalar.try_to_scalar_int() {
+                    TerminatorEdges::Single(
+                        targets.target_for_value(scalar_int.to_bits_unchecked()),
+                    )
+                } else {
+                    TerminatorEdges::SwitchInt { discr, targets }
+                }
             }
             FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets },
         }
diff --git a/tests/crashes/131227.rs b/tests/crashes/131227.rs
deleted file mode 100644
index f46185b5b4a6..000000000000
--- a/tests/crashes/131227.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #131227
-//@ compile-flags: -Zmir-opt-level=3
-
-static mut G: () = ();
-
-fn myfunc() -> i32 {
-    let var = &raw mut G;
-    if var.is_null() {
-        return 0;
-    }
-    0
-}
-
-fn main() {
-    myfunc();
-}
diff --git a/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs b/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs
new file mode 100644
index 000000000000..7a55e13d0eed
--- /dev/null
+++ b/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs
@@ -0,0 +1,19 @@
+//! Issue: 
+//! Test that constant propagation in SwitchInt does not crash
+//! when encountering a ptr-to-int transmute.
+
+//@ check-pass
+//@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline,+DataflowConstProp
+
+#![crate_type = "lib"]
+
+static mut G: i32 = 0;
+
+pub fn myfunc() -> i32 {
+    let var = &raw mut G;
+    let u: usize = unsafe { std::mem::transmute(var) };
+    match u {
+        0 => 0,
+        _ => 1,
+    }
+}

From 67c92878630657777039954b060d3410e5ef3d46 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 14:12:22 +0100
Subject: [PATCH 123/197] fix: Non-exhaustive structs may be empty

---
 .../diagnostics/match_check/pat_analysis.rs   |  6 +-----
 .../crates/hir-ty/src/inhabitedness.rs        |  8 +-------
 .../src/handlers/missing_match_arms.rs        | 19 +++++++++++++++++++
 3 files changed, 21 insertions(+), 12 deletions(-)

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 58de19ba81ee..5452f5c680df 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
@@ -383,9 +383,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
                     } else {
                         let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
 
-                        // Whether we must not match the fields of this variant exhaustively.
-                        let is_non_exhaustive =
-                            LazyCell::new(|| self.is_foreign_non_exhaustive(adt));
                         let visibilities = LazyCell::new(|| self.db.field_visibilities(variant));
 
                         self.list_variant_fields(ty, variant)
@@ -396,8 +393,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
                                             .is_visible_from(self.db.upcast(), self.module)
                                 };
                                 let is_uninhabited = self.is_uninhabited(&ty);
-                                let private_uninhabited =
-                                    is_uninhabited && (!is_visible() || *is_non_exhaustive);
+                                let private_uninhabited = is_uninhabited && !is_visible();
                                 (ty, PrivateUninhabitedField(private_uninhabited))
                             })
                             .collect()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index c0a781b17eea..56b549436c70 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -5,8 +5,7 @@ use chalk_ir::{
     visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
     DebruijnIndex,
 };
-use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId};
-use intern::sym;
+use hir_def::{visibility::Visibility, AdtId, EnumVariantId, ModuleId, VariantId};
 use rustc_hash::FxHashSet;
 
 use crate::{
@@ -118,11 +117,6 @@ impl UninhabitedFrom<'_> {
         variant: VariantId,
         subst: &Substitution,
     ) -> ControlFlow {
-        let is_local = variant.krate(self.db.upcast()) == self.target_mod.krate();
-        if !is_local && self.db.attrs(variant.into()).by_key(&sym::non_exhaustive).exists() {
-            return CONTINUE_OPAQUELY_INHABITED;
-        }
-
         let variant_data = self.db.variant_data(variant);
         let fields = variant_data.fields();
         if fields.is_empty() {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index f39738f2fb80..08e6e7dced97 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -1114,6 +1114,25 @@ fn test(x: Option) {
         }
     }
 
+    #[test]
+    fn non_exhaustive_may_be_empty() {
+        check_diagnostics_no_bails(
+            r"
+//- /main.rs crate:main deps:dep
+// In a different crate
+fn empty_match_on_empty_struct(x: dep::UninhabitedStruct) -> T {
+    match x {}
+}
+//- /dep.rs crate:dep
+#[non_exhaustive]
+pub struct UninhabitedStruct {
+    pub never: !,
+    // other fields
+}
+",
+        );
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! prefer false negatives to false positives (ideally there would be no false positives). This

From 73dc95dad19e2fa513ea8ac2b76231474398c8ec Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Mon, 9 Dec 2024 08:52:23 +0100
Subject: [PATCH 124/197] interpret: clean up deduplicating allocation
 functions

---
 .../rustc_const_eval/src/interpret/place.rs   | 42 +++++------
 .../src/util/caller_location.rs               |  9 +--
 compiler/rustc_middle/src/ty/context.rs       |  2 +-
 src/tools/miri/src/shims/backtrace.rs         | 10 +--
 src/tools/miri/src/shims/panic.rs             |  5 +-
 .../tests/pass/backtrace/backtrace-api-v0.rs  | 69 -------------------
 .../pass/backtrace/backtrace-api-v0.stderr    | 18 -----
 .../pass/backtrace/backtrace-api-v0.stdout    |  5 --
 8 files changed, 23 insertions(+), 137 deletions(-)
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
 delete mode 100644 src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout

diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index f54a932e1b6f..810e9356b26c 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -5,8 +5,7 @@
 use std::assert_matches::assert_matches;
 
 use either::{Either, Left, Right};
-use rustc_abi::{Align, BackendRepr, HasDataLayout, Size};
-use rustc_ast::Mutability;
+use rustc_abi::{BackendRepr, HasDataLayout, Size};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::{bug, mir, span_bug};
@@ -1018,40 +1017,31 @@ where
         self.allocate_dyn(layout, kind, MemPlaceMeta::None)
     }
 
-    /// Allocates a sequence of bytes in the interpreter's memory.
-    /// For immutable allocations, uses deduplication to reuse existing memory.
-    /// For mutable allocations, creates a new unique allocation.
-    pub fn allocate_bytes(
+    /// Allocates a sequence of bytes in the interpreter's memory with alignment 1.
+    /// This is allocated in immutable global memory and deduplicated.
+    pub fn allocate_bytes_dedup(
         &mut self,
         bytes: &[u8],
-        align: Align,
-        kind: MemoryKind,
-        mutbl: Mutability,
     ) -> InterpResult<'tcx, Pointer> {
-        // Use cache for immutable strings.
-        if mutbl.is_not() {
-            // Use dedup'd allocation function.
-            let salt = M::get_global_alloc_salt(self, None);
-            let id = self.tcx.allocate_bytes_dedup(bytes, salt);
+        let salt = M::get_global_alloc_salt(self, None);
+        let id = self.tcx.allocate_bytes_dedup(bytes, salt);
 
-            // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
-            M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind))
-        } else {
-            // Allocate new memory for mutable data.
-            self.allocate_bytes_ptr(bytes, align, kind, mutbl)
-        }
+        // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation.
+        M::adjust_alloc_root_pointer(
+            &self,
+            Pointer::from(id),
+            M::GLOBAL_KIND.map(MemoryKind::Machine),
+        )
     }
 
-    /// Allocates a string in the interpreter's memory with metadata for length.
-    /// Uses `allocate_bytes` internally but adds string-specific metadata handling.
-    pub fn allocate_str(
+    /// Allocates a string in the interpreter's memory, returning it as a (wide) place.
+    /// This is allocated in immutable global memory and deduplicated.
+    pub fn allocate_str_dedup(
         &mut self,
         str: &str,
-        kind: MemoryKind,
-        mutbl: Mutability,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let bytes = str.as_bytes();
-        let ptr = self.allocate_bytes(bytes, Align::ONE, kind, mutbl)?;
+        let ptr = self.allocate_bytes_dedup(bytes)?;
 
         // Create length metadata for the string.
         let meta = Scalar::from_target_usize(u64::try_from(bytes.len()).unwrap(), self);
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index 9bf16d4fe167..6593547cd238 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,7 +1,7 @@
 use rustc_hir::LangItem;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Mutability};
+use rustc_middle::ty::{self};
 use rustc_middle::{bug, mir};
 use rustc_span::symbol::Symbol;
 use tracing::trace;
@@ -20,12 +20,9 @@ fn alloc_caller_location<'tcx>(
     // This can fail if rustc runs out of memory right here. Trying to emit an error would be
     // pointless, since that would require allocating more memory than these short strings.
     let file = if loc_details.file {
-        ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap()
+        ecx.allocate_str_dedup(filename.as_str()).unwrap()
     } else {
-        // FIXME: This creates a new allocation each time. It might be preferable to
-        // perform this allocation only once, and re-use the `MPlaceTy`.
-        // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
-        ecx.allocate_str("", MemoryKind::CallerLocation, Mutability::Not).unwrap()
+        ecx.allocate_str_dedup("").unwrap()
     };
     let file = file.map_provenance(CtfeProvenance::as_immutable);
     let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d4835bb07f68..2841470d2487 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr))
     }
 
-    /// Allocates a read-only byte or string literal for `mir::interpret`.
+    /// Allocates a read-only byte or string literal for `mir::interpret` with alignment 1.
     /// Returns the same `AllocId` if called again with the same bytes.
     pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs
index 64bd546458d8..c7b399228bfb 100644
--- a/src/tools/miri/src/shims/backtrace.rs
+++ b/src/tools/miri/src/shims/backtrace.rs
@@ -1,5 +1,4 @@
 use rustc_abi::{ExternAbi, Size};
-use rustc_ast::ast::Mutability;
 use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{BytePos, Loc, Symbol, hygiene};
@@ -179,14 +178,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         match flags {
             0 => {
-                // These are "mutable" allocations as we consider them to be owned by the callee.
-                let name_alloc =
-                    this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
-                let filename_alloc =
-                    this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
-
-                this.write_immediate(name_alloc.to_ref(this), &this.project_field(dest, 0)?)?;
-                this.write_immediate(filename_alloc.to_ref(this), &this.project_field(dest, 1)?)?;
+                throw_unsup_format!("miri_resolve_frame: v0 is not supported any more");
             }
             1 => {
                 this.write_scalar(
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 722c3a2f0c59..93479540009e 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -12,7 +12,6 @@
 //!   metadata we remembered when pushing said frame.
 
 use rustc_abi::ExternAbi;
-use rustc_ast::Mutability;
 use rustc_middle::{mir, ty};
 use rustc_target::spec::PanicStrategy;
 
@@ -161,7 +160,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
+        let msg = this.allocate_str_dedup(msg)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_fn().unwrap();
@@ -180,7 +179,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         // First arg: message.
-        let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
+        let msg = this.allocate_str_dedup(msg)?;
 
         // Call the lang item.
         let panic = this.tcx.lang_items().panic_nounwind().unwrap();
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
deleted file mode 100644
index 3fff7921aff7..000000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-//@normalize-stderr-test: "::<.*>" -> ""
-
-#[inline(never)]
-fn func_a() -> Box<[*mut ()]> {
-    func_b::()
-}
-#[inline(never)]
-fn func_b() -> Box<[*mut ()]> {
-    func_c()
-}
-
-macro_rules! invoke_func_d {
-    () => {
-        func_d()
-    };
-}
-
-#[inline(never)]
-fn func_c() -> Box<[*mut ()]> {
-    invoke_func_d!()
-}
-#[inline(never)]
-fn func_d() -> Box<[*mut ()]> {
-    unsafe { miri_get_backtrace(0) }
-}
-
-fn main() {
-    let mut seen_main = false;
-    let frames = func_a();
-    for frame in frames.iter() {
-        let miri_frame = unsafe { miri_resolve_frame(*frame, 0) };
-        let name = String::from_utf8(miri_frame.name.into()).unwrap();
-        let filename = String::from_utf8(miri_frame.filename.into()).unwrap();
-
-        if name == "func_a" {
-            assert_eq!(func_a as *mut (), miri_frame.fn_ptr);
-        }
-
-        // Print every frame to stderr.
-        let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name);
-        eprintln!("{}", out);
-        // Print the 'main' frame (and everything before it) to stdout, skipping
-        // the printing of internal (and possibly fragile) libstd frames.
-        // Stdout is less normalized so we see more, but it also means we can print less
-        // as platform differences would lead to test suite failures.
-        if !seen_main {
-            println!("{}", out);
-            seen_main = name == "main";
-        }
-    }
-}
-
-// This goes at the bottom of the file so that we can change it
-// without disturbing line numbers of the functions in the backtrace.
-
-extern "Rust" {
-    fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>;
-    fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
-}
-
-#[derive(Debug)]
-#[repr(C)]
-struct MiriFrame {
-    name: Box<[u8]>,
-    filename: Box<[u8]>,
-    lineno: u32,
-    colno: u32,
-    fn_ptr: *mut (),
-}
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
deleted file mode 100644
index 9849a1aa74ea..000000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_d)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_c)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_b)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_a)
-tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (main)
-RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - shim(fn()))
-RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0})
-RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
-RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1})
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call)
-RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try)
-RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal)
-RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start)
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout
deleted file mode 100644
index 8c1bc5c353e9..000000000000
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout
+++ /dev/null
@@ -1,5 +0,0 @@
-tests/pass/backtrace/backtrace-api-v0.rs:24:14 (func_d)
-tests/pass/backtrace/backtrace-api-v0.rs:14:9 (func_c)
-tests/pass/backtrace/backtrace-api-v0.rs:9:5 (func_b::)
-tests/pass/backtrace/backtrace-api-v0.rs:5:5 (func_a)
-tests/pass/backtrace/backtrace-api-v0.rs:29:18 (main)

From ed8ee39930a1bc0b436a67b7189b79466a514bae Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Sat, 7 Dec 2024 17:22:09 +0100
Subject: [PATCH 125/197] fix ICE on type error in promoted

---
 .../rustc_const_eval/src/const_eval/error.rs  |  2 +-
 .../src/const_eval/eval_queries.rs            | 24 ++++----
 .../src/const_eval/machine.rs                 |  3 +-
 .../src/const_eval/valtrees.rs                |  4 +-
 .../src/interpret/eval_context.rs             |  6 +-
 compiler/rustc_middle/src/mir/consts.rs       |  6 +-
 .../rustc_middle/src/mir/interpret/error.rs   | 33 +++++-----
 .../rustc_middle/src/mir/interpret/queries.rs |  9 ++-
 .../clippy/clippy_lints/src/non_copy_const.rs |  7 ++-
 .../unevaluated-const-ice-119731.stderr       | 14 -----
 tests/ui/consts/const-integer-bool-ops.stderr | 60 -------------------
 .../consts/const-mut-refs/issue-76510.stderr  |  6 --
 tests/ui/consts/const-tup-index-span.stderr   |  6 --
 tests/ui/consts/issue-54954.stderr            | 18 ------
 .../consts/missing_assoc_const_type2.stderr   |  6 --
 .../promoted-type-error-issue-133968.rs       |  7 +++
 .../promoted-type-error-issue-133968.stderr   | 16 +++++
 tests/ui/enum-discriminant/issue-41394.stderr |  6 --
 .../base-layout-is-sized-ice-123078.stderr    |  6 --
 ...om-outer-item-in-const-item.default.stderr | 14 -----
 ...m-in-const-item.generic_const_items.stderr | 14 -----
 tests/ui/resolve/issue-50599.stderr           |  6 --
 .../avoid-invalid-mir.stderr                  |  6 --
 ...bitrary-self-from-method-substs-ice.stderr |  6 --
 .../type-dependent-def-issue-49241.stderr     |  6 --
 25 files changed, 78 insertions(+), 213 deletions(-)
 create mode 100644 tests/ui/consts/promoted-type-error-issue-133968.rs
 create mode 100644 tests/ui/consts/promoted-type-error-issue-133968.stderr

diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 3cb77d1dcb5c..fee7287951d0 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -170,7 +170,7 @@ where
             let reported = if allowed_in_infallible {
                 ReportedErrorInfo::allowed_in_infallible(g)
             } else {
-                ReportedErrorInfo::from(g)
+                ReportedErrorInfo::const_eval_error(g)
             };
             ErrorHandled::Reported(reported, span)
         }
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 647d880e2bf0..ce8eceebdf8d 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -3,13 +3,13 @@ use std::sync::atomic::Ordering::Relaxed;
 use either::{Left, Right};
 use rustc_abi::{self as abi, BackendRepr};
 use rustc_hir::def::DefKind;
-use rustc_middle::bug;
-use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
+use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, throw_inval};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument, trace};
@@ -93,18 +93,18 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
     match intern_result {
         Ok(()) => {}
         Err(InternResult::FoundDanglingPointer) => {
-            return Err(ecx
-                .tcx
-                .dcx()
-                .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
-            .into();
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
+                ecx.tcx
+                    .dcx()
+                    .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
+            )));
         }
         Err(InternResult::FoundBadMutablePointer) => {
-            return Err(ecx
-                .tcx
-                .dcx()
-                .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }))
-            .into();
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
+                ecx.tcx
+                    .dcx()
+                    .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }),
+            )));
         }
     }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 11e0fac51d85..56325eaa1be6 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem};
 use rustc_middle::mir::AssertMessage;
+use rustc_middle::mir::interpret::ReportedErrorInfo;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -563,7 +564,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                         .tcx
                         .dcx()
                         .span_delayed_bug(span, "The deny lint should have already errored");
-                    throw_inval!(AlreadyReported(guard.into()));
+                    throw_inval!(AlreadyReported(ReportedErrorInfo::allowed_in_infallible(guard)));
                 }
             } else if new_steps > start && new_steps.is_power_of_two() {
                 // Only report after a certain number of terminators have been evaluated and the
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 515028e6826b..6f51b09323d9 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{BackendRepr, VariantIdx};
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
+use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
 use rustc_middle::{bug, mir};
@@ -261,7 +261,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
                 ValTreeCreationError::NodesOverflow => {
                     let handled =
                         tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
-                    Err(handled.into())
+                    Err(ReportedErrorInfo::allowed_in_infallible(handled).into())
                 }
                 ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
             }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 241be5e175cd..95a72d3cbc1d 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -268,7 +268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         };
         // do not continue if typeck errors occurred (can only occur in local crate)
         if let Some(err) = body.tainted_by_errors {
-            throw_inval!(AlreadyReported(ReportedErrorInfo::from(err)));
+            throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(err)));
         }
         interp_ok(body)
     }
@@ -317,7 +317,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             Ok(None) => throw_inval!(TooGeneric),
 
             // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
-            Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())),
+            Err(error_guaranteed) => throw_inval!(AlreadyReported(
+                ReportedErrorInfo::non_const_eval_error(error_guaranteed)
+            )),
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 7983329b0f7e..52009422d98a 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -8,6 +8,7 @@ use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::{DUMMY_SP, Span};
 use rustc_type_ir::visit::TypeVisitableExt;
 
+use super::interpret::ReportedErrorInfo;
 use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range};
 use crate::mir::{Promoted, pretty_print_const_value};
 use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
@@ -331,7 +332,10 @@ impl<'tcx> Const<'tcx> {
                     ConstKind::Expr(_) => {
                         bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
                     }
-                    _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()),
+                    _ => Err(ReportedErrorInfo::non_const_eval_error(
+                        tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"),
+                    )
+                    .into()),
                 }
             }
             Const::Unevaluated(uneval, _) => {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index ad5d678178de..fbada6ec405f 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -28,10 +28,10 @@ pub enum ErrorHandled {
     TooGeneric(Span),
 }
 
-impl From for ErrorHandled {
+impl From for ErrorHandled {
     #[inline]
-    fn from(error: ErrorGuaranteed) -> ErrorHandled {
-        ErrorHandled::Reported(error.into(), DUMMY_SP)
+    fn from(error: ReportedErrorInfo) -> ErrorHandled {
+        ErrorHandled::Reported(error, DUMMY_SP)
     }
 }
 
@@ -64,6 +64,20 @@ pub struct ReportedErrorInfo {
 }
 
 impl ReportedErrorInfo {
+    #[inline]
+    pub fn const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
+        ReportedErrorInfo { allowed_in_infallible: false, error }
+    }
+
+    /// Use this when the error that led to this is *not* a const-eval error
+    /// (e.g., a layout or type checking error).
+    #[inline]
+    pub fn non_const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo {
+        ReportedErrorInfo { allowed_in_infallible: true, error }
+    }
+
+    /// Use this when the error that led to this *is* a const-eval error, but
+    /// we do allow it to occur in infallible constants (e.g., resource exhaustion).
     #[inline]
     pub fn allowed_in_infallible(error: ErrorGuaranteed) -> ReportedErrorInfo {
         ReportedErrorInfo { allowed_in_infallible: true, error }
@@ -74,13 +88,6 @@ impl ReportedErrorInfo {
     }
 }
 
-impl From for ReportedErrorInfo {
-    #[inline]
-    fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
-        ReportedErrorInfo { allowed_in_infallible: false, error }
-    }
-}
-
 impl Into for ReportedErrorInfo {
     #[inline]
     fn into(self) -> ErrorGuaranteed {
@@ -180,12 +187,6 @@ fn print_backtrace(backtrace: &Backtrace) {
     eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}");
 }
 
-impl From for InterpErrorInfo<'_> {
-    fn from(err: ErrorGuaranteed) -> Self {
-        InterpErrorKind::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
-    }
-}
-
 impl From for InterpErrorInfo<'_> {
     fn from(err: ErrorHandled) -> Self {
         InterpErrorKind::InvalidProgram(match err {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index e540f0194ec0..f7f38575bd03 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -6,6 +6,7 @@ use tracing::{debug, instrument};
 
 use super::{
     ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId,
+    ReportedErrorInfo,
 };
 use crate::mir;
 use crate::query::TyCtxtEnsure;
@@ -81,7 +82,9 @@ impl<'tcx> TyCtxt<'tcx> {
             // For errors during resolution, we deliberately do not point at the usage site of the constant,
             // since for these errors the place the constant is used shouldn't matter.
             Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
+            Err(err) => {
+                Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
+            }
         }
     }
 
@@ -138,7 +141,9 @@ impl<'tcx> TyCtxt<'tcx> {
             // For errors during resolution, we deliberately do not point at the usage site of the constant,
             // since for these errors the place the constant is used shouldn't matter.
             Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
+            Err(err) => {
+                Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP))
+            }
         }
     }
 
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 5f253b9e5d5b..ebd301d5156a 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -11,7 +11,7 @@ use rustc_hir::{
     BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
+use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo};
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
@@ -302,7 +302,10 @@ impl<'tcx> NonCopyConst<'tcx> {
                 tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
             },
             Ok(None) => Err(ErrorHandled::TooGeneric(span)),
-            Err(err) => Err(ErrorHandled::Reported(err.into(), span)),
+            Err(err) => Err(ErrorHandled::Reported(
+                ReportedErrorInfo::non_const_eval_error(err),
+                span,
+            )),
         }
     }
 }
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 4eb374b20204..30a45ce377e7 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,20 +72,6 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more
 LL + #![feature(adt_const_params)]
    |
 
-note: erroneous constant encountered
-  --> $DIR/unevaluated-const-ice-119731.rs:22:19
-   |
-LL |     impl v17<512, v0> {
-   |                   ^^
-
-note: erroneous constant encountered
-  --> $DIR/unevaluated-const-ice-119731.rs:22:19
-   |
-LL |     impl v17<512, v0> {
-   |                   ^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: maximum number of nodes exceeded in constant v20::v17::::{constant#0}
   --> $DIR/unevaluated-const-ice-119731.rs:28:37
    |
diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr
index d58a8e93ff6f..4e503e5a5c0a 100644
--- a/tests/ui/consts/const-integer-bool-ops.stderr
+++ b/tests/ui/consts/const-integer-bool-ops.stderr
@@ -16,12 +16,6 @@ error[E0308]: mismatched types
 LL | const X: usize = 42 && 39;
    |                  ^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:8:18
-   |
-LL | const ARR: [i32; X] = [99; 34];
-   |                  ^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:10:19
    |
@@ -40,12 +34,6 @@ error[E0308]: mismatched types
 LL | const X1: usize = 42 || 39;
    |                   ^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:17:19
-   |
-LL | const ARR1: [i32; X1] = [99; 47];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:19:19
    |
@@ -64,12 +52,6 @@ error[E0308]: mismatched types
 LL | const X2: usize = -42 || -39;
    |                   ^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:26:19
-   |
-LL | const ARR2: [i32; X2] = [99; 18446744073709551607];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:28:19
    |
@@ -88,84 +70,42 @@ error[E0308]: mismatched types
 LL | const X3: usize = -42 && -39;
    |                   ^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:35:19
-   |
-LL | const ARR3: [i32; X3] = [99; 6];
-   |                   ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:37:18
    |
 LL | const Y: usize = 42.0 == 42.0;
    |                  ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:40:19
-   |
-LL | const ARRR: [i32; Y] = [99; 1];
-   |                   ^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:42:19
    |
 LL | const Y1: usize = 42.0 >= 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:45:20
-   |
-LL | const ARRR1: [i32; Y1] = [99; 1];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:47:19
    |
 LL | const Y2: usize = 42.0 <= 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:50:20
-   |
-LL | const ARRR2: [i32; Y2] = [99; 1];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:52:19
    |
 LL | const Y3: usize = 42.0 > 42.0;
    |                   ^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:55:20
-   |
-LL | const ARRR3: [i32; Y3] = [99; 0];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:57:19
    |
 LL | const Y4: usize = 42.0 < 42.0;
    |                   ^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:60:20
-   |
-LL | const ARRR4: [i32; Y4] = [99; 0];
-   |                    ^^
-
 error[E0308]: mismatched types
   --> $DIR/const-integer-bool-ops.rs:62:19
    |
 LL | const Y5: usize = 42.0 != 42.0;
    |                   ^^^^^^^^^^^^ expected `usize`, found `bool`
 
-note: erroneous constant encountered
-  --> $DIR/const-integer-bool-ops.rs:65:20
-   |
-LL | const ARRR5: [i32; Y5] = [99; 0];
-   |                    ^^
-
 error: aborting due to 18 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr
index a63be676fdab..aff86e83578d 100644
--- a/tests/ui/consts/const-mut-refs/issue-76510.stderr
+++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr
@@ -4,12 +4,6 @@ error[E0764]: mutable references are not allowed in the final value of constants
 LL | const S: &'static mut str = &mut " hello ";
    |                             ^^^^^^^^^^^^^^
 
-note: erroneous constant encountered
-  --> $DIR/issue-76510.rs:7:70
-   |
-LL |         let s = transmute::<(*const u8, usize), &ManuallyDrop>((S.as_ptr(), 3));
-   |                                                                      ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0764`.
diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr
index 2a3f0cfb06df..792e18aa8fd4 100644
--- a/tests/ui/consts/const-tup-index-span.stderr
+++ b/tests/ui/consts/const-tup-index-span.stderr
@@ -11,12 +11,6 @@ help: use a trailing comma to create a tuple with one element
 LL | const TUP: (usize,) = (5usize << 64,);
    |                       +            ++
 
-note: erroneous constant encountered
-  --> $DIR/const-tup-index-span.rs:6:18
-   |
-LL | const ARR: [i32; TUP.0] = [];
-   |                  ^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr
index ed6aa9c44a3d..b8c983eb7b81 100644
--- a/tests/ui/consts/issue-54954.stderr
+++ b/tests/ui/consts/issue-54954.stderr
@@ -19,24 +19,6 @@ LL | |         core::mem::size_of::()
 LL | |     }
    | |_____- `Tt::const_val` defined here
 
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:11:15
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |               ^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:11:34
-   |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
-   |                                  ^^^^^^^
-
-note: erroneous constant encountered
-  --> $DIR/issue-54954.rs:16:22
-   |
-LL |     let _ = f([1f32; ARR_LEN]);
-   |                      ^^^^^^^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0379, E0790.
diff --git a/tests/ui/consts/missing_assoc_const_type2.stderr b/tests/ui/consts/missing_assoc_const_type2.stderr
index 3279a077464b..1255ca2d102b 100644
--- a/tests/ui/consts/missing_assoc_const_type2.stderr
+++ b/tests/ui/consts/missing_assoc_const_type2.stderr
@@ -4,11 +4,5 @@ error: missing type for `const` item
 LL |     const FIRST:  = 10;
    |                 ^ help: provide a type for the associated constant: `u8`
 
-note: erroneous constant encountered
-  --> $DIR/missing_assoc_const_type2.rs:18:5
-   |
-LL |     TwoDigits::FIRST as usize
-   |     ^^^^^^^^^^^^^^^^
-
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/promoted-type-error-issue-133968.rs b/tests/ui/consts/promoted-type-error-issue-133968.rs
new file mode 100644
index 000000000000..52c0d48ab5bc
--- /dev/null
+++ b/tests/ui/consts/promoted-type-error-issue-133968.rs
@@ -0,0 +1,7 @@
+struct B {
+    x: &'static T,
+}
+static STR: &'static [u8] = "a b"; //~ERROR: mismatched types
+static C: &B<[u8]> = &B { x: STR };
+
+fn main() {}
diff --git a/tests/ui/consts/promoted-type-error-issue-133968.stderr b/tests/ui/consts/promoted-type-error-issue-133968.stderr
new file mode 100644
index 000000000000..24f1268e4b6e
--- /dev/null
+++ b/tests/ui/consts/promoted-type-error-issue-133968.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/promoted-type-error-issue-133968.rs:4:29
+   |
+LL | static STR: &'static [u8] = "a b";
+   |                             ^^^^^ expected `&[u8]`, found `&str`
+   |
+   = note: expected reference `&'static [u8]`
+              found reference `&'static str`
+help: consider adding a leading `b`
+   |
+LL | static STR: &'static [u8] = b"a b";
+   |                             +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/enum-discriminant/issue-41394.stderr b/tests/ui/enum-discriminant/issue-41394.stderr
index 9bf4fc79b1b0..e81562df04f5 100644
--- a/tests/ui/enum-discriminant/issue-41394.stderr
+++ b/tests/ui/enum-discriminant/issue-41394.stderr
@@ -6,12 +6,6 @@ LL |     A = "" + 1
    |         |
    |         &str
 
-note: erroneous constant encountered
-  --> $DIR/issue-41394.rs:7:9
-   |
-LL |     A = Foo::A as isize
-   |         ^^^^^^^^^^^^^^^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
index ee7f5162552d..455bd2cbf8b6 100644
--- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
@@ -25,12 +25,6 @@ LL | const C: S = unsafe { std::mem::transmute(()) };
    = note: source type: `()` (0 bits)
    = note: target type: `S` (size can vary because of [u8])
 
-note: erroneous constant encountered
-  --> $DIR/base-layout-is-sized-ice-123078.rs:13:5
-   |
-LL |     C;
-   |     ^
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0512.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
index c7e9df10d41c..fbb9ede8aa17 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr
@@ -29,20 +29,6 @@ LL |     const _: u32 = T::C;
    |
    = note: a `const` is a separate item from the item that contains it
 
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
index 64c436d3cebc..60aa94038c3a 100644
--- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
+++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr
@@ -35,20 +35,6 @@ LL |     const _: u32 = T::C;
    |
    = note: a `const` is a separate item from the item that contains it
 
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-
-note: erroneous constant encountered
-  --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9
-   |
-LL |         I
-   |         ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr
index 427dc9f20491..24fb3d580b8f 100644
--- a/tests/ui/resolve/issue-50599.stderr
+++ b/tests/ui/resolve/issue-50599.stderr
@@ -20,12 +20,6 @@ LL -     const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize;
 LL +     const M: usize = (f64::from(N) * LOG10_2) as usize;
    |
 
-note: erroneous constant encountered
-  --> $DIR/issue-50599.rs:4:29
-   |
-LL |     let mut digits = [0u32; M];
-   |                             ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
index eab2604d4c0c..606f808f0936 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr
@@ -6,11 +6,5 @@ LL |     !let y = 42;
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-note: erroneous constant encountered
-  --> $DIR/avoid-invalid-mir.rs:11:13
-   |
-LL |     x: [(); N]
-   |             ^
-
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index e4991823d28a..cf4c219215e0 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -17,12 +17,6 @@ LL |     const fn get>(self: R) -> u32 {
 LL |     }
    |     - value is dropped here
 
-note: erroneous constant encountered
-  --> $DIR/arbitrary-self-from-method-substs-ice.rs:24:5
-   |
-LL |     FOO;
-   |     ^^^
-
 error[E0801]: invalid generic `self` parameter type: `R`
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
    |
diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr
index 4e55618e5cb1..cf372dc59681 100644
--- a/tests/ui/type/type-dependent-def-issue-49241.stderr
+++ b/tests/ui/type/type-dependent-def-issue-49241.stderr
@@ -9,12 +9,6 @@ help: consider using `let` instead of `const`
 LL |     let l: usize = v.count();
    |     ~~~
 
-note: erroneous constant encountered
-  --> $DIR/type-dependent-def-issue-49241.rs:4:18
-   |
-LL |     let s: [u32; l] = v.into_iter().collect();
-   |                  ^
-
 error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0435`.

From a97404eee382141939459fb879cab84233d02d15 Mon Sep 17 00:00:00 2001
From: Eric Huss 
Date: Sun, 8 Dec 2024 12:09:58 -0800
Subject: [PATCH 126/197] Add test to check unicode identifier version

---
 compiler/rustc_lexer/src/lib.rs               |  1 +
 compiler/rustc_parse/src/lib.rs               |  1 +
 tests/ui-fulldeps/lexer/unicode-version.rs    | 27 +++++++++++++++++++
 .../lexer/unicode-version.run.stdout          |  4 +++
 triagebot.toml                                |  7 +++++
 5 files changed, 40 insertions(+)
 create mode 100644 tests/ui-fulldeps/lexer/unicode-version.rs
 create mode 100644 tests/ui-fulldeps/lexer/unicode-version.run.stdout

diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 6caeec1b5cc9..aa4abf678b9f 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -33,6 +33,7 @@ pub mod unescape;
 mod tests;
 
 use unicode_properties::UnicodeEmoji;
+pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;
 
 use self::LiteralKind::*;
 use self::TokenKind::*;
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 2792050a0b39..f963a424a7fd 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -24,6 +24,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diag, FatalError, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::{FileName, SourceFile, Span};
+pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION;
 
 pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
 
diff --git a/tests/ui-fulldeps/lexer/unicode-version.rs b/tests/ui-fulldeps/lexer/unicode-version.rs
new file mode 100644
index 000000000000..cd02b952895c
--- /dev/null
+++ b/tests/ui-fulldeps/lexer/unicode-version.rs
@@ -0,0 +1,27 @@
+// This test is used to validate which version of Unicode is used for parsing
+// identifiers. If the Unicode version changes, it should also be updated in
+// the reference at
+// https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md.
+
+//@ run-pass
+//@ check-run-results
+//@ ignore-cross-compile
+//@ reference: ident.unicode
+//@ reference: ident.normalization
+
+#![feature(rustc_private)]
+
+extern crate rustc_driver;
+extern crate rustc_lexer;
+extern crate rustc_parse;
+
+fn main() {
+    println!("Checking if Unicode version changed.");
+    println!(
+        "If the Unicode version changes are intentional, \
+         it should also be updated in the reference at \
+         https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md."
+    );
+    println!("Unicode XID version is: {:?}", rustc_lexer::UNICODE_XID_VERSION);
+    println!("Unicode normalization version is: {:?}", rustc_parse::UNICODE_NORMALIZATION_VERSION);
+}
diff --git a/tests/ui-fulldeps/lexer/unicode-version.run.stdout b/tests/ui-fulldeps/lexer/unicode-version.run.stdout
new file mode 100644
index 000000000000..f32c8365cdf3
--- /dev/null
+++ b/tests/ui-fulldeps/lexer/unicode-version.run.stdout
@@ -0,0 +1,4 @@
+Checking if Unicode version changed.
+If the Unicode version changes are intentional, it should also be updated in the reference at https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md.
+Unicode XID version is: (16, 0, 0)
+Unicode normalization version is: (16, 0, 0)
diff --git a/triagebot.toml b/triagebot.toml
index 4d6806711fbc..e7c899d150ba 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -991,6 +991,13 @@ cc = ["@Zalathar"]
 [mentions."src/tools/opt-dist"]
 cc = ["@kobzol"]
 
+[mentions."tests/ui-fulldeps/lexer/unicode-version.run.stdout"]
+message = """If the Unicode version changes are intentional,
+it should also be updated in the reference at
+https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md.
+"""
+cc = ["@ehuss"]
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"

From 2ad6d7103cab511a72706c7fb2a06d8c4fe62c4e Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 9 Dec 2024 15:52:04 +0100
Subject: [PATCH 127/197] Disable pipe on typing handler

---
 src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +-
 src/tools/rust-analyzer/docs/user/generated_config.adoc    | 2 +-
 src/tools/rust-analyzer/editors/code/package.json          | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

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 dd7351bcf26c..fd4c8d0e6871 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -309,7 +309,7 @@ config_data! {
         signatureInfo_documentation_enable: bool                       = true,
 
         /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
-        typing_excludeChars: Option = Some('<'.to_string()),
+        typing_excludeChars: Option = Some("|<".to_owned()),
 
 
         /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 715f8d43adc4..1195a85cf70a 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -992,7 +992,7 @@ Show full signature of the callable. Only shows parameters if disabled.
 --
 Show documentation.
 --
-[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"<"`)::
+[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`)::
 +
 --
 Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 70d26c97078c..469c1b458d52 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2607,7 +2607,7 @@
                 "properties": {
                     "rust-analyzer.typing.excludeChars": {
                         "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.",
-                        "default": "<",
+                        "default": "|<",
                         "type": [
                             "null",
                             "string"

From 5404cbb9960c9aa15d104a658a94879237e5a845 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Mon, 9 Dec 2024 17:16:14 +0000
Subject: [PATCH 128/197] Fix typo in RFC mention 3598 -> 3593

https://github.com/rust-lang/rfcs/blob/master/text/3593-unprefixed-guarded-strings.md
---
 compiler/rustc_parse/src/lexer/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index d97f05dc7eb7..2426eb81678e 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -822,7 +822,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
 
     /// Detect guarded string literal syntax
     ///
-    /// RFC 3598 reserved this syntax for future use. As of Rust 2024,
+    /// RFC 3593 reserved this syntax for future use. As of Rust 2024,
     /// using this syntax produces an error. In earlier editions, however, it
     /// only results in an (allowed by default) lint, and is treated as
     /// separate tokens.

From ab6382e4609a94c095b4df409a8ab1c0da953c1d Mon Sep 17 00:00:00 2001
From: roife 
Date: Tue, 10 Dec 2024 02:47:52 +0800
Subject: [PATCH 129/197] minor: enhance name suggestion for `Arc` and
 `Rc`

---
 .../ide-db/src/syntax_helpers/suggest_name.rs | 28 ++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 2679cbef61b3..b3ecc26cb22f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -29,7 +29,7 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
 /// # Examples
 /// `Option` -> `Name`
 /// `Result` -> `User`
-const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"];
+const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
 
 /// Prefixes to strip from methods names
 ///
@@ -858,6 +858,32 @@ fn foo() { $0(bar())$0; }
         );
     }
 
+    #[test]
+    fn arc_value() {
+        check(
+            r#"
+struct Arc(*const T);
+struct Seed;
+fn bar() -> Arc {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seed",
+        );
+    }
+
+    #[test]
+    fn rc_value() {
+        check(
+            r#"
+struct Rc(*const T);
+struct Seed;
+fn bar() -> Rc {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seed",
+        );
+    }
+
     #[test]
     fn ref_call() {
         check(

From 7951d1928086c2c64b80f9ea5d512d365bfdf9b6 Mon Sep 17 00:00:00 2001
From: Sven Kanoldt 
Date: Mon, 9 Dec 2024 20:23:02 +0100
Subject: [PATCH 130/197] Apply suggestions from code review

commit suggestion of not always pretty printing

Co-authored-by: Urgau <3616612+Urgau@users.noreply.github.com>
---
 compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 59c543bb3978..56f0cdbb3192 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -120,7 +120,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     mixed_export_name_no_mangle_lint_state.track_no_mangle(
                         attr.span,
                         tcx.local_def_id_to_hir_id(did),
-                        rustc_ast_pretty::pprust::attribute_to_string(attr),
+                        attr,
                     );
                 } else {
                     tcx.dcx()
@@ -788,22 +788,22 @@ fn check_link_name_xor_ordinal(
 }
 
 #[derive(Default)]
-struct MixedExportNameAndNoMangleState {
+struct MixedExportNameAndNoMangleState<'a> {
     export_name: Option,
     hir_id: Option,
     no_mangle: Option,
-    no_mangle_attr_name: Option,
+    no_mangle_attr: Option<&'a ast::Attribute>,
 }
 
-impl MixedExportNameAndNoMangleState {
+impl<'a> MixedExportNameAndNoMangleState<'a> {
     fn track_export_name(&mut self, span: Span) {
         self.export_name = Some(span);
     }
 
-    fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: String) {
+    fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a ast::Attribute) {
         self.no_mangle = Some(span);
         self.hir_id = Some(hir_id);
-        self.no_mangle_attr_name = Some(attr_name);
+        self.no_mangle_attr = Some(attr_name);
     }
 
     /// Emit diagnostics if the lint condition is met.
@@ -812,7 +812,7 @@ impl MixedExportNameAndNoMangleState {
             export_name: Some(export_name),
             no_mangle: Some(no_mangle),
             hir_id: Some(hir_id),
-            no_mangle_attr_name: Some(no_mangle_attr_name),
+            no_mangle_attr: Some(no_mangle_attr),
         } = self
         {
             tcx.emit_node_span_lint(
@@ -821,7 +821,7 @@ impl MixedExportNameAndNoMangleState {
                 no_mangle,
                 errors::MixedExportNameAndNoMangle {
                     no_mangle,
-                    no_mangle_attr: no_mangle_attr_name,
+                    no_mangle_attr: rustc_ast_pretty::pprust::attribute_to_string(no_mangle_attr),
                     export_name,
                     removal_span: no_mangle,
                 },

From cbc006993957595db56432d0d0b43e944fd5e9d7 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Mon, 9 Dec 2024 19:53:30 +0200
Subject: [PATCH 131/197] Draft completion hashing

---
 src/tools/rust-analyzer/Cargo.lock            |  8 ++
 .../crates/ide-completion/src/item.rs         |  3 +-
 .../crates/ide-completion/src/lib.rs          |  1 +
 .../crates/rust-analyzer/Cargo.toml           | 16 ++--
 .../rust-analyzer/src/handlers/request.rs     | 26 ++++--
 .../crates/rust-analyzer/src/lib.rs           | 89 +++++++++++++++++++
 .../crates/rust-analyzer/src/lsp/ext.rs       |  3 +-
 .../crates/rust-analyzer/src/lsp/to_proto.rs  | 18 +++-
 .../rust-analyzer/docs/dev/lsp-extensions.md  |  2 +-
 9 files changed, 142 insertions(+), 24 deletions(-)

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 5861833d53a2..b6f2c6faf867 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1659,6 +1659,7 @@ dependencies = [
  "hir-def",
  "hir-ty",
  "ide",
+ "ide-completion",
  "ide-db",
  "ide-ssr",
  "intern",
@@ -1687,6 +1688,7 @@ dependencies = [
  "stdx",
  "syntax",
  "syntax-bridge",
+ "tenthash",
  "test-fixture",
  "test-utils",
  "tikv-jemallocator",
@@ -1990,6 +1992,12 @@ dependencies = [
  "tt",
 ]
 
+[[package]]
+name = "tenthash"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d67f9f3cf70e0852941d7bc3cb884b49b24b8ee956baf91ad0abae31f5ef11fb"
+
 [[package]]
 name = "test-fixture"
 version = "0.0.0"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 52f6bedaaa9f..8878fbbea304 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -346,8 +346,7 @@ pub enum CompletionItemKind {
 impl_from!(SymbolKind for CompletionItemKind);
 
 impl CompletionItemKind {
-    #[cfg(test)]
-    pub(crate) fn tag(self) -> &'static str {
+    pub fn tag(self) -> &'static str {
         match self {
             CompletionItemKind::SymbolKind(kind) => match kind {
                 SymbolKind::Attribute => "at",
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 cffdfa29f1a3..14f42b40055e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -34,6 +34,7 @@ pub use crate::{
     config::{CallableSnippets, CompletionConfig},
     item::{
         CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
+        CompletionRelevanceReturnType, CompletionRelevanceTypeMatch,
     },
     snippet::{Snippet, SnippetScope},
 };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 2dd2f2242a00..022b0a0ecf1a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -24,6 +24,7 @@ anyhow.workspace = true
 crossbeam-channel.workspace = true
 dirs = "5.0.1"
 dissimilar.workspace = true
+ide-completion.workspace = true
 itertools.workspace = true
 scip = "0.5.1"
 lsp-types = { version = "=0.95.0", features = ["proposed"] }
@@ -34,6 +35,7 @@ rayon.workspace = true
 rustc-hash.workspace = true
 serde_json = { workspace = true, features = ["preserve_order"] }
 serde.workspace = true
+tenthash = "0.4.0"
 num_cpus = "1.15.0"
 mimalloc = { version = "0.1.30", default-features = false, optional = true }
 lsp-server.workspace = true
@@ -90,13 +92,13 @@ jemalloc = ["jemallocator", "profile/jemalloc"]
 force-always-assert = ["always-assert/force"]
 sysroot-abi = []
 in-rust-tree = [
-  "sysroot-abi",
-  "syntax/in-rust-tree",
-  "parser/in-rust-tree",
-  "hir/in-rust-tree",
-  "hir-def/in-rust-tree",
-  "hir-ty/in-rust-tree",
-  "load-cargo/in-rust-tree",
+    "sysroot-abi",
+    "syntax/in-rust-tree",
+    "parser/in-rust-tree",
+    "hir/in-rust-tree",
+    "hir-def/in-rust-tree",
+    "hir-ty/in-rust-tree",
+    "load-cargo/in-rust-tree",
 ]
 
 [lints]
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 0fadfa6c420f..9dd6dc999b48 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
@@ -36,6 +36,7 @@ use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
+    completion_item_hash,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diagnostics::convert_diagnostic,
     global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
@@ -1122,12 +1123,15 @@ pub(crate) fn handle_completion_resolve(
         return Ok(original_completion);
     };
     let source_root = snap.analysis.source_root_id(file_id)?;
+    let Some(completion_hash_for_resolve) = &resolve_data.completion_item_hash else {
+        return Ok(original_completion);
+    };
 
     let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
     forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
 
     let position = FilePosition { file_id, offset };
-    let Some(resolved_completions) = snap.analysis.completions(
+    let Some(completions) = snap.analysis.completions(
         &forced_resolve_completions_config,
         position,
         resolve_data.trigger_character,
@@ -1135,6 +1139,14 @@ pub(crate) fn handle_completion_resolve(
     else {
         return Ok(original_completion);
     };
+
+    let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
+        let hash = completion_item_hash(&completion_item, resolve_data.for_ref);
+        &hash == completion_hash_for_resolve
+    }) else {
+        return Ok(original_completion);
+    };
+
     let mut resolved_completions = to_proto::completion_items(
         &snap.config,
         &forced_resolve_completions_config.fields_to_resolve,
@@ -1142,15 +1154,11 @@ pub(crate) fn handle_completion_resolve(
         snap.file_version(position.file_id),
         resolve_data.position,
         resolve_data.trigger_character,
-        resolved_completions,
+        vec![corresponding_completion],
     );
-
-    let mut resolved_completion =
-        if resolved_completions.get(resolve_data.completion_item_index).is_some() {
-            resolved_completions.swap_remove(resolve_data.completion_item_index)
-        } else {
-            return Ok(original_completion);
-        };
+    let Some(mut resolved_completion) = resolved_completions.pop() else {
+        return Ok(original_completion);
+    };
 
     if !resolve_data.imports.is_empty() {
         let additional_edits = snap
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 234204695cb6..8f74e75d3d33 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,9 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
+use ide::{CompletionItem, CompletionRelevance, TextEdit, TextRange};
 use serde::de::DeserializeOwned;
+use tenthash::TentHasher;
 
 pub use crate::{
     lsp::capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph,
@@ -61,3 +63,90 @@ pub fn from_json(
     serde_json::from_value(json.clone())
         .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}"))
 }
+
+fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
+    fn hash_text_range(hasher: &mut TentHasher, text_range: &TextRange) {
+        hasher.update(u32::from(text_range.start()).to_le_bytes());
+        hasher.update(u32::from(text_range.end()).to_le_bytes());
+    }
+
+    fn hash_text_edit(hasher: &mut TentHasher, edit: &TextEdit) {
+        for indel in edit.iter() {
+            hasher.update(&indel.insert);
+            hash_text_range(hasher, &indel.delete);
+        }
+    }
+
+    fn has_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) {
+        use ide_completion::{
+            CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
+            CompletionRelevanceTypeMatch,
+        };
+
+        if let Some(type_match) = &relevance.type_match {
+            let label = match type_match {
+                CompletionRelevanceTypeMatch::CouldUnify => "could_unify",
+                CompletionRelevanceTypeMatch::Exact => "exact",
+            };
+            hasher.update(label);
+        }
+        hasher.update(&[u8::from(relevance.exact_name_match), u8::from(relevance.is_local)]);
+        if let Some(trait_) = &relevance.trait_ {
+            hasher.update(&[u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
+        }
+        hasher.update(&[
+            u8::from(relevance.is_name_already_imported),
+            u8::from(relevance.requires_import),
+            u8::from(relevance.is_private_editable),
+        ]);
+        if let Some(postfix_match) = &relevance.postfix_match {
+            let label = match postfix_match {
+                CompletionRelevancePostfixMatch::NonExact => "non_exact",
+                CompletionRelevancePostfixMatch::Exact => "exact",
+            };
+            hasher.update(label);
+        }
+        if let Some(function) = &relevance.function {
+            hasher.update(&[u8::from(function.has_params), u8::from(function.has_self_param)]);
+            let label = match function.return_type {
+                CompletionRelevanceReturnType::Other => "other",
+                CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
+                CompletionRelevanceReturnType::Constructor => "constructor",
+                CompletionRelevanceReturnType::Builder => "builder",
+            };
+            hasher.update(label);
+        }
+    }
+
+    let mut hasher = TentHasher::new();
+    hasher.update(&[
+        u8::from(is_ref_completion),
+        u8::from(item.is_snippet),
+        u8::from(item.deprecated),
+        u8::from(item.trigger_call_info),
+    ]);
+    hasher.update(&item.label);
+    if let Some(label_detail) = &item.label_detail {
+        hasher.update(label_detail);
+    }
+    hash_text_range(&mut hasher, &item.source_range);
+    hash_text_edit(&mut hasher, &item.text_edit);
+    hasher.update(item.kind.tag());
+    hasher.update(&item.lookup);
+    if let Some(detail) = &item.detail {
+        hasher.update(detail);
+    }
+    if let Some(documentation) = &item.documentation {
+        hasher.update(documentation.as_str());
+    }
+    has_completion_relevance(&mut hasher, &item.relevance);
+    if let Some((mutability, text_size)) = &item.ref_match {
+        hasher.update(mutability.as_keyword_for_ref());
+        hasher.update(u32::from(*text_size).to_le_bytes());
+    }
+    for (import_path, import_name) in &item.import_to_add {
+        hasher.update(import_path);
+        hasher.update(import_name);
+    }
+    hasher.finalize()
+}
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 6ddfe118d5e6..7d60ae703b26 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
@@ -826,7 +826,8 @@ pub struct CompletionResolveData {
     pub imports: Vec,
     pub version: Option,
     pub trigger_character: Option,
-    pub completion_item_index: usize,
+    pub for_ref: bool,
+    pub completion_item_hash: Option<[u8; 20]>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
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 d444f90a1318..97caed8f08c0 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
@@ -21,6 +21,7 @@ use serde_json::to_value;
 use vfs::AbsPath;
 
 use crate::{
+    completion_item_hash,
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
@@ -274,6 +275,11 @@ fn completion_item(
     completion_trigger_character: Option,
     item: CompletionItem,
 ) {
+    let original_completion_item = if fields_to_resolve == &CompletionFieldsToResolve::empty() {
+        None
+    } else {
+        Some(item.clone())
+    };
     let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
     let ref_match = item.ref_match();
 
@@ -393,16 +399,17 @@ fn completion_item(
             Vec::new()
         };
     let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
-        let mut item_index = acc.len();
         let ref_resolve_data = if ref_match.is_some() {
             let ref_resolve_data = lsp_ext::CompletionResolveData {
                 position: tdpp.clone(),
                 imports: Vec::new(),
                 version,
                 trigger_character: completion_trigger_character,
-                completion_item_index: item_index,
+                for_ref: true,
+                completion_item_hash: original_completion_item
+                    .as_ref()
+                    .map(|item| completion_item_hash(item, true)),
             };
-            item_index += 1;
             Some(to_value(ref_resolve_data).unwrap())
         } else {
             None
@@ -412,7 +419,10 @@ fn completion_item(
             imports,
             version,
             trigger_character: completion_trigger_character,
-            completion_item_index: item_index,
+            for_ref: false,
+            completion_item_hash: original_completion_item
+                .as_ref()
+                .map(|item| completion_item_hash(item, false)),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index b7c536e02796..008638251705 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 @@
  $DIR/struct_destructure_fail.rs:15:19
-   |
-LL |     Struct { a, .. };
-   |                   ^
-   |
-help: add a base expression here
-   |
-LL |     Struct { a, ../* expr */ };
-   |                   ++++++++++
-
 error[E0026]: struct `Struct` does not have a field named `c`
   --> $DIR/struct_destructure_fail.rs:10:20
    |
@@ -48,6 +37,17 @@ help: or always ignore missing fields here
 LL |     Struct { a, .. } = Struct { a: 1, b: 2 };
    |               ~~~~~~
 
+error[E0797]: base expression required after `..`
+  --> $DIR/struct_destructure_fail.rs:15:19
+   |
+LL |     Struct { a, .. };
+   |                   ^
+   |
+help: add a base expression here
+   |
+LL |     Struct { a, ../* expr */ };
+   |                   ++++++++++
+
 error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0026, E0027, E0797.
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs
new file mode 100644
index 000000000000..01441de67e0a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs
@@ -0,0 +1,106 @@
+#![feature(generic_const_exprs)]
+#![allow(unused_variables, dead_code, incomplete_features)]
+
+pub struct S;
+
+#[derive(Default)]
+pub struct Foo {
+    pub bar: S = S, //~ ERROR default values on `struct` fields aren't supported
+    pub baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+}
+
+#[derive(Default)]
+pub enum Bar {
+    #[default]
+    Foo { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+        bar: S = S, //~ ERROR default values on `struct` fields aren't supported
+        baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+    }
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Qux::::S, //~ ERROR default values on `struct` fields aren't supported
+    baz: i32 = foo(), //~ ERROR default values on `struct` fields aren't supported
+    bat: i32 =  as T>::K, //~ ERROR default values on `struct` fields aren't supported
+    bay: i32 = C, //~ ERROR default values on `struct` fields aren't supported
+    bak: Vec = Vec::new(), //~ ERROR default values on `struct` fields aren't supported
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+#[derive(Default)]
+pub struct Opt {
+    mandatory: Option<()>,
+    optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+}
+
+#[derive(Default)]
+pub enum OptEnum {
+    #[default]
+    Variant { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+        mandatory: Option<()>,
+        optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+    }
+}
+
+fn main () {
+    let x = Foo { .. }; //~ ERROR base expression required after `..`
+    let y = Foo::default();
+    let z = Foo { baz: 1, .. }; //~ ERROR base expression required after `..`
+
+    assert_eq!(45, x.baz);
+    assert_eq!(45, y.baz);
+    assert_eq!(1, z.baz);
+
+    let x = Bar::Foo { .. }; //~ ERROR base expression required after `..`
+    let y = Bar::default();
+    let z = Bar::Foo { baz: 1, .. }; //~ ERROR base expression required after `..`
+
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x));
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y));
+    assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z));
+
+    let x = Qux:: { .. }; //~ ERROR base expression required after `..`
+    assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
+    //~^ ERROR base expression required after `..`
+    assert!(x.bak.is_empty());
+    let y = Opt { mandatory: None, .. };
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt::default(), y));
+    let z = Opt::default();
+    assert!(matches!(Opt { mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { optional: (), .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    let y = OptEnum::Variant { mandatory: None, .. };
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::default(), y));
+    let z = OptEnum::default();
+    assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
+    //~^ ERROR base expression required after `..`
+    assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+    //~^ ERROR base expression required after `..`
+}
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
new file mode 100644
index 000000000000..a24217c07276
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -0,0 +1,318 @@
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/feature-gate-default-field-values.rs:15:5
+   |
+LL |     Foo {
+   |     ^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/feature-gate-default-field-values.rs:55:5
+   |
+LL |     Variant {
+   |     ^^^^^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:8:15
+   |
+LL |     pub bar: S = S,
+   |               ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:9:17
+   |
+LL |     pub baz: i32 = 42 + 3,
+   |                 ^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:16:15
+   |
+LL |         bar: S = S,
+   |               ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:17:17
+   |
+LL |         baz: i32 = 42 + 3,
+   |                 ^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:23:11
+   |
+LL |     bar: S = Qux::::S,
+   |           ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:24:13
+   |
+LL |     baz: i32 = foo(),
+   |             ^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:25:13
+   |
+LL |     bat: i32 =  as T>::K,
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:26:13
+   |
+LL |     bay: i32 = C,
+   |             ^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:27:16
+   |
+LL |     bak: Vec = Vec::new(),
+   |                ^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:49:17
+   |
+LL |     optional: () = (),
+   |                 ^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/feature-gate-default-field-values.rs:57:21
+   |
+LL |         optional: () = (),
+   |                     ^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` 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[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:62:21
+   |
+LL |     let x = Foo { .. };
+   |                     ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Foo { ../* expr */ };
+   |                     ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:64:29
+   |
+LL |     let z = Foo { baz: 1, .. };
+   |                             ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let z = Foo { baz: 1, ../* expr */ };
+   |                             ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:70:26
+   |
+LL |     let x = Bar::Foo { .. };
+   |                          ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Bar::Foo { ../* expr */ };
+   |                          ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:72:34
+   |
+LL |     let z = Bar::Foo { baz: 1, .. };
+   |                                  ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let z = Bar::Foo { baz: 1, ../* expr */ };
+   |                                  ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:78:31
+   |
+LL |     let x = Qux:: { .. };
+   |                               ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let x = Qux:: { ../* expr */ };
+   |                               ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:79:73
+   |
+LL |     assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
+   |                                                                         ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, ../* expr */ }, x));
+   |                                                                         ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:82:38
+   |
+LL |     let y = Opt { mandatory: None, .. };
+   |                                      ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let y = Opt { mandatory: None, ../* expr */ };
+   |                                      ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:86:47
+   |
+LL |     assert!(matches!(Opt { mandatory: None, .. }, z));
+   |                                               ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
+   |                                               ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:88:30
+   |
+LL |     assert!(matches!(Opt { .. }, z));
+   |                              ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { ../* expr */ }, z));
+   |                              ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:90:44
+   |
+LL |     assert!(matches!(Opt { optional: (), .. }, z));
+   |                                            ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(Opt { optional: (), ../* expr */ }, z));
+   |                                            ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:92:61
+   |
+LL |     assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+   |                                                             ^
+   |
+help: remove the `..` as all the fields are already present
+   |
+LL -     assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
+LL +     assert!(matches!(Opt { optional: (), mandatory: None,  }, z));
+   |
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:94:51
+   |
+LL |     let y = OptEnum::Variant { mandatory: None, .. };
+   |                                                   ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     let y = OptEnum::Variant { mandatory: None, ../* expr */ };
+   |                                                   ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:98:60
+   |
+LL |     assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
+   |                                                            ^
+   |
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z));
+   |                                                            ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:100:43
+   |
+LL |     assert!(matches!(OptEnum::Variant { .. }, z));
+   |                                           ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
+   |                                           ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:102:57
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
+   |                                                         ^
+   |
+help: add a base expression here
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
+   |                                                         ++++++++++
+
+error[E0797]: base expression required after `..`
+  --> $DIR/feature-gate-default-field-values.rs:104:74
+   |
+LL |     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+   |                                                                          ^
+   |
+help: remove the `..` as all the fields are already present
+   |
+LL -     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
+LL +     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None,  }, z));
+   |
+
+error: aborting due to 29 previous errors
+
+Some errors have detailed explanations: E0658, E0797.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed b/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed
deleted file mode 100644
index be6ed053c6e3..000000000000
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed
+++ /dev/null
@@ -1,35 +0,0 @@
-//@ run-rustfix
-#![allow(dead_code)]
-
-enum E {
-    A,
-}
-
-struct S {
-    field1: i32, //~ ERROR default values on `struct` fields aren't supported
-    field2: E, //~ ERROR default values on `struct` fields aren't supported
-    field3: i32, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32, //~ ERROR default values on `struct` fields aren't supported
-    field5: E, //~ ERROR default values on `struct` fields aren't supported
-    field6: E, //~ ERROR default values on `struct` fields aren't supported
-}
-
-struct S1 {
-    field1: i32, //~ ERROR expected `,`, or `}`, found `field2`
-    field2: E, //~ ERROR expected `,`, or `}`, found `field3`
-    field3: i32, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32, //~ ERROR default values on `struct` fields aren't supported
-    field5: E, //~ ERROR default values on `struct` fields aren't supported
-    field6: E, //~ ERROR default values on `struct` fields aren't supported
-}
-
-struct S2 {
-    field1 : i32, //~ ERROR expected `:`, found `=`
-    field2: E, //~ ERROR expected `:`, found `;`
-}
-
-const fn foo(_: i32) -> E {
-    E::A
-}
-
-fn main() {}
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
index 7900d397a5de..8ecf042ad385 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
@@ -1,4 +1,3 @@
-//@ run-rustfix
 #![allow(dead_code)]
 
 enum E {
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
index 1fb57ab11f9f..669147c5685f 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
@@ -1,137 +1,17 @@
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16
-   |
-LL |     field1: i32 = 42,
-   |                ^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field1: i32 = 42,
-LL +     field1: i32,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14
-   |
-LL |     field2: E = E::A,
-   |              ^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field2: E = E::A,
-LL +     field2: E,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
-   |
-LL |     field3: i32 = 1 + 2,
-   |                ^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field3: i32 = 1 + 2,
-LL +     field3: i32,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16
-   |
-LL |     field4: i32 = { 1 + 2 },
-   |                ^^^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field4: i32 = { 1 + 2 },
-LL +     field4: i32,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
-   |
-LL |     field5: E = foo(42),
-   |              ^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field5: E = foo(42),
-LL +     field5: E,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14
-   |
-LL |     field6: E = { foo(42) },
-   |              ^^^^^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field6: E = { foo(42) },
-LL +     field6: E,
-   |
-
 error: expected `,`, or `}`, found `field2`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:17:16
    |
 LL |     field1: i32
    |                ^ help: try adding a comma: `,`
 
 error: expected `,`, or `}`, found `field3`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:19:14
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:18:14
    |
 LL |     field2: E
    |              ^ help: try adding a comma: `,`
 
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
-   |
-LL |     field3: i32 = 1 + 2,
-   |                ^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field3: i32 = 1 + 2,
-LL +     field3: i32,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16
-   |
-LL |     field4: i32 = { 1 + 2 },
-   |                ^^^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field4: i32 = { 1 + 2 },
-LL +     field4: i32,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
-   |
-LL |     field5: E = foo(42),
-   |              ^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field5: E = foo(42),
-LL +     field5: E,
-   |
-
-error: default values on `struct` fields aren't supported
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14
-   |
-LL |     field6: E = { foo(42) },
-   |              ^^^^^^^^^^^^^^
-   |
-help: remove this unsupported default value
-   |
-LL -     field6: E = { foo(42) },
-LL +     field6: E,
-   |
-
 error: expected `:`, found `=`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:26:12
    |
 LL |     field1 = i32,
    |            ^
@@ -140,7 +20,7 @@ LL |     field1 = i32,
    |            help: field names and their types are separated with `:`
 
 error: expected `:`, found `;`
-  --> $DIR/struct-default-values-and-missing-field-separator.rs:28:11
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:27:11
    |
 LL |     field2; E,
    |           ^
@@ -148,5 +28,106 @@ LL |     field2; E,
    |           expected `:`
    |           help: field names and their types are separated with `:`
 
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:8:16
+   |
+LL |     field1: i32 = 42,
+   |                ^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:9:14
+   |
+LL |     field2: E = E::A,
+   |              ^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:10:16
+   |
+LL |     field3: i32 = 1 + 2,
+   |                ^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
+   |
+LL |     field4: i32 = { 1 + 2 },
+   |                ^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:12:14
+   |
+LL |     field5: E = foo(42),
+   |              ^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
+   |
+LL |     field6: E = { foo(42) },
+   |              ^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:19:16
+   |
+LL |     field3: i32 = 1 + 2,
+   |                ^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
+   |
+LL |     field4: i32 = { 1 + 2 },
+   |                ^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:21:14
+   |
+LL |     field5: E = foo(42),
+   |              ^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on `struct` fields aren't supported
+  --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
+   |
+LL |     field6: E = { foo(42) },
+   |              ^^^^^^^^^^^^^^
+   |
+   = note: see issue #132162  for more information
+   = help: add `#![feature(default_field_values)]` 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 14 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 2adbcfab612c..e3bc68a21341 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -20,8 +20,8 @@ ast-stats-1 Stmt                     160 ( 2.4%)             5            32
 ast-stats-1 - Let                       32 ( 0.5%)             1
 ast-stats-1 - MacCall                   32 ( 0.5%)             1
 ast-stats-1 - Expr                      96 ( 1.4%)             3
-ast-stats-1 FieldDef                 176 ( 2.6%)             2            88
 ast-stats-1 Block                    192 ( 2.9%)             6            32
+ast-stats-1 FieldDef                 208 ( 3.1%)             2           104
 ast-stats-1 Variant                  208 ( 3.1%)             2           104
 ast-stats-1 AssocItem                352 ( 5.3%)             4            88
 ast-stats-1 - Type                     176 ( 2.6%)             2
@@ -29,7 +29,7 @@ ast-stats-1 - Fn                       176 ( 2.6%)             2
 ast-stats-1 GenericBound             352 ( 5.3%)             4            88
 ast-stats-1 - Trait                    352 ( 5.3%)             4
 ast-stats-1 GenericParam             480 ( 7.2%)             5            96
-ast-stats-1 Pat                      504 ( 7.6%)             7            72
+ast-stats-1 Pat                      504 ( 7.5%)             7            72
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Wild                      72 ( 1.1%)             1
 ast-stats-1 - Ident                    360 ( 5.4%)             5
@@ -39,13 +39,13 @@ ast-stats-1 - Match                     72 ( 1.1%)             1
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Lit                      144 ( 2.2%)             2
 ast-stats-1 - Block                    216 ( 3.2%)             3
-ast-stats-1 PathSegment              744 (11.2%)            31            24
+ast-stats-1 PathSegment              744 (11.1%)            31            24
 ast-stats-1 Ty                       896 (13.4%)            14            64
 ast-stats-1 - Ref                       64 ( 1.0%)             1
 ast-stats-1 - Ptr                       64 ( 1.0%)             1
 ast-stats-1 - ImplicitSelf             128 ( 1.9%)             2
 ast-stats-1 - Path                     640 ( 9.6%)            10
-ast-stats-1 Item                   1_224 (18.4%)             9           136
+ast-stats-1 Item                   1_224 (18.3%)             9           136
 ast-stats-1 - ForeignMod               136 ( 2.0%)             1
 ast-stats-1 - Trait                    136 ( 2.0%)             1
 ast-stats-1 - Impl                     136 ( 2.0%)             1
@@ -53,7 +53,7 @@ ast-stats-1 - Enum                     136 ( 2.0%)             1
 ast-stats-1 - Fn                       272 ( 4.1%)             2
 ast-stats-1 - Use                      408 ( 6.1%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  6_664                   116
+ast-stats-1 Total                  6_696                   116
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -70,7 +70,7 @@ ast-stats-2 - Fn                        88 ( 1.2%)             1
 ast-stats-2 Arm                       96 ( 1.3%)             2            48
 ast-stats-2 FnDecl                   120 ( 1.6%)             5            24
 ast-stats-2 InlineAsm                120 ( 1.6%)             1           120
-ast-stats-2 Attribute                128 ( 1.8%)             4            32
+ast-stats-2 Attribute                128 ( 1.7%)             4            32
 ast-stats-2 - DocComment                32 ( 0.4%)             1
 ast-stats-2 - Normal                    96 ( 1.3%)             3
 ast-stats-2 Param                    160 ( 2.2%)             4            40
@@ -78,33 +78,33 @@ ast-stats-2 Stmt                     160 ( 2.2%)             5            32
 ast-stats-2 - Let                       32 ( 0.4%)             1
 ast-stats-2 - Semi                      32 ( 0.4%)             1
 ast-stats-2 - Expr                      96 ( 1.3%)             3
-ast-stats-2 FieldDef                 176 ( 2.4%)             2            88
 ast-stats-2 Block                    192 ( 2.6%)             6            32
+ast-stats-2 FieldDef                 208 ( 2.8%)             2           104
 ast-stats-2 Variant                  208 ( 2.8%)             2           104
 ast-stats-2 AssocItem                352 ( 4.8%)             4            88
 ast-stats-2 - Type                     176 ( 2.4%)             2
 ast-stats-2 - Fn                       176 ( 2.4%)             2
 ast-stats-2 GenericBound             352 ( 4.8%)             4            88
 ast-stats-2 - Trait                    352 ( 4.8%)             4
-ast-stats-2 GenericParam             480 ( 6.6%)             5            96
+ast-stats-2 GenericParam             480 ( 6.5%)             5            96
 ast-stats-2 Pat                      504 ( 6.9%)             7            72
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - Wild                      72 ( 1.0%)             1
 ast-stats-2 - Ident                    360 ( 4.9%)             5
-ast-stats-2 Expr                     648 ( 8.9%)             9            72
+ast-stats-2 Expr                     648 ( 8.8%)             9            72
 ast-stats-2 - Path                      72 ( 1.0%)             1
 ast-stats-2 - Match                     72 ( 1.0%)             1
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - InlineAsm                 72 ( 1.0%)             1
 ast-stats-2 - Lit                      144 ( 2.0%)             2
-ast-stats-2 - Block                    216 ( 3.0%)             3
+ast-stats-2 - Block                    216 ( 2.9%)             3
 ast-stats-2 PathSegment              864 (11.8%)            36            24
-ast-stats-2 Ty                       896 (12.3%)            14            64
+ast-stats-2 Ty                       896 (12.2%)            14            64
 ast-stats-2 - Ref                       64 ( 0.9%)             1
 ast-stats-2 - Ptr                       64 ( 0.9%)             1
-ast-stats-2 - ImplicitSelf             128 ( 1.8%)             2
-ast-stats-2 - Path                     640 ( 8.8%)            10
-ast-stats-2 Item                   1_496 (20.5%)            11           136
+ast-stats-2 - ImplicitSelf             128 ( 1.7%)             2
+ast-stats-2 - Path                     640 ( 8.7%)            10
+ast-stats-2 Item                   1_496 (20.4%)            11           136
 ast-stats-2 - Enum                     136 ( 1.9%)             1
 ast-stats-2 - Trait                    136 ( 1.9%)             1
 ast-stats-2 - Impl                     136 ( 1.9%)             1
@@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod               136 ( 1.9%)             1
 ast-stats-2 - Fn                       272 ( 3.7%)             2
 ast-stats-2 - Use                      544 ( 7.4%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  7_312                   127
+ast-stats-2 Total                  7_344                   127
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
@@ -138,9 +138,9 @@ hir-stats Stmt                      96 ( 1.1%)             3            32
 hir-stats - Let                       32 ( 0.4%)             1
 hir-stats - Semi                      32 ( 0.4%)             1
 hir-stats - Expr                      32 ( 0.4%)             1
-hir-stats FieldDef                 112 ( 1.3%)             2            56
 hir-stats FnDecl                   120 ( 1.3%)             3            40
 hir-stats Attribute                128 ( 1.4%)             4            32
+hir-stats FieldDef                 128 ( 1.4%)             2            64
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  144 ( 1.6%)             2            72
 hir-stats GenericBound             256 ( 2.9%)             4            64
@@ -163,7 +163,7 @@ hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.3%)             6
-hir-stats Item                     968 (10.9%)            11            88
+hir-stats Item                     968 (10.8%)            11            88
 hir-stats - Enum                      88 ( 1.0%)             1
 hir-stats - Trait                     88 ( 1.0%)             1
 hir-stats - Impl                      88 ( 1.0%)             1
@@ -174,5 +174,5 @@ hir-stats - Use                      352 ( 3.9%)             4
 hir-stats Path                   1_240 (13.9%)            31            40
 hir-stats PathSegment            1_920 (21.5%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_920                   180
+hir-stats Total                  8_936                   180
 hir-stats
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
new file mode 100644
index 000000000000..c4de4f5cdade
--- /dev/null
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -0,0 +1,49 @@
+#![feature(default_field_values)]
+
+#[derive(Debug)]
+pub struct S;
+
+#[derive(Debug, Default)]
+pub struct Foo {
+    pub bar: S = S,
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Debug, Default)]
+pub struct Bar {
+    pub bar: S, //~ ERROR the trait bound `S: Default` is not satisfied
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Self::S, //~ ERROR generic `Self` types are currently not permitted in anonymous constants
+    baz: i32 = foo(),
+    bat: i32 =  as T>::K, //~ ERROR generic parameters may not be used in const operations
+    bay: i32 = C,
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+fn main () {
+    let _ = Foo { .. }; // ok
+    let _ = Foo::default(); // ok
+    let _ = Bar { .. }; //~ ERROR mandatory field
+    let _ = Bar::default(); // silenced
+    let _ = Bar { bar: S, .. }; // ok
+    let _ = Qux::<4> { .. };
+}
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
new file mode 100644
index 000000000000..bd96777f8652
--- /dev/null
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -0,0 +1,40 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/default-field-values-failures.rs:22:23
+   |
+LL |     bat: i32 =  as T>::K,
+   |                       ^ cannot perform const operation using `C`
+   |
+   = help: const parameters may only be used as standalone arguments, i.e. `C`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error[E0277]: the trait bound `S: Default` is not satisfied
+  --> $DIR/default-field-values-failures.rs:14:5
+   |
+LL | #[derive(Debug, Default)]
+   |                 ------- in this derive macro expansion
+LL | pub struct Bar {
+LL |     pub bar: S,
+   |     ^^^^^^^^^^ the trait `Default` is not implemented for `S`
+   |
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `S` with `#[derive(Default)]`
+   |
+LL + #[derive(Default)]
+LL | pub struct S;
+   |
+
+error: missing mandatory field `bar`
+  --> $DIR/default-field-values-failures.rs:45:21
+   |
+LL |     let _ = Bar { .. };
+   |                     ^
+
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/default-field-values-failures.rs:20:14
+   |
+LL |     bar: S = Self::S,
+   |              ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/structs/default-field-values-invalid-const.rs b/tests/ui/structs/default-field-values-invalid-const.rs
new file mode 100644
index 000000000000..6838238064be
--- /dev/null
+++ b/tests/ui/structs/default-field-values-invalid-const.rs
@@ -0,0 +1,19 @@
+#![feature(default_field_values, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+#[warn(default_field_always_invalid_const)] //~ WARN lint `default_field_always_invalid_const` can't be warned on
+pub struct Bat {
+    pub bax: u8 = panic!("asdf"),
+    //~^ ERROR evaluation of constant value failed
+    //~| WARN default field fails const-evaluation
+}
+
+pub struct Baz {
+    pub bax: u8 = 130 + C, // ok
+    pub bat: u8 = 130 + 130,
+    //~^ ERROR evaluation of `Baz::::bat::{constant#0}` failed
+    //~| ERROR default field fails const-evaluation
+    pub bay: u8 = 1, // ok
+}
+
+fn main() {}
diff --git a/tests/ui/structs/default-field-values-invalid-const.stderr b/tests/ui/structs/default-field-values-invalid-const.stderr
new file mode 100644
index 000000000000..a0d84271f4bc
--- /dev/null
+++ b/tests/ui/structs/default-field-values-invalid-const.stderr
@@ -0,0 +1,45 @@
+warning: lint `default_field_always_invalid_const` can't be warned on
+  --> $DIR/default-field-values-invalid-const.rs:4:8
+   |
+LL | #[warn(default_field_always_invalid_const)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ either `deny` or `allow`, no other lint level is supported for this lint
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/default-field-values-invalid-const.rs:6:19
+   |
+LL |     pub bax: u8 = panic!("asdf"),
+   |                   ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:6:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: default field fails const-evaluation
+  --> $DIR/default-field-values-invalid-const.rs:6:5
+   |
+LL |     pub bax: u8 = panic!("asdf"),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
+   |
+   = help: you can skip const-evaluation of default fields by enabling this lint
+note: the lint level is defined here
+  --> $DIR/default-field-values-invalid-const.rs:4:8
+   |
+LL | #[warn(default_field_always_invalid_const)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0080]: evaluation of `Baz::::bat::{constant#0}` failed
+  --> $DIR/default-field-values-invalid-const.rs:13:19
+   |
+LL |     pub bat: u8 = 130 + 130,
+   |                   ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow
+
+error: default field fails const-evaluation
+  --> $DIR/default-field-values-invalid-const.rs:13:5
+   |
+LL |     pub bat: u8 = 130 + 130,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
+   |
+   = help: you can skip const-evaluation of default fields by enabling this lint
+   = note: `#[deny(default_field_always_invalid_const)]` on by default
+
+error: aborting due to 3 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/structs/default-field-values-support.rs b/tests/ui/structs/default-field-values-support.rs
new file mode 100644
index 000000000000..bdf21e1272d8
--- /dev/null
+++ b/tests/ui/structs/default-field-values-support.rs
@@ -0,0 +1,68 @@
+//@ run-pass
+#![feature(default_field_values, generic_const_exprs)]
+#![allow(unused_variables, dead_code, incomplete_features)]
+
+pub struct S;
+
+#[derive(Default)]
+pub struct Foo {
+    pub bar: S = S,
+    pub baz: i32 = 42 + 3,
+}
+
+#[derive(Default)]
+pub enum Bar {
+    #[default]
+    Foo {
+        bar: S = S,
+        baz: i32 = 42 + 3,
+    }
+}
+
+#[derive(Default)]
+pub struct Qux {
+    bar: S = Qux::::S,
+    baz: i32 = foo(),
+    bat: i32 =  as T>::K,
+    baq: i32 = Self::K,
+    bay: i32 = C,
+    bak: Vec = Vec::new(),
+}
+
+impl Qux {
+    const S: S = S;
+}
+
+trait T {
+    const K: i32;
+}
+
+impl T for Qux {
+    const K: i32 = 2;
+}
+
+const fn foo() -> i32 {
+    42
+}
+
+fn main () {
+    let x = Foo { .. };
+    let y = Foo::default();
+    let z = Foo { baz: 1, .. };
+
+    assert_eq!(45, x.baz);
+    assert_eq!(45, y.baz);
+    assert_eq!(1, z.baz);
+
+    let x = Bar::Foo { .. };
+    let y = Bar::default();
+    let z = Bar::Foo { baz: 1, .. };
+
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x));
+    assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y));
+    assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z));
+
+    let x = Qux:: { .. };
+    assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, baq: 2, bay: 4, .. }, x));
+    assert!(x.bak.is_empty());
+}
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index d56f15fb221c..916f296ccfc6 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -92,7 +92,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []
@@ -154,7 +154,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []
@@ -206,7 +206,7 @@ body:
                                                                                         adt_def: 
                                                                                             AdtDef {
                                                                                                 did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo)
-                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
+                                                                                                variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags:  }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags:  }]
                                                                                                 flags: IS_ENUM
                                                                                                 repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 }
                                                                                         args: []

From 550bcae8aa7859abace52c20b8b9149ae6cb37f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Tue, 26 Nov 2024 17:53:00 +0000
Subject: [PATCH 138/197] Detect `struct S(ty = val);`

Emit a specific error for unsupported default field value syntax in tuple structs.
---
 compiler/rustc_ast_lowering/messages.ftl      |  3 ++
 compiler/rustc_ast_lowering/src/errors.rs     |  8 +++++
 compiler/rustc_ast_lowering/src/item.rs       | 33 ++++++++++++++-----
 compiler/rustc_parse/src/parser/item.rs       | 18 +++++++++-
 .../structs/default-field-values-failures.rs  |  2 ++
 .../default-field-values-failures.stderr      | 10 ++++--
 6 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index b53cb7a3822a..b31e21f5c356 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -53,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static
 ast_lowering_coroutine_too_many_parameters =
     too many parameters for a coroutine (expected 0 or 1 parameters)
 
+ast_lowering_default_field_in_tuple = default field in tuple struct
+    .label = default fields are only supported on structs
+
 ast_lowering_does_not_support_modifiers =
     the `{$class_name}` register class does not support template modifiers
 
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 665da14e8612..2564d4e27726 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -38,6 +38,14 @@ pub(crate) struct InvalidAbi {
     pub suggestion: Option,
 }
 
+#[derive(Diagnostic)]
+#[diag(ast_lowering_default_field_in_tuple)]
+pub(crate) struct TupleStructWithDefault {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
 pub(crate) struct InvalidAbiReason(pub &'static str);
 
 impl Subdiagnostic for InvalidAbiReason {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1078aeea22b1..7d6c41992eb0 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -17,7 +17,10 @@ use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
-use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound};
+use super::errors::{
+    InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
+    TupleStructWithDefault,
+};
 use super::{
     AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
     ResolverAstLoweringExt,
@@ -690,13 +693,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
             VariantData::Tuple(fields, id) => {
                 let ctor_id = self.lower_node_id(*id);
                 self.alias_attrs(ctor_id, parent_id);
-                hir::VariantData::Tuple(
-                    self.arena.alloc_from_iter(
-                        fields.iter().enumerate().map(|f| self.lower_field_def(f)),
-                    ),
-                    ctor_id,
-                    self.local_def_id(*id),
-                )
+                let fields = self
+                    .arena
+                    .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
+                for field in &fields[..] {
+                    if let Some(default) = field.default {
+                        // Default values in tuple struct and tuple variants are not allowed by the
+                        // RFC due to concerns about the syntax, both in the item definition and the
+                        // expression. We could in the future allow `struct S(i32 = 0);` and force
+                        // users to construct the value with `let _ = S { .. };`.
+                        if self.tcx.features().default_field_values() {
+                            self.dcx().emit_err(TupleStructWithDefault { span: default.span });
+                        } else {
+                            let _ = self.dcx().span_delayed_bug(
+                                default.span,
+                                "expected `default values on `struct` fields aren't supported` \
+                                 feature-gate error but none was produced",
+                            );
+                        }
+                    }
+                }
+                hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id))
             }
             VariantData::Unit(id) => {
                 let ctor_id = self.lower_node_id(*id);
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index f12b4ca249d6..58b4bf8980b1 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1836,6 +1836,22 @@ impl<'a> Parser<'a> {
                         return Err(err);
                     }
                 };
+                let mut default = None;
+                if p.token == token::Eq {
+                    let mut snapshot = p.create_snapshot_for_diagnostic();
+                    snapshot.bump();
+                    match snapshot.parse_expr_anon_const() {
+                        Ok(const_expr) => {
+                            let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
+                            p.psess.gated_spans.gate(sym::default_field_values, sp);
+                            p.restore_snapshot(snapshot);
+                            default = Some(const_expr);
+                        }
+                        Err(err) => {
+                            err.cancel();
+                        }
+                    }
+                }
 
                 Ok((
                     FieldDef {
@@ -1845,7 +1861,7 @@ impl<'a> Parser<'a> {
                         ident: None,
                         id: DUMMY_NODE_ID,
                         ty,
-                        default: None,
+                        default,
                         attrs,
                         is_placeholder: false,
                     },
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index c4de4f5cdade..27eff70dd3e2 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -23,6 +23,8 @@ pub struct Qux {
     bay: i32 = C,
 }
 
+pub struct Rak(i32 = 42); //~ ERROR default field in tuple struct
+
 impl Qux {
     const S: S = S;
 }
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index bd96777f8652..3564c1dc20e8 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -7,6 +7,12 @@ LL |     bat: i32 =  as T>::K,
    = help: const parameters may only be used as standalone arguments, i.e. `C`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
+error: default field in tuple struct
+  --> $DIR/default-field-values-failures.rs:26:22
+   |
+LL | pub struct Rak(i32 = 42);
+   |                      ^^ default fields are only supported on structs
+
 error[E0277]: the trait bound `S: Default` is not satisfied
   --> $DIR/default-field-values-failures.rs:14:5
    |
@@ -24,7 +30,7 @@ LL | pub struct S;
    |
 
 error: missing mandatory field `bar`
-  --> $DIR/default-field-values-failures.rs:45:21
+  --> $DIR/default-field-values-failures.rs:47:21
    |
 LL |     let _ = Bar { .. };
    |                     ^
@@ -35,6 +41,6 @@ error: generic `Self` types are currently not permitted in anonymous constants
 LL |     bar: S = Self::S,
    |              ^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.

From e0752ad2572218dfc7764951b72d4e3e84ea842c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Tue, 26 Nov 2024 22:28:51 +0000
Subject: [PATCH 139/197] Provide diagnostic for `Struct(a, .., z)` expression

People might extrapolate from `Struct { .. }` that `Struct(..)` would work, but it doesn't.
---
 .../rustc_hir_typeck/src/fn_ctxt/checks.rs    | 31 +++++++++
 tests/ui/range/issue-54505-no-std.rs          |  1 +
 tests/ui/range/issue-54505-no-std.stderr      | 11 ++-
 tests/ui/range/issue-54505.fixed              |  1 +
 tests/ui/range/issue-54505.rs                 |  1 +
 tests/ui/range/issue-54505.stderr             | 11 ++-
 .../structs/default-field-values-failures.rs  |  7 ++
 .../default-field-values-failures.stderr      | 68 ++++++++++++++++++-
 8 files changed, 123 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 44582390a4bf..6b1cceefbeea 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -903,6 +903,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| {
+            if let ty::Adt(adt, _) = ty.kind()
+                && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did())
+                && let hir::ExprKind::Struct(
+                    hir::QPath::LangItem(hir::LangItem::RangeFull, _),
+                    [],
+                    _,
+                ) = expr.kind
+            {
+                // We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax
+                // from default field values, which is not supported on tuples.
+                let explanation = if self.tcx.features().default_field_values() {
+                    "this is only supported on non-tuple struct literals"
+                } else if self.tcx.sess.is_nightly_build() {
+                    "this is only supported on non-tuple struct literals when \
+                     `#![feature(default_field_values)]` is enabled"
+                } else {
+                    "this is not supported"
+                };
+                let msg = format!(
+                    "you might have meant to use `..` to skip providing a value for \
+                     expected fields, but {explanation}; it is instead interpreted as a \
+                     `std::ops::RangeFull` literal",
+                );
+                err.span_help(expr.span, msg);
+            }
+        };
+
         let mut reported = None;
         errors.retain(|error| {
             let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
@@ -1009,6 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 tuple_arguments,
             );
             suggest_confusable(&mut err);
+            detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
             return err.emit();
         }
 
@@ -1133,6 +1162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None,
                         None,
                     );
+                    detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
                 }
                 Error::Extra(arg_idx) => {
                     let (provided_ty, provided_span) = provided_arg_tys[arg_idx];
@@ -1216,6 +1246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
                         prev_extra_idx = Some(arg_idx.index())
                     }
+                    detect_dotdot(&mut err, provided_ty, provided_args[arg_idx]);
                 }
                 Error::Missing(expected_idx) => {
                     // If there are multiple missing arguments adjacent to each other,
diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs
index a15956853729..0c913f766b70 100644
--- a/tests/ui/range/issue-54505-no-std.rs
+++ b/tests/ui/range/issue-54505-no-std.rs
@@ -38,6 +38,7 @@ fn main() {
 
     take_range(..);
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr
index f15a0ae61389..2aa1d584046d 100644
--- a/tests/ui/range/issue-54505-no-std.stderr
+++ b/tests/ui/range/issue-54505-no-std.stderr
@@ -53,13 +53,18 @@ note: function defined here
    |
 LL | fn take_range(_r: &impl RangeBounds) {}
    |    ^^^^^^^^^^ -------------------------
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/issue-54505-no-std.rs:39:16
+   |
+LL |     take_range(..);
+   |                ^^
 help: consider borrowing here
    |
 LL |     take_range(&(..));
    |                ++  +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:44:16
+  --> $DIR/issue-54505-no-std.rs:45:16
    |
 LL |     take_range(0..=1);
    |     ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>`
@@ -79,7 +84,7 @@ LL |     take_range(&(0..=1));
    |                ++     +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:49:16
+  --> $DIR/issue-54505-no-std.rs:50:16
    |
 LL |     take_range(..5);
    |     ---------- ^^^ expected `&_`, found `RangeTo<{integer}>`
@@ -99,7 +104,7 @@ LL |     take_range(&(..5));
    |                ++   +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505-no-std.rs:54:16
+  --> $DIR/issue-54505-no-std.rs:55:16
    |
 LL |     take_range(..=42);
    |     ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>`
diff --git a/tests/ui/range/issue-54505.fixed b/tests/ui/range/issue-54505.fixed
index 054d3c2cf5e0..08a2682140a4 100644
--- a/tests/ui/range/issue-54505.fixed
+++ b/tests/ui/range/issue-54505.fixed
@@ -23,6 +23,7 @@ fn main() {
 
     take_range(&(..));
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505.rs b/tests/ui/range/issue-54505.rs
index f5cec8317609..0a9d7083e4f8 100644
--- a/tests/ui/range/issue-54505.rs
+++ b/tests/ui/range/issue-54505.rs
@@ -23,6 +23,7 @@ fn main() {
 
     take_range(..);
     //~^ ERROR mismatched types [E0308]
+    //~| HELP you might have meant
     //~| HELP consider borrowing here
     //~| SUGGESTION &(
 
diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr
index 0e959fc05e27..291e097e8659 100644
--- a/tests/ui/range/issue-54505.stderr
+++ b/tests/ui/range/issue-54505.stderr
@@ -53,13 +53,18 @@ note: function defined here
    |
 LL | fn take_range(_r: &impl RangeBounds) {}
    |    ^^^^^^^^^^ -------------------------
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/issue-54505.rs:24:16
+   |
+LL |     take_range(..);
+   |                ^^
 help: consider borrowing here
    |
 LL |     take_range(&(..));
    |                ++  +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:29:16
+  --> $DIR/issue-54505.rs:30:16
    |
 LL |     take_range(0..=1);
    |     ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>`
@@ -79,7 +84,7 @@ LL |     take_range(&(0..=1));
    |                ++     +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:34:16
+  --> $DIR/issue-54505.rs:35:16
    |
 LL |     take_range(..5);
    |     ---------- ^^^ expected `&_`, found `RangeTo<{integer}>`
@@ -99,7 +104,7 @@ LL |     take_range(&(..5));
    |                ++   +
 
 error[E0308]: mismatched types
-  --> $DIR/issue-54505.rs:39:16
+  --> $DIR/issue-54505.rs:40:16
    |
 LL |     take_range(..=42);
    |     ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>`
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index 27eff70dd3e2..e850ad387aaf 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -48,4 +48,11 @@ fn main () {
     let _ = Bar::default(); // silenced
     let _ = Bar { bar: S, .. }; // ok
     let _ = Qux::<4> { .. };
+    let _ = Rak(..); //~ ERROR E0308
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak(0, ..); //~ ERROR E0061
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak(.., 0); //~ ERROR E0061
+    //~^ you might have meant to use `..` to skip providing
+    let _ = Rak { .. }; // ok
 }
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index 3564c1dc20e8..bd8d1922e912 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -35,12 +35,76 @@ error: missing mandatory field `bar`
 LL |     let _ = Bar { .. };
    |                     ^
 
+error[E0308]: mismatched types
+  --> $DIR/default-field-values-failures.rs:51:17
+   |
+LL |     let _ = Rak(..);
+   |             --- ^^ expected `i32`, found `RangeFull`
+   |             |
+   |             arguments to this struct are incorrect
+   |
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:51:17
+   |
+LL |     let _ = Rak(..);
+   |                 ^^
+
+error[E0061]: this struct takes 1 argument but 2 arguments were supplied
+  --> $DIR/default-field-values-failures.rs:53:13
+   |
+LL |     let _ = Rak(0, ..);
+   |             ^^^    -- unexpected argument #2 of type `RangeFull`
+   |
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:53:20
+   |
+LL |     let _ = Rak(0, ..);
+   |                    ^^
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: remove the extra argument
+   |
+LL -     let _ = Rak(0, ..);
+LL +     let _ = Rak(0);
+   |
+
+error[E0061]: this struct takes 1 argument but 2 arguments were supplied
+  --> $DIR/default-field-values-failures.rs:55:13
+   |
+LL |     let _ = Rak(.., 0);
+   |             ^^^ -- unexpected argument #1 of type `RangeFull`
+   |
+help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
+  --> $DIR/default-field-values-failures.rs:55:17
+   |
+LL |     let _ = Rak(.., 0);
+   |                 ^^
+note: tuple struct defined here
+  --> $DIR/default-field-values-failures.rs:26:12
+   |
+LL | pub struct Rak(i32 = 42);
+   |            ^^^
+help: remove the extra argument
+   |
+LL -     let _ = Rak(.., 0);
+LL +     let _ = Rak(0);
+   |
+
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/default-field-values-failures.rs:20:14
    |
 LL |     bar: S = Self::S,
    |              ^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0061, E0277, E0308.
+For more information about an error, try `rustc --explain E0061`.

From 148a77dfde03dba553b2e4f3cf817cd6d105b3e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Fri, 6 Dec 2024 19:43:01 +0000
Subject: [PATCH 140/197] review comments: rewordings

---
 compiler/rustc_ast_lowering/messages.ftl      |  2 +-
 compiler/rustc_ast_passes/src/feature_gate.rs |  2 +-
 compiler/rustc_middle/src/ty/adt.rs           |  4 ++--
 .../rustc_mir_build/src/build/expr/into.rs    |  2 +-
 compiler/rustc_resolve/src/late.rs            |  2 +-
 .../feature-gate-default-field-values.rs      | 22 +++++++++----------
 .../feature-gate-default-field-values.stderr  | 22 +++++++++----------
 ...ault-values-and-missing-field-separator.rs | 20 ++++++++---------
 ...-values-and-missing-field-separator.stderr | 20 ++++++++---------
 .../structs/default-field-values-failures.rs  |  2 +-
 .../default-field-values-failures.stderr      |  2 +-
 11 files changed, 50 insertions(+), 50 deletions(-)

diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index b31e21f5c356..f96c9fe8e327 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -53,7 +53,7 @@ ast_lowering_closure_cannot_be_static = closures cannot be static
 ast_lowering_coroutine_too_many_parameters =
     too many parameters for a coroutine (expected 0 or 1 parameters)
 
-ast_lowering_default_field_in_tuple = default field in tuple struct
+ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
     .label = default fields are only supported on structs
 
 ast_lowering_does_not_support_modifiers =
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 688d4d635cf5..aa3b772efb15 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -557,7 +557,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
     gate_all!(explicit_tail_calls, "`become` expression is experimental");
     gate_all!(generic_const_items, "generic const items are experimental");
     gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards");
-    gate_all!(default_field_values, "default values on `struct` fields aren't supported");
+    gate_all!(default_field_values, "default values on fields are experimental");
     gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
     gate_all!(postfix_match, "postfix match is experimental");
     gate_all!(mut_ref, "mutable by-reference bindings are experimental");
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 9678863ee4d8..447cbc8932ee 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -259,10 +259,10 @@ impl Into for AdtKind {
     }
 }
 
-impl<'tcx> AdtDefData {
+impl AdtDefData {
     /// Creates a new `AdtDefData`.
     pub(super) fn new(
-        tcx: TyCtxt<'tcx>,
+        tcx: TyCtxt<'_>,
         did: DefId,
         kind: AdtKind,
         variants: IndexVec,
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index b31f61a75ffe..a3d5376dcd40 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -352,7 +352,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     AdtExprBase::Base(FruInfo { base, field_types }) => {
                         let place_builder = unpack!(block = this.as_place_builder(block, *base));
 
-                        // MIR does not natively support FRU, so for each
+                        // We desugar FRU as we lower to MIR, so for each
                         // base-supplied field, generate an operand that
                         // reads it from the base.
                         itertools::zip_eq(field_names, &**field_types)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index f5e1a5988649..789d74876f72 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -752,7 +752,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
         self.parent_scope.macro_rules = old_macro_rules;
     }
     fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
-        bug!("encountered anon const without a manual call to `resolve_anon_const` {constant:#?}");
+        bug!("encountered anon const without a manual call to `resolve_anon_const`: {constant:#?}");
     }
     fn visit_expr(&mut self, expr: &'ast Expr) {
         self.resolve_expr(expr, None);
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs
index 01441de67e0a..d2e41a716025 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.rs
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs
@@ -5,26 +5,26 @@ pub struct S;
 
 #[derive(Default)]
 pub struct Foo {
-    pub bar: S = S, //~ ERROR default values on `struct` fields aren't supported
-    pub baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+    pub bar: S = S, //~ ERROR default values on fields are experimental
+    pub baz: i32 = 42 + 3, //~ ERROR default values on fields are experimental
 }
 
 #[derive(Default)]
 pub enum Bar {
     #[default]
     Foo { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
-        bar: S = S, //~ ERROR default values on `struct` fields aren't supported
-        baz: i32 = 42 + 3, //~ ERROR default values on `struct` fields aren't supported
+        bar: S = S, //~ ERROR default values on fields are experimental
+        baz: i32 = 42 + 3, //~ ERROR default values on fields are experimental
     }
 }
 
 #[derive(Default)]
 pub struct Qux {
-    bar: S = Qux::::S, //~ ERROR default values on `struct` fields aren't supported
-    baz: i32 = foo(), //~ ERROR default values on `struct` fields aren't supported
-    bat: i32 =  as T>::K, //~ ERROR default values on `struct` fields aren't supported
-    bay: i32 = C, //~ ERROR default values on `struct` fields aren't supported
-    bak: Vec = Vec::new(), //~ ERROR default values on `struct` fields aren't supported
+    bar: S = Qux::::S, //~ ERROR default values on fields are experimental
+    baz: i32 = foo(), //~ ERROR default values on fields are experimental
+    bat: i32 =  as T>::K, //~ ERROR default values on fields are experimental
+    bay: i32 = C, //~ ERROR default values on fields are experimental
+    bak: Vec = Vec::new(), //~ ERROR default values on fields are experimental
 }
 
 impl Qux {
@@ -46,7 +46,7 @@ const fn foo() -> i32 {
 #[derive(Default)]
 pub struct Opt {
     mandatory: Option<()>,
-    optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+    optional: () = (), //~ ERROR default values on fields are experimental
 }
 
 #[derive(Default)]
@@ -54,7 +54,7 @@ pub enum OptEnum {
     #[default]
     Variant { //~ ERROR the `#[default]` attribute may only be used on unit enum variants
         mandatory: Option<()>,
-        optional: () = (), //~ ERROR default values on `struct` fields aren't supported
+        optional: () = (), //~ ERROR default values on fields are experimental
     }
 }
 
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
index a24217c07276..d882c322c8ed 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.stderr
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -14,7 +14,7 @@ LL |     Variant {
    |
    = help: consider a manual implementation of `Default`
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:8:15
    |
 LL |     pub bar: S = S,
@@ -24,7 +24,7 @@ LL |     pub bar: S = S,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:9:17
    |
 LL |     pub baz: i32 = 42 + 3,
@@ -34,7 +34,7 @@ LL |     pub baz: i32 = 42 + 3,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:16:15
    |
 LL |         bar: S = S,
@@ -44,7 +44,7 @@ LL |         bar: S = S,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:17:17
    |
 LL |         baz: i32 = 42 + 3,
@@ -54,7 +54,7 @@ LL |         baz: i32 = 42 + 3,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:23:11
    |
 LL |     bar: S = Qux::::S,
@@ -64,7 +64,7 @@ LL |     bar: S = Qux::::S,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:24:13
    |
 LL |     baz: i32 = foo(),
@@ -74,7 +74,7 @@ LL |     baz: i32 = foo(),
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:25:13
    |
 LL |     bat: i32 =  as T>::K,
@@ -84,7 +84,7 @@ LL |     bat: i32 =  as T>::K,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:26:13
    |
 LL |     bay: i32 = C,
@@ -94,7 +94,7 @@ LL |     bay: i32 = C,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:27:16
    |
 LL |     bak: Vec = Vec::new(),
@@ -104,7 +104,7 @@ LL |     bak: Vec = Vec::new(),
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:49:17
    |
 LL |     optional: () = (),
@@ -114,7 +114,7 @@ LL |     optional: () = (),
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/feature-gate-default-field-values.rs:57:21
    |
 LL |         optional: () = (),
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
index 8ecf042ad385..bb9de98bddbf 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs
@@ -5,21 +5,21 @@ enum E {
 }
 
 struct S {
-    field1: i32 = 42, //~ ERROR default values on `struct` fields aren't supported
-    field2: E = E::A, //~ ERROR default values on `struct` fields aren't supported
-    field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported
-    field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported
-    field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported
+    field1: i32 = 42, //~ ERROR default values on fields are experimental
+    field2: E = E::A, //~ ERROR default values on fields are experimental
+    field3: i32 = 1 + 2, //~ ERROR default values on fields are experimental
+    field4: i32 = { 1 + 2 }, //~ ERROR default values on fields are experimental
+    field5: E = foo(42), //~ ERROR default values on fields are experimental
+    field6: E = { foo(42) }, //~ ERROR default values on fields are experimental
 }
 
 struct S1 {
     field1: i32 //~ ERROR expected `,`, or `}`, found `field2`
     field2: E //~ ERROR expected `,`, or `}`, found `field3`
-    field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported
-    field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported
-    field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported
-    field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported
+    field3: i32 = 1 + 2, //~ ERROR default values on fields are experimental
+    field4: i32 = { 1 + 2 }, //~ ERROR default values on fields are experimental
+    field5: E = foo(42), //~ ERROR default values on fields are experimental
+    field6: E = { foo(42) }, //~ ERROR default values on fields are experimental
 }
 
 struct S2 {
diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
index 669147c5685f..fdd9f0d6dce8 100644
--- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
+++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr
@@ -28,7 +28,7 @@ LL |     field2; E,
    |           expected `:`
    |           help: field names and their types are separated with `:`
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:8:16
    |
 LL |     field1: i32 = 42,
@@ -38,7 +38,7 @@ LL |     field1: i32 = 42,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:9:14
    |
 LL |     field2: E = E::A,
@@ -48,7 +48,7 @@ LL |     field2: E = E::A,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:10:16
    |
 LL |     field3: i32 = 1 + 2,
@@ -58,7 +58,7 @@ LL |     field3: i32 = 1 + 2,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16
    |
 LL |     field4: i32 = { 1 + 2 },
@@ -68,7 +68,7 @@ LL |     field4: i32 = { 1 + 2 },
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:12:14
    |
 LL |     field5: E = foo(42),
@@ -78,7 +78,7 @@ LL |     field5: E = foo(42),
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14
    |
 LL |     field6: E = { foo(42) },
@@ -88,7 +88,7 @@ LL |     field6: E = { foo(42) },
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:19:16
    |
 LL |     field3: i32 = 1 + 2,
@@ -98,7 +98,7 @@ LL |     field3: i32 = 1 + 2,
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16
    |
 LL |     field4: i32 = { 1 + 2 },
@@ -108,7 +108,7 @@ LL |     field4: i32 = { 1 + 2 },
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:21:14
    |
 LL |     field5: E = foo(42),
@@ -118,7 +118,7 @@ LL |     field5: E = foo(42),
    = help: add `#![feature(default_field_values)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: default values on `struct` fields aren't supported
+error[E0658]: default values on fields are experimental
   --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14
    |
 LL |     field6: E = { foo(42) },
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index e850ad387aaf..d67bea18c699 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -23,7 +23,7 @@ pub struct Qux {
     bay: i32 = C,
 }
 
-pub struct Rak(i32 = 42); //~ ERROR default field in tuple struct
+pub struct Rak(i32 = 42); //~ ERROR default fields are not supported in tuple structs
 
 impl Qux {
     const S: S = S;
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index bd8d1922e912..195ee0dbb5f1 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -7,7 +7,7 @@ LL |     bat: i32 =  as T>::K,
    = help: const parameters may only be used as standalone arguments, i.e. `C`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error: default field in tuple struct
+error: default fields are not supported in tuple structs
   --> $DIR/default-field-values-failures.rs:26:22
    |
 LL | pub struct Rak(i32 = 42);

From 2d6e763cc68b2433b9df33da2a80dc4cf4953079 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Fri, 6 Dec 2024 19:50:55 +0000
Subject: [PATCH 141/197] Disallow `#[default] Variant {}` regardless of
 feature flag

---
 compiler/rustc_builtin_macros/messages.ftl    |  2 +-
 .../src/deriving/default.rs                   | 16 +++++++++++--
 compiler/rustc_builtin_macros/src/errors.rs   |  1 +
 .../structs/default-field-values-failures.rs  |  6 +++++
 .../default-field-values-failures.stderr      | 24 ++++++++++++-------
 5 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index c05d44cb4525..87d3d288013a 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -261,7 +261,7 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
 
 builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
 
-builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
+builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants{$post}
     .help = consider a manual implementation of `Default`
 
 builtin_macros_only_one_argument = {$name} takes 1 argument
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 12d5587b5db8..6b1a6effad75 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -199,10 +199,17 @@ fn extract_default_variant<'a>(
     if cx.ecfg.features.default_field_values()
         && let VariantData::Struct { fields, .. } = &variant.data
         && fields.iter().all(|f| f.default.is_some())
+        // Disallow `#[default] Variant {}`
+        && !fields.is_empty()
     {
         // Allowed
     } else if !matches!(variant.data, VariantData::Unit(..)) {
-        let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
+        let post = if cx.ecfg.features.default_field_values() {
+            " or variants where every field has a default value"
+        } else {
+            ""
+        };
+        let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span, post });
         return Err(guar);
     }
 
@@ -261,7 +268,12 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
 impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
     fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
         if attr.has_name(kw::Default) {
-            self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span });
+            let post = if self.cx.ecfg.features.default_field_values() {
+                " or variants where every field has a default value"
+            } else {
+                ""
+            };
+            self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span, post });
         }
 
         rustc_ast::visit::walk_attribute(self, attr);
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index f8e65661e52e..c9bd3371e559 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -424,6 +424,7 @@ pub(crate) struct MultipleDefaultsSugg {
 pub(crate) struct NonUnitDefault {
     #[primary_span]
     pub(crate) span: Span,
+    pub(crate) post: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs
index d67bea18c699..0ac071d91d65 100644
--- a/tests/ui/structs/default-field-values-failures.rs
+++ b/tests/ui/structs/default-field-values-failures.rs
@@ -41,6 +41,12 @@ const fn foo() -> i32 {
     42
 }
 
+#[derive(Debug, Default)]
+enum E {
+    #[default]
+    Variant {} //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+}
+
 fn main () {
     let _ = Foo { .. }; // ok
     let _ = Foo::default(); // ok
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index 195ee0dbb5f1..e60ec392fdd6 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -1,3 +1,11 @@
+error: the `#[default]` attribute may only be used on unit enum variants or variants where every field has a default value
+  --> $DIR/default-field-values-failures.rs:47:5
+   |
+LL |     Variant {}
+   |     ^^^^^^^
+   |
+   = help: consider a manual implementation of `Default`
+
 error: generic parameters may not be used in const operations
   --> $DIR/default-field-values-failures.rs:22:23
    |
@@ -30,13 +38,13 @@ LL | pub struct S;
    |
 
 error: missing mandatory field `bar`
-  --> $DIR/default-field-values-failures.rs:47:21
+  --> $DIR/default-field-values-failures.rs:53:21
    |
 LL |     let _ = Bar { .. };
    |                     ^
 
 error[E0308]: mismatched types
-  --> $DIR/default-field-values-failures.rs:51:17
+  --> $DIR/default-field-values-failures.rs:57:17
    |
 LL |     let _ = Rak(..);
    |             --- ^^ expected `i32`, found `RangeFull`
@@ -49,19 +57,19 @@ note: tuple struct defined here
 LL | pub struct Rak(i32 = 42);
    |            ^^^
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/default-field-values-failures.rs:51:17
+  --> $DIR/default-field-values-failures.rs:57:17
    |
 LL |     let _ = Rak(..);
    |                 ^^
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/default-field-values-failures.rs:53:13
+  --> $DIR/default-field-values-failures.rs:59:13
    |
 LL |     let _ = Rak(0, ..);
    |             ^^^    -- unexpected argument #2 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/default-field-values-failures.rs:53:20
+  --> $DIR/default-field-values-failures.rs:59:20
    |
 LL |     let _ = Rak(0, ..);
    |                    ^^
@@ -77,13 +85,13 @@ LL +     let _ = Rak(0);
    |
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/default-field-values-failures.rs:55:13
+  --> $DIR/default-field-values-failures.rs:61:13
    |
 LL |     let _ = Rak(.., 0);
    |             ^^^ -- unexpected argument #1 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/default-field-values-failures.rs:55:17
+  --> $DIR/default-field-values-failures.rs:61:17
    |
 LL |     let _ = Rak(.., 0);
    |                 ^^
@@ -104,7 +112,7 @@ error: generic `Self` types are currently not permitted in anonymous constants
 LL |     bar: S = Self::S,
    |              ^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0061, E0277, E0308.
 For more information about an error, try `rustc --explain E0061`.

From 0757641f4d89418091a6381a4ad6426769ee0fa8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Fri, 6 Dec 2024 23:08:17 +0000
Subject: [PATCH 142/197] Unconditionally error at definition if default field
 value has const errors

Emit E0080 always on struct definition with default fields that have unconditional const errors and remove `default_field_always_invalid_const` lint.
---
 .../rustc_hir_analysis/src/check/wfcheck.rs   | 19 ++++
 compiler/rustc_lint/messages.ftl              |  4 -
 .../src/default_field_always_invalid.rs       | 91 -------------------
 compiler/rustc_lint/src/lib.rs                |  3 -
 compiler/rustc_lint/src/lints.rs              |  9 --
 .../default-field-values-failures.stderr      | 12 +--
 .../default-field-values-invalid-const.rs     |  3 -
 .../default-field-values-invalid-const.stderr | 36 +-------
 8 files changed, 29 insertions(+), 148 deletions(-)
 delete mode 100644 compiler/rustc_lint/src/default_field_always_invalid.rs

diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 2b33da3c49a0..c9773972d9a2 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1104,6 +1104,25 @@ fn check_type_defn<'tcx>(
         for variant in variants.iter() {
             // All field types must be well-formed.
             for field in &variant.fields {
+                if let Some(def_id) = field.value
+                    && let Some(_ty) = tcx.type_of(def_id).no_bound_vars()
+                {
+                    // FIXME(generic_const_exprs, default_field_values): this is a hack and needs to
+                    // be refactored to check the instantiate-ability of the code better.
+                    if let Some(def_id) = def_id.as_local()
+                        && let hir::Node::AnonConst(anon) = tcx.hir_node_by_def_id(def_id)
+                        && let expr = &tcx.hir().body(anon.body).value
+                        && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+                        && let Res::Def(DefKind::ConstParam, _def_id) = path.res
+                    {
+                        // Do not evaluate bare `const` params, as those would ICE and are only
+                        // usable if `#![feature(generic_const_exprs)]` is enabled.
+                    } else {
+                        // Evaluate the constant proactively, to emit an error if the constant has
+                        // an unconditional error. We only do so if the const has no type params.
+                        let _ = tcx.const_eval_poly(def_id.into());
+                    }
+                }
                 let field_id = field.did.expect_local();
                 let hir::FieldDef { ty: hir_ty, .. } =
                     tcx.hir_node_by_def_id(field_id).expect_field();
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index f5d2ebc3e87e..422629cd11d0 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -211,10 +211,6 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be
     .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
     .help = for more information, see 
 
-lint_default_field_always_invalid_const = default field fails const-evaluation
-    .label = this field's constant fails const-evaluation, as seen in the previous error
-    .help = you can skip const-evaluation of default fields by enabling this lint
-
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
 
diff --git a/compiler/rustc_lint/src/default_field_always_invalid.rs b/compiler/rustc_lint/src/default_field_always_invalid.rs
deleted file mode 100644
index 46cffb53b4b6..000000000000
--- a/compiler/rustc_lint/src/default_field_always_invalid.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-use rustc_hir as hir;
-use rustc_middle::lint::LintLevelSource;
-use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_session::lint::Level;
-use rustc_session::{declare_lint, declare_lint_pass};
-
-use crate::lints::DefaultFieldAlwaysInvalidConst;
-use crate::{LateContext, LateLintPass};
-
-declare_lint! {
-    /// The `default_field_always_invalid_const` lint checks for structs with
-    /// default fields const values that will *always* fail to be created.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail
-    /// #![feature(default_field_values)]
-    /// #[deny(default_field_always_invalid_const)]
-    /// struct Foo {
-    ///     bar: u8 = 130 + 130, // `260` doesn't fit in `u8`
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Without this lint, the error would only happen only during construction
-    /// of the affected type. For example, given the type above, `Foo { .. }`
-    /// would always fail to build, but `Foo { bar: 0 }` would be accepted. This
-    /// lint will catch accidental cases of const values that would fail to
-    /// compile, but won't detect cases that are only partially evaluated.
-    pub DEFAULT_FIELD_ALWAYS_INVALID_CONST,
-    Deny,
-    "using this default field will always fail to compile"
-}
-
-declare_lint_pass!(DefaultFieldAlwaysInvalid => [DEFAULT_FIELD_ALWAYS_INVALID_CONST]);
-
-impl<'tcx> LateLintPass<'tcx> for DefaultFieldAlwaysInvalid {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        let data = match item.kind {
-            hir::ItemKind::Struct(data, _generics) => data,
-            _ => return,
-        };
-        let hir::VariantData::Struct { fields, recovered: _ } = data else {
-            return;
-        };
-
-        let (level, source) =
-            cx.tcx.lint_level_at_node(DEFAULT_FIELD_ALWAYS_INVALID_CONST, item.hir_id());
-        match level {
-            Level::Deny | Level::Forbid => {}
-            Level::Warn | Level::ForceWarn(_) | Level::Expect(_) => {
-                // We *can't* turn the const eval error into a warning, so we make it a
-                // warning to not use `#[warn(default_field_always_invalid_const)]`.
-                let invalid_msg = "lint `default_field_always_invalid_const` can't be warned on";
-                #[allow(rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic)]
-                if let LintLevelSource::Node { span, .. } = source {
-                    let mut err = cx.tcx.sess.dcx().struct_span_warn(span, invalid_msg);
-                    err.span_label(
-                        span,
-                        "either `deny` or `allow`, no other lint level is supported for this lint",
-                    );
-                    err.emit();
-                } else {
-                    cx.tcx.sess.dcx().warn(invalid_msg);
-                }
-            }
-            Level::Allow => {
-                // We don't even look at the fields.
-                return;
-            }
-        }
-        for field in fields {
-            if let Some(c) = field.default
-                && let Some(_ty) = cx.tcx.type_of(c.def_id).no_bound_vars()
-                && let Err(ErrorHandled::Reported(_, _)) = cx.tcx.const_eval_poly(c.def_id.into())
-            {
-                // We use the item's hir id because the const's hir id might resolve inside of a
-                // foreign macro, meaning the lint won't trigger.
-                cx.tcx.emit_node_span_lint(
-                    DEFAULT_FIELD_ALWAYS_INVALID_CONST,
-                    item.hir_id(),
-                    field.span,
-                    DefaultFieldAlwaysInvalidConst { span: field.span, help: () },
-                );
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index baf2703511e2..a99c94592b30 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -41,7 +41,6 @@ mod async_fn_in_trait;
 pub mod builtin;
 mod context;
 mod dangling;
-mod default_field_always_invalid;
 mod deref_into_dyn_supertrait;
 mod drop_forget_useless;
 mod early;
@@ -86,7 +85,6 @@ use async_closures::AsyncClosureUsage;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
 use dangling::*;
-use default_field_always_invalid::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -195,7 +193,6 @@ late_lint_methods!(
             DropForgetUseless: DropForgetUseless,
             ImproperCTypesDeclarations: ImproperCTypesDeclarations,
             ImproperCTypesDefinitions: ImproperCTypesDefinitions,
-            DefaultFieldAlwaysInvalid: DefaultFieldAlwaysInvalid,
             InvalidFromUtf8: InvalidFromUtf8,
             VariantSizeDifferences: VariantSizeDifferences,
             PathStatements: PathStatements,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 07f1c48bafb5..9fa263799ebf 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -730,15 +730,6 @@ pub(crate) struct UndroppedManuallyDropsSuggestion {
     pub end_span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(lint_default_field_always_invalid_const)]
-pub(crate) struct DefaultFieldAlwaysInvalidConst {
-    #[label]
-    pub span: Span,
-    #[help]
-    pub help: (),
-}
-
 // invalid_from_utf8.rs
 #[derive(LintDiagnostic)]
 pub(crate) enum InvalidFromUtf8Diag {
diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr
index e60ec392fdd6..5b9d2df5a5d7 100644
--- a/tests/ui/structs/default-field-values-failures.stderr
+++ b/tests/ui/structs/default-field-values-failures.stderr
@@ -21,6 +21,12 @@ error: default fields are not supported in tuple structs
 LL | pub struct Rak(i32 = 42);
    |                      ^^ default fields are only supported on structs
 
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/default-field-values-failures.rs:20:14
+   |
+LL |     bar: S = Self::S,
+   |              ^^^^
+
 error[E0277]: the trait bound `S: Default` is not satisfied
   --> $DIR/default-field-values-failures.rs:14:5
    |
@@ -106,12 +112,6 @@ LL -     let _ = Rak(.., 0);
 LL +     let _ = Rak(0);
    |
 
-error: generic `Self` types are currently not permitted in anonymous constants
-  --> $DIR/default-field-values-failures.rs:20:14
-   |
-LL |     bar: S = Self::S,
-   |              ^^^^
-
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0061, E0277, E0308.
diff --git a/tests/ui/structs/default-field-values-invalid-const.rs b/tests/ui/structs/default-field-values-invalid-const.rs
index 6838238064be..203a712868b7 100644
--- a/tests/ui/structs/default-field-values-invalid-const.rs
+++ b/tests/ui/structs/default-field-values-invalid-const.rs
@@ -1,18 +1,15 @@
 #![feature(default_field_values, generic_const_exprs)]
 #![allow(incomplete_features)]
 
-#[warn(default_field_always_invalid_const)] //~ WARN lint `default_field_always_invalid_const` can't be warned on
 pub struct Bat {
     pub bax: u8 = panic!("asdf"),
     //~^ ERROR evaluation of constant value failed
-    //~| WARN default field fails const-evaluation
 }
 
 pub struct Baz {
     pub bax: u8 = 130 + C, // ok
     pub bat: u8 = 130 + 130,
     //~^ ERROR evaluation of `Baz::::bat::{constant#0}` failed
-    //~| ERROR default field fails const-evaluation
     pub bay: u8 = 1, // ok
 }
 
diff --git a/tests/ui/structs/default-field-values-invalid-const.stderr b/tests/ui/structs/default-field-values-invalid-const.stderr
index a0d84271f4bc..47f25a1f38e3 100644
--- a/tests/ui/structs/default-field-values-invalid-const.stderr
+++ b/tests/ui/structs/default-field-values-invalid-const.stderr
@@ -1,45 +1,17 @@
-warning: lint `default_field_always_invalid_const` can't be warned on
-  --> $DIR/default-field-values-invalid-const.rs:4:8
-   |
-LL | #[warn(default_field_always_invalid_const)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ either `deny` or `allow`, no other lint level is supported for this lint
-
 error[E0080]: evaluation of constant value failed
-  --> $DIR/default-field-values-invalid-const.rs:6:19
+  --> $DIR/default-field-values-invalid-const.rs:5:19
    |
 LL |     pub bax: u8 = panic!("asdf"),
-   |                   ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:6:19
+   |                   ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:5:19
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-warning: default field fails const-evaluation
-  --> $DIR/default-field-values-invalid-const.rs:6:5
-   |
-LL |     pub bax: u8 = panic!("asdf"),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
-   |
-   = help: you can skip const-evaluation of default fields by enabling this lint
-note: the lint level is defined here
-  --> $DIR/default-field-values-invalid-const.rs:4:8
-   |
-LL | #[warn(default_field_always_invalid_const)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0080]: evaluation of `Baz::::bat::{constant#0}` failed
-  --> $DIR/default-field-values-invalid-const.rs:13:19
+  --> $DIR/default-field-values-invalid-const.rs:11:19
    |
 LL |     pub bat: u8 = 130 + 130,
    |                   ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow
 
-error: default field fails const-evaluation
-  --> $DIR/default-field-values-invalid-const.rs:13:5
-   |
-LL |     pub bat: u8 = 130 + 130,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ this field's constant fails const-evaluation, as seen in the previous error
-   |
-   = help: you can skip const-evaluation of default fields by enabling this lint
-   = note: `#[deny(default_field_always_invalid_const)]` on by default
-
-error: aborting due to 3 previous errors; 2 warnings emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.

From fa331f4d0d2d7657c76972574868c5c00afae459 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Sat, 7 Dec 2024 03:04:51 +0000
Subject: [PATCH 143/197] Support x-crate default fields

---
 compiler/rustc_metadata/src/rmeta/decoder.rs       | 6 +++++-
 compiler/rustc_metadata/src/rmeta/encoder.rs       | 7 +++++++
 compiler/rustc_metadata/src/rmeta/mod.rs           | 1 +
 tests/ui/structs/auxiliary/struct_field_default.rs | 5 +++++
 tests/ui/structs/default-field-values-support.rs   | 6 ++++++
 5 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/structs/auxiliary/struct_field_default.rs

diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 4a4930fff9d5..b9586338655e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1104,7 +1104,7 @@ impl<'a> CrateMetadataRef<'a> {
                         name: self.item_name(did.index),
                         vis: self.get_visibility(did.index),
                         safety: self.get_safety(did.index),
-                        value: None,
+                        value: self.get_default_field(did.index),
                     })
                     .collect(),
                 adt_kind,
@@ -1170,6 +1170,10 @@ impl<'a> CrateMetadataRef<'a> {
         self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id))
     }
 
+    fn get_default_field(self, id: DefIndex) -> Option {
+        self.root.tables.default_fields.get(self, id).map(|d| d.decode(self))
+    }
+
     fn get_trait_item_def_id(self, id: DefIndex) -> Option {
         self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self))
     }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d4ea1276d002..5c80d24f502d 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1401,6 +1401,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 continue;
             }
 
+            if def_kind == DefKind::Field
+                && let hir::Node::Field(field) = tcx.hir_node_by_def_id(local_id)
+                && let Some(anon) = field.default
+            {
+                record!(self.tables.default_fields[def_id] <- anon.def_id.to_def_id());
+            }
+
             if should_encode_span(def_kind) {
                 let def_span = tcx.def_span(local_id);
                 record!(self.tables.def_span[def_id] <- def_span);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a5e21ab51fd8..4961464833af 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -450,6 +450,7 @@ define_tables! {
     trait_def: Table>,
     trait_item_def_id: Table,
     expn_that_defined: Table>,
+    default_fields: Table>,
     params_in_repr: Table>>,
     repr_options: Table>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
diff --git a/tests/ui/structs/auxiliary/struct_field_default.rs b/tests/ui/structs/auxiliary/struct_field_default.rs
new file mode 100644
index 000000000000..b315df5dba28
--- /dev/null
+++ b/tests/ui/structs/auxiliary/struct_field_default.rs
@@ -0,0 +1,5 @@
+#![feature(default_field_values)]
+
+pub struct A {
+    pub a: isize = 42,
+}
diff --git a/tests/ui/structs/default-field-values-support.rs b/tests/ui/structs/default-field-values-support.rs
index bdf21e1272d8..da0379af94b8 100644
--- a/tests/ui/structs/default-field-values-support.rs
+++ b/tests/ui/structs/default-field-values-support.rs
@@ -1,7 +1,10 @@
 //@ run-pass
+//@ aux-build:struct_field_default.rs
 #![feature(default_field_values, generic_const_exprs)]
 #![allow(unused_variables, dead_code, incomplete_features)]
 
+extern crate struct_field_default as xc;
+
 pub struct S;
 
 #[derive(Default)]
@@ -65,4 +68,7 @@ fn main () {
     let x = Qux:: { .. };
     assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, baq: 2, bay: 4, .. }, x));
     assert!(x.bak.is_empty());
+
+    let x = xc::A { .. };
+    assert!(matches!(xc::A { a: 42 }, x));
 }

From 2d71dd5a0f56bed87231ab223b80b64a99339371 Mon Sep 17 00:00:00 2001
From: Aarik Pokras <85502246+aarikpokras@users.noreply.github.com>
Date: Sat, 7 Dec 2024 16:42:59 -0500
Subject: [PATCH 144/197] Grammar fixes

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3690a9c93c52..d84d96a0e917 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ standard library, and documentation.
 
 ## Why Rust?
 
-- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages.
+- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages.
 
 - **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time.
 

From b203c73ccfb868c8d299aee34228ddc5b3545b9f Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 00:04:53 +0200
Subject: [PATCH 145/197] Avoid hashing completion-related ranges as those may
 change during /resolve query

---
 .../crates/rust-analyzer/src/lib.rs            | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

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 7cf88e60dba8..aed847958955 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -47,7 +47,7 @@ use self::lsp::ext as lsp_ext;
 #[cfg(test)]
 mod integrated_benchmarks;
 
-use ide::{CompletionItem, CompletionRelevance, TextEdit, TextRange};
+use ide::{CompletionItem, CompletionRelevance};
 use serde::de::DeserializeOwned;
 use tenthash::TentHasher;
 
@@ -65,18 +65,6 @@ pub fn from_json(
 }
 
 fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
-    fn hash_text_range(hasher: &mut TentHasher, text_range: &TextRange) {
-        hasher.update(u32::from(text_range.start()).to_le_bytes());
-        hasher.update(u32::from(text_range.end()).to_le_bytes());
-    }
-
-    fn hash_text_edit(hasher: &mut TentHasher, edit: &TextEdit) {
-        for indel in edit.iter() {
-            hasher.update(&indel.insert);
-            hash_text_range(hasher, &indel.delete);
-        }
-    }
-
     fn hash_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) {
         use ide_completion::{
             CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
@@ -130,8 +118,8 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     if let Some(label_detail) = &item.label_detail {
         hasher.update(label_detail);
     }
-    hash_text_range(&mut hasher, &item.source_range);
-    hash_text_edit(&mut hasher, &item.text_edit);
+    // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
+    // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
     hasher.update(item.kind.tag());
     hasher.update(&item.lookup);
     if let Some(detail) = &item.detail {

From 61c0b269d8655e1db902238f987f642b558f3947 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 01:04:02 +0200
Subject: [PATCH 146/197] Clippy fixes

---
 .../crates/rust-analyzer/src/handlers/request.rs          | 2 +-
 src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs   | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

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 851341dfdf35..3f2ef7616be5 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
@@ -1138,7 +1138,7 @@ pub(crate) fn handle_completion_resolve(
     };
 
     let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
-        let hash = completion_item_hash(&completion_item, resolve_data.for_ref);
+        let hash = completion_item_hash(completion_item, resolve_data.for_ref);
         hash == resolve_data.hash
     }) else {
         return Ok(original_completion);
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 aed847958955..8c8ac8de8144 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -71,7 +71,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             CompletionRelevanceTypeMatch,
         };
 
-        hasher.update(&[
+        hasher.update([
             u8::from(relevance.exact_name_match),
             u8::from(relevance.is_local),
             u8::from(relevance.is_name_already_imported),
@@ -86,7 +86,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             hasher.update(label);
         }
         if let Some(trait_) = &relevance.trait_ {
-            hasher.update(&[u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
+            hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
         }
         if let Some(postfix_match) = &relevance.postfix_match {
             let label = match postfix_match {
@@ -96,7 +96,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
             hasher.update(label);
         }
         if let Some(function) = &relevance.function {
-            hasher.update(&[u8::from(function.has_params), u8::from(function.has_self_param)]);
+            hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
             let label = match function.return_type {
                 CompletionRelevanceReturnType::Other => "other",
                 CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
@@ -108,7 +108,7 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     }
 
     let mut hasher = TentHasher::new();
-    hasher.update(&[
+    hasher.update([
         u8::from(is_ref_completion),
         u8::from(item.is_snippet),
         u8::from(item.deprecated),

From 5f99e96fbb7964c94f465897ebb59964db76628e Mon Sep 17 00:00:00 2001
From: Waffle Lapkin 
Date: Tue, 10 Dec 2024 00:05:40 +0100
Subject: [PATCH 147/197] only ignore `{flake,default}.nix` and
 `{.envrc,.direnv/}` in the root

this makes it so files in `src/nix-dev-shell` are *not* ignored, as they
should not be. note that `flake.lock` is still ignored globally.
---
 .gitignore | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.gitignore b/.gitignore
index ce9db8b861d0..f84a3704ca90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,12 +88,12 @@ package.json
 tests/rustdoc-gui/src/**.lock
 
 ## direnv
-.envrc
-.direnv/
+/.envrc
+/.direnv/
 
 ## nix
-flake.nix
+/flake.nix
 flake.lock
-default.nix
+/default.nix
 
 # Before adding new lines, see the comment at the top.

From b9afc78585fe1cbda5d6a3aed665338e7381ae79 Mon Sep 17 00:00:00 2001
From: Eric Holk 
Date: Mon, 9 Dec 2024 15:08:30 -0800
Subject: [PATCH 148/197] Remove rustc_const_stable attribute on const NOOP

This was accidentally reintroduced while editing #133089.
---
 library/core/src/task/wake.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 6762ed54e5c9..bfffcc24a46a 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -61,7 +61,6 @@ impl RawWaker {
     }
 
     #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")]
-    #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")]
     const NOOP: RawWaker = {
         const VTABLE: RawWakerVTable = RawWakerVTable::new(
             // Cloning just returns a new no-op raw waker

From 6058cdcccc4fcfa3c2ae2ce878cf229dae776041 Mon Sep 17 00:00:00 2001
From: Waffle Lapkin 
Date: Tue, 10 Dec 2024 00:09:40 +0100
Subject: [PATCH 149/197] remove instructions to git exclude files in
 `src/nix-dev-shell/envrc-*`

this is no longer needed as `.gitignore` contains both `/.envrc` and
`flake.lock` (and also `/.direnv/`)
---
 src/tools/nix-dev-shell/envrc-flake | 2 +-
 src/tools/nix-dev-shell/envrc-shell | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/tools/nix-dev-shell/envrc-flake b/src/tools/nix-dev-shell/envrc-flake
index 9def420f05cb..849ed1f4fc56 100644
--- a/src/tools/nix-dev-shell/envrc-flake
+++ b/src/tools/nix-dev-shell/envrc-flake
@@ -1,7 +1,7 @@
 # If you want to use this as an .envrc file to create a shell with necessery components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
-# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell && echo .envrc >> .git/info/exclude
+# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell
 
 if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then
   use flake path:./src/tools/nix-dev-shell
diff --git a/src/tools/nix-dev-shell/envrc-shell b/src/tools/nix-dev-shell/envrc-shell
index fb7231a6c30c..d8f900fe86a6 100644
--- a/src/tools/nix-dev-shell/envrc-shell
+++ b/src/tools/nix-dev-shell/envrc-shell
@@ -1,7 +1,7 @@
 # If you want to use this as an .envrc file to create a shell with necessery components 
 # to develop rustc, use the following command in the root of the rusr checkout:
 #	
-# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc && echo .envrc >> .git/info/exclude
+# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc
 
 use nix ./src/tools/nix-dev-shell/shell.nix
   

From 05d83185c3faac682a8a1d8a674a58afa180f292 Mon Sep 17 00:00:00 2001
From: Waffle Lapkin 
Date: Tue, 10 Dec 2024 00:19:29 +0100
Subject: [PATCH 150/197] provide `libz.so.1` in the `nix-dev-shell`

`libz.so.1` is needed for some (?) things...

i personally found myself in need of it when running `x t linkchecker`,
which failed when running cargo build script or something.

although there are also mentions of rustc itself needing it:

---
 src/tools/nix-dev-shell/flake.nix | 5 ++---
 src/tools/nix-dev-shell/shell.nix | 5 ++---
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/tools/nix-dev-shell/flake.nix b/src/tools/nix-dev-shell/flake.nix
index 8ab5e097427d..1b838bd2f7b3 100644
--- a/src/tools/nix-dev-shell/flake.nix
+++ b/src/tools/nix-dev-shell/flake.nix
@@ -24,9 +24,8 @@
           # Avoid creating text files for ICEs.
           RUSTC_ICE = "0";
           # Provide `libstdc++.so.6` for the self-contained lld.
-          LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [
-            stdenv.cc.cc.lib
-          ]}";
+          # Provide `libz.so.1`.
+          LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
         };
       }
     );
diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix
index 8a5cbb7c89e4..a3f5969bd812 100644
--- a/src/tools/nix-dev-shell/shell.nix
+++ b/src/tools/nix-dev-shell/shell.nix
@@ -13,7 +13,6 @@ pkgs.mkShell {
   # Avoid creating text files for ICEs.
   RUSTC_ICE = "0";
   # Provide `libstdc++.so.6` for the self-contained lld.
-  LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [
-    stdenv.cc.cc.lib
-  ]}";
+  # Provide `libz.so.1`
+  LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
 }

From 4007fc9a0f2ca14c26a494cf7d5e02c79485b43b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= 
Date: Mon, 9 Dec 2024 19:34:43 +0000
Subject: [PATCH 151/197] Tweak wording of non-const traits used as const
 bounds

Use verbose suggestions and add additional labels/notes.

Add more test cases for stable/nightly and feature enabled/disabled.
---
 compiler/rustc_hir_analysis/messages.ftl      |  12 ++-
 compiler/rustc_hir_analysis/src/collect.rs    |  16 ++-
 compiler/rustc_hir_analysis/src/errors.rs     |  19 +++-
 .../src/hir_ty_lowering/mod.rs                |  17 +++
 .../const-super-trait-nightly-disabled.stderr |  66 ++++++++++++
 .../const-super-trait-nightly-enabled.stderr  |  45 ++++++++
 .../const-super-trait-stable-disabled.stderr  |  64 +++++++++++
 .../const-super-trait-stable-enabled.stderr   |  54 ++++++++++
 .../const-super-trait.rs                      |  13 +++
 .../const-trait-stable-toolchain/rmake.rs     |  59 ++++++++++
 tests/ui/consts/const-try.stderr              |   4 +-
 tests/ui/consts/fn_trait_refs.stderr          |  65 ++++++++---
 .../consts/rustc-impl-const-stability.stderr  |   2 +-
 .../unstable-const-fn-in-libcore.stderr       |   9 +-
 .../impl-trait/normalize-tait-in-const.stderr |   9 +-
 .../ui/specialization/const_trait_impl.stderr |  27 +++--
 .../call-const-trait-method-pass.stderr       |   2 +-
 .../const-traits/call-generic-in-impl.stderr  |   9 +-
 .../call-generic-method-chain.stderr          |  20 +++-
 .../call-generic-method-dup-bound.stderr      |  20 +++-
 .../call-generic-method-pass.stderr           |  11 +-
 .../const-bounds-non-const-trait.stderr       |  20 +++-
 .../const-closure-parse-not-item.stderr       |  13 ++-
 .../const-closure-trait-method-fail.stderr    |   9 +-
 .../const-closure-trait-method.stderr         |   9 +-
 .../traits/const-traits/const-closures.stderr |  36 +++++--
 .../const-impl-requires-const-trait.stderr    |   9 +-
 .../const_derives/derive-const-gate.stderr    |   2 +-
 .../derive-const-non-const-type.stderr        |   2 +-
 .../const_derives/derive-const-use.stderr     |   8 +-
 .../derive-const-with-params.stderr           |   5 +-
 .../ice-112822-expected-type-for-param.stderr |  13 ++-
 .../effects/spec-effectvar-ice.stderr         |  25 +++--
 .../ice-119717-constant-lifetime.stderr       |   2 +-
 .../ice-123664-unexpected-bound-var.stderr    |   9 +-
 .../ice-126148-failed-to-normalize.stderr     |   4 +-
 .../non-const-op-in-closure-in-const.stderr   |   9 +-
 .../super-traits-fail-2.nn.stderr             |  19 +++-
 .../super-traits-fail-2.ny.stderr             |  31 +++++-
 .../super-traits-fail-3.nnn.stderr            | 102 ++++++++++++++++++
 .../super-traits-fail-3.nny.stderr            | 102 ++++++++++++++++++
 .../super-traits-fail-3.ny.stderr             |  49 ---------
 .../super-traits-fail-3.nyn.stderr            |  53 +++++++++
 .../super-traits-fail-3.nyy.stderr            |  53 +++++++++
 .../const-traits/super-traits-fail-3.rs       |  43 +++++---
 ....stderr => super-traits-fail-3.ynn.stderr} |  48 ++++++---
 .../super-traits-fail-3.yny.stderr            |  70 ++++++++++++
 ....stderr => super-traits-fail-3.yyn.stderr} |  23 ++--
 .../trait-default-body-stability.stderr       |   4 +-
 49 files changed, 1121 insertions(+), 194 deletions(-)
 create mode 100644 tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
 create mode 100644 tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
 create mode 100644 tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
 create mode 100644 tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
 create mode 100644 tests/run-make/const-trait-stable-toolchain/const-super-trait.rs
 create mode 100644 tests/run-make/const-trait-stable-toolchain/rmake.rs
 create mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
 create mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
 delete mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
 create mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
 create mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
 rename tests/ui/traits/const-traits/{super-traits-fail-3.nn.stderr => super-traits-fail-3.ynn.stderr} (51%)
 create mode 100644 tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
 rename tests/ui/traits/const-traits/{super-traits-fail-3.yn.stderr => super-traits-fail-3.yyn.stderr} (55%)

diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 070d63b48b7b..32498d9c5ab5 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -96,12 +96,14 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
 
 hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
 
-hir_analysis_const_bound_for_non_const_trait =
-    `{$modifier}` can only be applied to `#[const_trait]` traits
+hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits
+    .label = can't be applied to `{$trait_name}`
+    .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]`
+    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
 
-hir_analysis_const_impl_for_non_const_trait =
-    const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
-    .suggestion = mark `{$trait_name}` as const
+hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+    .label = this trait is not `const`
+    .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
     .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
     .adding = adding a non-const method body in the future would be a breaking change
 
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index a4636da3f621..1bd0585e7713 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1637,11 +1637,23 @@ fn check_impl_constness(
     }
 
     let trait_name = tcx.item_name(trait_def_id).to_string();
+    let (local_trait_span, suggestion_pre) =
+        match (trait_def_id.is_local(), tcx.sess.is_nightly_build()) {
+            (true, true) => (
+                Some(tcx.def_span(trait_def_id).shrink_to_lo()),
+                if tcx.features().const_trait_impl() {
+                    ""
+                } else {
+                    "enable `#![feature(const_trait_impl)]` in your crate and "
+                },
+            ),
+            (false, _) | (_, false) => (None, ""),
+        };
     Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
         trait_ref_span: hir_trait_ref.path.span,
         trait_name,
-        local_trait_span:
-            trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
+        local_trait_span,
+        suggestion_pre,
         marking: (),
         adding: (),
     }))
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 4142dcff226b..7f62ccc91f09 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -530,10 +530,16 @@ pub(crate) struct GenericArgsOnOverriddenImpl {
 #[diag(hir_analysis_const_impl_for_non_const_trait)]
 pub(crate) struct ConstImplForNonConstTrait {
     #[primary_span]
+    #[label]
     pub trait_ref_span: Span,
     pub trait_name: String,
-    #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
+    #[suggestion(
+        applicability = "machine-applicable",
+        code = "#[const_trait] ",
+        style = "verbose"
+    )]
     pub local_trait_span: Option,
+    pub suggestion_pre: &'static str,
     #[note]
     pub marking: (),
     #[note(hir_analysis_adding)]
@@ -544,8 +550,19 @@ pub(crate) struct ConstImplForNonConstTrait {
 #[diag(hir_analysis_const_bound_for_non_const_trait)]
 pub(crate) struct ConstBoundForNonConstTrait {
     #[primary_span]
+    #[label]
     pub span: Span,
     pub modifier: &'static str,
+    #[note]
+    pub def_span: Option,
+    pub suggestion_pre: &'static str,
+    #[suggestion(
+        applicability = "machine-applicable",
+        code = "#[const_trait] ",
+        style = "verbose"
+    )]
+    pub suggestion: Option,
+    pub trait_name: String,
 }
 
 #[derive(Diagnostic)]
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 3313339abb31..09e46517cea8 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -737,9 +737,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
             && !self.tcx().is_const_trait(trait_def_id)
         {
+            let (def_span, suggestion, suggestion_pre) =
+                match (trait_def_id.is_local(), self.tcx().sess.is_nightly_build()) {
+                    (true, true) => (
+                        None,
+                        Some(tcx.def_span(trait_def_id).shrink_to_lo()),
+                        if self.tcx().features().const_trait_impl() {
+                            ""
+                        } else {
+                            "enable `#![feature(const_trait_impl)]` in your crate and "
+                        },
+                    ),
+                    (false, _) | (_, false) => (Some(tcx.def_span(trait_def_id)), None, ""),
+                };
             self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
                 span,
                 modifier: constness.as_str(),
+                def_span,
+                trait_name: self.tcx().def_path_str(trait_def_id),
+                suggestion_pre,
+                suggestion,
             });
         }
 
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
new file mode 100644
index 000000000000..596f7c510be5
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr
@@ -0,0 +1,66 @@
+error: `~const` is not allowed here
+  --> const-super-trait.rs:7:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> const-super-trait.rs:7:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: const trait impls are experimental
+  --> const-super-trait.rs:7:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> const-super-trait.rs:9:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> const-super-trait.rs:7:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> const-super-trait.rs:9:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> const-super-trait.rs:10:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
new file mode 100644
index 000000000000..7235278d1bd7
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr
@@ -0,0 +1,45 @@
+error: `~const` is not allowed here
+  --> const-super-trait.rs:7:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> const-super-trait.rs:7:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> const-super-trait.rs:7:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> const-super-trait.rs:9:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> const-super-trait.rs:10:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
new file mode 100644
index 000000000000..eacdaf5e3690
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr
@@ -0,0 +1,64 @@
+error: `~const` is not allowed here
+ --> const-super-trait.rs:7:12
+  |
+7 | trait Bar: ~const Foo {}
+  |            ^^^^^^
+  |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+ --> const-super-trait.rs:7:1
+  |
+7 | trait Bar: ~const Foo {}
+  | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: const trait impls are experimental
+ --> const-super-trait.rs:7:12
+  |
+7 | trait Bar: ~const Foo {}
+  |            ^^^^^^
+  |
+  = note: see issue #67792  for more information
+
+error[E0658]: const trait impls are experimental
+ --> const-super-trait.rs:9:17
+  |
+9 | const fn foo(x: &T) {
+  |                 ^^^^^^
+  |
+  = note: see issue #67792  for more information
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> const-super-trait.rs:7:12
+  |
+7 | trait Bar: ~const Foo {}
+  |            ^^^^^^ can't be applied to `Foo`
+  |
+note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+ --> const-super-trait.rs:3:1
+  |
+3 | trait Foo {
+  | ^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> const-super-trait.rs:9:17
+  |
+9 | const fn foo(x: &T) {
+  |                 ^^^^^^ can't be applied to `Bar`
+  |
+note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+ --> const-super-trait.rs:7:1
+  |
+7 | trait Bar: ~const Foo {}
+  | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> const-super-trait.rs:10:7
+   |
+10 |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
new file mode 100644
index 000000000000..9ddec6e422c0
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr
@@ -0,0 +1,54 @@
+error: `~const` is not allowed here
+ --> const-super-trait.rs:7:12
+  |
+7 | trait Bar: ~const Foo {}
+  |            ^^^^^^
+  |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+ --> const-super-trait.rs:7:1
+  |
+7 | trait Bar: ~const Foo {}
+  | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel
+ --> const-super-trait.rs:1:30
+  |
+1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))]
+  |                              ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> const-super-trait.rs:7:12
+  |
+7 | trait Bar: ~const Foo {}
+  |            ^^^^^^ can't be applied to `Foo`
+  |
+note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+ --> const-super-trait.rs:3:1
+  |
+3 | trait Foo {
+  | ^^^^^^^^^
+
+error: `~const` can only be applied to `#[const_trait]` traits
+ --> const-super-trait.rs:9:17
+  |
+9 | const fn foo(x: &T) {
+  |                 ^^^^^^ can't be applied to `Bar`
+  |
+note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+ --> const-super-trait.rs:7:1
+  |
+7 | trait Bar: ~const Foo {}
+  | ^^^^^^^^^^^^^^^^^^^^^
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> const-super-trait.rs:10:7
+   |
+10 |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0015, E0554.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs b/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs
new file mode 100644
index 000000000000..b2ee96d79f70
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs
@@ -0,0 +1,13 @@
+#![cfg_attr(feature_enabled, feature(const_trait_impl))]
+
+trait Foo {
+    fn a(&self);
+}
+
+trait Bar: ~const Foo {}
+
+const fn foo(x: &T) {
+    x.a();
+}
+
+fn main() {}
diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs
new file mode 100644
index 000000000000..241de11ed59c
--- /dev/null
+++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs
@@ -0,0 +1,59 @@
+// Test output of const super trait errors in both stable and nightly.
+// We don't want to provide suggestions on stable that only make sense in nightly.
+
+use run_make_support::{diff, rustc};
+
+fn main() {
+    let out = rustc()
+        .input("const-super-trait.rs")
+        .env("RUSTC_BOOTSTRAP", "-1")
+        .cfg("feature_enabled")
+        .run_fail()
+        .assert_stderr_not_contains(
+            "as `#[const_trait]` to allow it to have `const` implementations",
+        )
+        .stderr_utf8();
+    diff()
+        .expected_file("const-super-trait-stable-enabled.stderr")
+        .normalize(
+            "may not be used on the .* release channel",
+            "may not be used on the NIGHTLY release channel",
+        )
+        .actual_text("(rustc)", &out)
+        .run();
+    let out = rustc()
+        .input("const-super-trait.rs")
+        .cfg("feature_enabled")
+        .ui_testing()
+        .run_fail()
+        .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark")
+        .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations")
+        .stderr_utf8();
+    diff()
+        .expected_file("const-super-trait-nightly-enabled.stderr")
+        .actual_text("(rustc)", &out)
+        .run();
+    let out = rustc()
+        .input("const-super-trait.rs")
+        .env("RUSTC_BOOTSTRAP", "-1")
+        .run_fail()
+        .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark")
+        .assert_stderr_not_contains(
+            "as `#[const_trait]` to allow it to have `const` implementations",
+        )
+        .stderr_utf8();
+    diff()
+        .expected_file("const-super-trait-stable-disabled.stderr")
+        .actual_text("(rustc)", &out)
+        .run();
+    let out = rustc()
+        .input("const-super-trait.rs")
+        .ui_testing()
+        .run_fail()
+        .assert_stderr_contains("enable `#![feature(const_trait_impl)]` in your crate and mark")
+        .stderr_utf8();
+    diff()
+        .expected_file("const-super-trait-nightly-disabled.stderr")
+        .actual_text("(rustc)", &out)
+        .run();
+}
diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr
index abb03a74c82a..4209ca1d5266 100644
--- a/tests/ui/consts/const-try.stderr
+++ b/tests/ui/consts/const-try.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t
   --> $DIR/const-try.rs:15:12
    |
 LL | impl const FromResidual for TryMe {
-   |            ^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -11,7 +11,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
   --> $DIR/const-try.rs:22:12
    |
 LL | impl const Try for TryMe {
-   |            ^^^
+   |            ^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index bb7ff76b1255..e0dbecff8e58 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -14,110 +14,145 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:14:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:14:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:14:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:21:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
+   |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:21:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
    |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:21:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
    |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:28:8
    |
 LL |     T: ~const FnOnce<()>,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnOnce`
+   |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:28:8
    |
 LL |     T: ~const FnOnce<()>,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:28:8
    |
 LL |     T: ~const FnOnce<()>,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:35:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:35:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:35:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:49:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
+   |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:49:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
    |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:49:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |        ^^^^^^
+   |        ^^^^^^ can't be applied to `FnMut`
    |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied
diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr
index 4a58b5c86034..19c6bb5907f8 100644
--- a/tests/ui/consts/rustc-impl-const-stability.stderr
+++ b/tests/ui/consts/rustc-impl-const-stability.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait]
   --> $DIR/rustc-impl-const-stability.rs:15:12
    |
 LL | impl const Default for Data {
-   |            ^^^^^^^
+   |            ^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index f40c1871e90b..32693edbfcbd 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/unstable-const-fn-in-libcore.rs:19:32
    |
 LL |     const fn unwrap_or_else T>(self, f: F) -> T {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
+   |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/unstable-const-fn-in-libcore.rs:19:32
    |
 LL |     const fn unwrap_or_else T>(self, f: F) -> T {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index 1dd84f10ad86..0f79cefeaecb 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/normalize-tait-in-const.rs:26:35
    |
 LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                   ^^^^^^
+   |                                   ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/normalize-tait-in-const.rs:26:35
    |
 LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                   ^^^^^^
+   |                                   ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index 607fc06823e4..3e1260ff09c9 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -2,42 +2,57 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:34:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
+   |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:40:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
+   |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:46:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
+   |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:40:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
    |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:34:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
    |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:46:9
    |
 LL | impl const A for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `Default`
    |
+note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/default.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
index 1e48a0331cca..ef494bde98ce 100644
--- a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/call-const-trait-method-pass.rs:15:12
    |
 LL | impl const PartialEq for Int {
-   |            ^^^^^^^^^
+   |            ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
index 52ee04425b2c..58d0997f5a34 100644
--- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-in-impl.rs:10:9
    |
 LL | impl const MyPartialEq for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-in-impl.rs:10:9
    |
 LL | impl const MyPartialEq for T {
-   |         ^^^^^^
+   |         ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const fn `::eq` in constant functions
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
index 21fb19daad4a..d7a2a1864940 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/call-generic-method-chain.rs:11:12
    |
 LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
+   |            ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -11,28 +11,38 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-chain.rs:20:25
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-chain.rs:20:25
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-chain.rs:24:33
    |
 LL | const fn equals_self_wrapper(t: &T) -> bool {
-   |                                 ^^^^^^
+   |                                 ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-chain.rs:24:33
    |
 LL | const fn equals_self_wrapper(t: &T) -> bool {
-   |                                 ^^^^^^
+   |                                 ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const operator in constant functions
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
index 845949a38bf5..90465d0a5b2d 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/call-generic-method-dup-bound.rs:9:12
    |
 LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
+   |            ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -11,28 +11,38 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-dup-bound.rs:20:37
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                                     ^^^^^^
+   |                                     ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-dup-bound.rs:20:37
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                                     ^^^^^^
+   |                                     ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-dup-bound.rs:27:30
    |
 LL | const fn equals_self2(t: &T) -> bool {
-   |                              ^^^^^^
+   |                              ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-dup-bound.rs:27:30
    |
 LL | const fn equals_self2(t: &T) -> bool {
-   |                              ^^^^^^
+   |                              ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const operator in constant functions
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
index 0c0037e36b86..a7626a4e99d2 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/call-generic-method-pass.rs:11:12
    |
 LL | impl const PartialEq for S {
-   |            ^^^^^^^^^
+   |            ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -11,14 +11,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-pass.rs:20:25
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/call-generic-method-pass.rs:20:25
    |
 LL | const fn equals_self(t: &T) -> bool {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `PartialEq`
    |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const operator in constant functions
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index 2436c97ccf2c..f97d3a9181e0 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -2,21 +2,35 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform() {}
-   |                     ^^^^^^
+   |                     ^^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform() {}
-   |                     ^^^^^^
+   |                     ^^^^^^ can't be applied to `NonConst`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
 
 error: `const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-bounds-non-const-trait.rs:10:15
    |
 LL | fn operate() {}
-   |               ^^^^^
+   |               ^^^^^ can't be applied to `NonConst`
+   |
+help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait NonConst {}
+   | ++++++++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 0970cd5225fb..57afa2257b7d 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -2,22 +2,29 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index a76dc3e82af7..2a97846ccb44 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method-fail.rs:14:32
    |
 LL | const fn need_const_closure i32>(x: T) -> i32 {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
+   |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method-fail.rs:14:32
    |
 LL | const fn need_const_closure i32>(x: T) -> i32 {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index d37ff3d727ce..9c63b7e63a65 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method.rs:14:32
    |
 LL | const fn need_const_closure i32>(x: T) -> i32 {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
+   |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method.rs:14:32
    |
 LL | const fn need_const_closure i32>(x: T) -> i32 {
-   |                                ^^^^^^
+   |                                ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index 8ceaae16d8e7..92f3ba208207 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -2,56 +2,76 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:8:12
    |
 LL |         F: ~const FnOnce() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `FnOnce`
+   |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:9:12
    |
 LL |         F: ~const FnMut() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `FnMut`
+   |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:10:12
    |
 LL |         F: ~const Fn() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:8:12
    |
 LL |         F: ~const FnOnce() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `FnOnce`
    |
+note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:9:12
    |
 LL |         F: ~const FnMut() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `FnMut`
    |
+note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:10:12
    |
 LL |         F: ~const Fn() -> u8,
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:23:20
    |
 LL | const fn answer u8>(f: &F) -> u8 {
-   |                    ^^^^^^
+   |                    ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:23:20
    |
 LL | const fn answer u8>(f: &F) -> u8 {
-   |                    ^^^^^^
+   |                    ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const closure in constant functions
diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
index bcaae3819495..c728eda069ec 100644
--- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr
@@ -1,14 +1,15 @@
 error: const `impl` for trait `A` which is not marked with `#[const_trait]`
   --> $DIR/const-impl-requires-const-trait.rs:6:12
    |
-LL | pub trait A {}
-   | - help: mark `A` as const: `#[const_trait]`
-LL |
 LL | impl const A for () {}
-   |            ^
+   |            ^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
+help: mark `A` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] pub trait A {}
+   | ++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
index 95f6f32f21d3..fae871a4c85a 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr
@@ -11,7 +11,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait]
   --> $DIR/derive-const-gate.rs:1:16
    |
 LL | #[derive_const(Default)]
-   |                ^^^^^^^
+   |                ^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index 9492000a5631..8a6401afcf19 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait]
   --> $DIR/derive-const-non-const-type.rs:10:16
    |
 LL | #[derive_const(Default)]
-   |                ^^^^^^^
+   |                ^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index 6f4fc90f6363..3b06f4d801a4 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -14,7 +14,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait]
   --> $DIR/derive-const-use.rs:7:12
    |
 LL | impl const Default for A {
-   |            ^^^^^^^
+   |            ^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -23,7 +23,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait]
   --> $DIR/derive-const-use.rs:15:16
    |
 LL | #[derive_const(Default, PartialEq)]
-   |                ^^^^^^^
+   |                ^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -33,7 +33,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/derive-const-use.rs:11:12
    |
 LL | impl const PartialEq for A {
-   |            ^^^^^^^^^
+   |            ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -42,7 +42,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/derive-const-use.rs:15:25
    |
 LL | #[derive_const(Default, PartialEq)]
-   |                         ^^^^^^^^^
+   |                         ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
index 21cf64f89ea8..6b1405712ef7 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
@@ -2,13 +2,16 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai
   --> $DIR/derive-const-with-params.rs:7:16
    |
 LL | #[derive_const(PartialEq)]
-   |                ^^^^^^^^^
+   |                ^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `~const` can only be applied to `#[const_trait]` traits
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
 
 error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/derive-const-with-params.rs:8:23
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index 879d966b1f97..280f8807f5fd 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -12,22 +12,29 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                         ^^^^^^
+   |                         ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const operator in constant functions
diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
index 5659102c5e5c..474d96698d56 100644
--- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
@@ -1,32 +1,39 @@
 error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
   --> $DIR/spec-effectvar-ice.rs:10:15
    |
-LL | trait Foo {}
-   | - help: mark `Foo` as const: `#[const_trait]`
-LL |
 LL | impl const Foo for T {}
-   |               ^^^
+   |               ^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {}
+   | ++++++++++++++
 
 error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
   --> $DIR/spec-effectvar-ice.rs:13:15
    |
-LL | trait Foo {}
-   | - help: mark `Foo` as const: `#[const_trait]`
-...
 LL | impl const Foo for T where T: const Specialize {}
-   |               ^^^
+   |               ^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {}
+   | ++++++++++++++
 
 error: `const` can only be applied to `#[const_trait]` traits
   --> $DIR/spec-effectvar-ice.rs:13:34
    |
 LL | impl const Foo for T where T: const Specialize {}
-   |                                  ^^^^^
+   |                                  ^^^^^ can't be applied to `Specialize`
+   |
+help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Specialize {}
+   | ++++++++++++++
 
 error: specialization impl does not specialize any associated items
   --> $DIR/spec-effectvar-ice.rs:13:1
diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
index 9e22422ad3b9..5af263de28c4 100644
--- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
+++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t
   --> $DIR/ice-119717-constant-lifetime.rs:6:15
    |
 LL | impl const FromResidual for T {
-   |               ^^^^^^^^^^^^
+   |               ^^^^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
index 1178c90fce54..821b257af880 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
    |
 LL | const fn with_positive() {}
-   |                           ^^^^^^
+   |                           ^^^^^^ can't be applied to `Fn`
+   |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
    |
 LL | const fn with_positive() {}
-   |                           ^^^^^^
+   |                           ^^^^^^ can't be applied to `Fn`
    |
+note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/ops/function.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index 9bd493e5fdbb..41f99c2d375e 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t
   --> $DIR/ice-126148-failed-to-normalize.rs:8:12
    |
 LL | impl const FromResidual for TryMe {}
-   |            ^^^^^^^^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -19,7 +19,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
   --> $DIR/ice-126148-failed-to-normalize.rs:12:12
    |
 LL | impl const Try for TryMe {
-   |            ^^^
+   |            ^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
index 837effb7ca4c..4ddb1e8c5a9f 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/non-const-op-in-closure-in-const.rs:10:44
    |
 LL | impl const Convert for A where B: ~const From {
-   |                                            ^^^^^^
+   |                                            ^^^^^^ can't be applied to `From`
+   |
+note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/non-const-op-in-closure-in-const.rs:10:44
    |
 LL | impl const Convert for A where B: ~const From {
-   |                                            ^^^^^^
+   |                                            ^^^^^^ can't be applied to `From`
    |
+note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0015]: cannot call non-const fn `>::from` in constant functions
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index e7f54b4c5bdd..51b88cf87022 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -14,23 +14,36 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error[E0015]: cannot call non-const fn `::a` in constant functions
   --> $DIR/super-traits-fail-2.rs:20:7
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index a09fe81f7169..38fb6f05412f 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -2,39 +2,60 @@ error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:11:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error[E0015]: cannot call non-const fn `::a` in constant functions
   --> $DIR/super-traits-fail-2.rs:20:7
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
new file mode 100644
index 000000000000..fd802fde5bd5
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr
@@ -0,0 +1,102 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-3.rs:23:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:36:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
new file mode 100644
index 000000000000..fd802fde5bd5
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr
@@ -0,0 +1,102 @@
+error: `~const` is not allowed here
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
+  --> $DIR/super-traits-fail-3.rs:23:1
+   |
+LL | trait Bar: ~const Foo {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:36:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0015, E0658.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
deleted file mode 100644
index a880c2a22061..000000000000
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
+++ /dev/null
@@ -1,49 +0,0 @@
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
-   |
-LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0015]: cannot call non-const fn `::a` in constant functions
-  --> $DIR/super-traits-fail-3.rs:24:7
-   |
-LL |     x.a();
-   |       ^^^
-   |
-   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
new file mode 100644
index 000000000000..8abda1c8f8af
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr
@@ -0,0 +1,53 @@
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future.
+  --> $DIR/super-traits-fail-3.rs:15:37
+   |
+LL | #[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)]
+   |                                     ^^^^^^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future.
+  --> $DIR/super-traits-fail-3.rs:21:37
+   |
+LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
+   |                                     ^^^^^^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: cannot call conditionally-const method `::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:36:5
+   |
+LL |     x.a();
+   |     ^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
new file mode 100644
index 000000000000..8abda1c8f8af
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr
@@ -0,0 +1,53 @@
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/super-traits-fail-3.rs:32:17
+   |
+LL | const fn foo(x: &T) {
+   |                 ^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future.
+  --> $DIR/super-traits-fail-3.rs:15:37
+   |
+LL | #[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)]
+   |                                     ^^^^^^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future.
+  --> $DIR/super-traits-fail-3.rs:21:37
+   |
+LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
+   |                                     ^^^^^^^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: cannot call conditionally-const method `::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:36:5
+   |
+LL |     x.a();
+   |     ^^^^^
+   |
+   = note: see issue #67792  for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs
index bd95ae8d96a9..aa27554e7f89 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.rs
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs
@@ -1,29 +1,42 @@
 //@ compile-flags: -Znext-solver
-#![feature(const_trait_impl)]
+#![cfg_attr(any(yyy, yyn, yny, ynn), feature(const_trait_impl))]
 
-//@ revisions: yy yn ny nn
-//@[yy] check-pass
+//@ revisions: yyy yyn yny ynn nyy nyn nny nnn
+//@[yyy] check-pass
+/// yyy: feature enabled, Foo is const, Bar is const
+/// yyn: feature enabled, Foo is const, Bar is not const
+/// yny: feature enabled, Foo is not const, Bar is const
+/// ynn: feature enabled, Foo is not const, Bar is not const
+/// nyy: feature not enabled, Foo is const, Bar is const
+/// nyn: feature not enabled, Foo is const, Bar is not const
+/// nny: feature not enabled, Foo is not const, Bar is const
+/// nnn: feature not enabled, Foo is not const, Bar is not const
 
-#[cfg_attr(any(yy, yn), const_trait)]
+#[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)]
+//[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future
 trait Foo {
     fn a(&self);
 }
 
-#[cfg_attr(any(yy, ny), const_trait)]
+#[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)]
+//[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future
 trait Bar: ~const Foo {}
-//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]`
-//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here
+//[yny,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yny]~^^^^ ERROR: `~const` can only be applied to `#[const_trait]`
+//[yny]~| ERROR: `~const` can only be applied to `#[const_trait]`
+//[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `~const` is not allowed here
+//[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental
 
 const fn foo(x: &T) {
-    //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
-    //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
+    //[yyn,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+    //[yyn,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]`
+    //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental
     x.a();
-    //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
-    //[nn,ny]~^^ ERROR: cannot call non-const fn `::a` in constant functions
+    //[yyn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied
+    //[ynn,yny,nny,nnn]~^^ ERROR: cannot call non-const fn `::a` in constant functions
+    //[nyy,nyn]~^^^ ERROR: cannot call conditionally-const method `::a` in constant functions
 }
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
similarity index 51%
rename from tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
rename to tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
index 599b8c826f7a..16424696eeb5 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr
@@ -1,53 +1,75 @@
 error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-3.rs:13:12
+  --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^
    |
 note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-3.rs:13:1
+  --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
+  --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
+  --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:13:12
+  --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: ~const Foo {}
-   |            ^^^^^^
+   |            ^^^^^^ can't be applied to `Foo`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:21:17
+  --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo(x: &T) {
-   |                 ^^^^^^
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:21:17
+  --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo(x: &T) {
-   |                 ^^^^^^
+   |                 ^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
 
 error[E0015]: cannot call non-const fn `::a` in constant functions
-  --> $DIR/super-traits-fail-3.rs:24:7
+  --> $DIR/super-traits-fail-3.rs:36:7
    |
 LL |     x.a();
    |       ^^^
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
new file mode 100644
index 000000000000..c81544c4bf5b
--- /dev/null
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr
@@ -0,0 +1,70 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/super-traits-fail-3.rs:23:12
+   |
+LL | trait Bar: ~const Foo {}
+   |            ^^^^^^ can't be applied to `Foo`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Foo {
+   | ++++++++++++++
+
+error[E0015]: cannot call non-const fn `::a` in constant functions
+  --> $DIR/super-traits-fail-3.rs:36:7
+   |
+LL |     x.a();
+   |       ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
similarity index 55%
rename from tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
rename to tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
index ecee348222d1..3270611dace2 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr
@@ -1,31 +1,40 @@
 error: `~const` is not allowed here
-  --> $DIR/super-traits-fail-3.rs:13:12
+  --> $DIR/super-traits-fail-3.rs:23:12
    |
 LL | trait Bar: ~const Foo {}
    |            ^^^^^^
    |
 note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds
-  --> $DIR/super-traits-fail-3.rs:13:1
+  --> $DIR/super-traits-fail-3.rs:23:1
    |
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:21:17
+  --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo(x: &T) {
-   |                 ^^^^^^
+   |                 ^^^^^^ can't be applied to `Bar`
+   |
+help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:21:17
+  --> $DIR/super-traits-fail-3.rs:32:17
    |
 LL | const fn foo(x: &T) {
-   |                 ^^^^^^
+   |                 ^^^^^^ can't be applied to `Bar`
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations
+   |
+LL | #[const_trait] trait Bar: ~const Foo {}
+   | ++++++++++++++
 
 error[E0277]: the trait bound `T: ~const Foo` is not satisfied
-  --> $DIR/super-traits-fail-3.rs:24:7
+  --> $DIR/super-traits-fail-3.rs:36:7
    |
 LL |     x.a();
    |       ^
diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
index b471cb81c3b8..77b81211e815 100644
--- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr
+++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr
@@ -2,7 +2,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
   --> $DIR/trait-default-body-stability.rs:19:12
    |
 LL | impl const Try for T {
-   |            ^^^
+   |            ^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
@@ -11,7 +11,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t
   --> $DIR/trait-default-body-stability.rs:34:12
    |
 LL | impl const FromResidual for T {
-   |            ^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^ this trait is not `const`
    |
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change

From 6e2e9f676c03128e3c988c393904e3e6181b938b Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Tue, 10 Dec 2024 01:08:03 +0000
Subject: [PATCH 152/197] Don't ICE when encountering never in pattern

---
 compiler/rustc_hir_typeck/src/expr.rs         |  6 +++++-
 tests/ui/never_type/never-in-range-pat.rs     | 16 ++++++++++++++++
 tests/ui/never_type/never-in-range-pat.stderr | 11 +++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/never_type/never-in-range-pat.rs
 create mode 100644 tests/ui/never_type/never-in-range-pat.stderr

diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 04c06169d330..1676337ab484 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -402,6 +402,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true,
 
+            hir::Node::Pat(_) => {
+                self.dcx().span_delayed_bug(expr.span, "place expr not allowed in pattern");
+                true
+            }
+
             // These nodes do not have direct sub-exprs.
             hir::Node::Param(_)
             | hir::Node::Item(_)
@@ -414,7 +419,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | hir::Node::Ty(_)
             | hir::Node::AssocItemConstraint(_)
             | hir::Node::TraitRef(_)
-            | hir::Node::Pat(_)
             | hir::Node::PatField(_)
             | hir::Node::LetStmt(_)
             | hir::Node::Synthetic
diff --git a/tests/ui/never_type/never-in-range-pat.rs b/tests/ui/never_type/never-in-range-pat.rs
new file mode 100644
index 000000000000..ae2d76c172ea
--- /dev/null
+++ b/tests/ui/never_type/never-in-range-pat.rs
@@ -0,0 +1,16 @@
+// Regression test for .
+
+// Make sure we don't ICE when there's `!` in a range pattern.
+//
+// This shouldn't be allowed anyways, but we only deny it during MIR
+// building, so make sure we handle it semi-gracefully during typeck.
+
+#![feature(never_type)]
+
+fn main() {
+    let x: !;
+    match 1 {
+        0..x => {}
+        //~^ ERROR only `char` and numeric types are allowed in range patterns
+    }
+}
diff --git a/tests/ui/never_type/never-in-range-pat.stderr b/tests/ui/never_type/never-in-range-pat.stderr
new file mode 100644
index 000000000000..c78be5350e0f
--- /dev/null
+++ b/tests/ui/never_type/never-in-range-pat.stderr
@@ -0,0 +1,11 @@
+error[E0029]: only `char` and numeric types are allowed in range patterns
+  --> $DIR/never-in-range-pat.rs:13:12
+   |
+LL |         0..x => {}
+   |         -  ^ this is of type `!` but it should be `char` or numeric
+   |         |
+   |         this is of type `{integer}`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0029`.

From a73a6a00583db23af2f47eff6965dee1ccac8167 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Fri, 1 Nov 2024 10:40:19 -0400
Subject: [PATCH 153/197] Add diagnostic fix to remove unnecessary wrapper in
 type mismatch

I also reorganized the tests in a more logical order, and removed the redundant `test_` prefix from their names.
---
 .../src/handlers/type_mismatch.rs             | 449 +++++++++++++++---
 1 file changed, 381 insertions(+), 68 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 93fe9374a3ee..8994ab50e670 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,14 +1,17 @@
 use either::Either;
-use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
-use ide_db::text_edit::TextEdit;
-use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
+use hir::{db::ExpandDatabase, CallableKind, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use ide_db::{
+    famous_defs::FamousDefs,
+    source_change::{SourceChange, SourceChangeBuilder},
+    text_edit::TextEdit,
+};
 use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        BlockExpr, Expr, ExprStmt,
+        make, BlockExpr, Expr, ExprStmt, HasArgList,
     },
-    AstNode, AstPtr, TextSize,
+    ted, AstNode, AstPtr, TextSize,
 };
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -63,6 +66,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option,
+    d: &hir::TypeMismatch,
+    expr_ptr: &InFile>,
+    acc: &mut Vec,
+) -> Option<()> {
+    let db = ctx.sema.db;
+    let root = db.parse_or_expand(expr_ptr.file_id);
+    let expr = expr_ptr.value.to_node(&root);
+    let expr = ctx.sema.original_ast_node(expr.clone())?;
+
+    let Expr::CallExpr(call_expr) = expr else {
+        return None;
+    };
+
+    let callable = ctx.sema.resolve_expr_as_callable(&call_expr.expr()?)?;
+    let CallableKind::TupleEnumVariant(variant) = callable.kind() else {
+        return None;
+    };
+
+    let actual_enum = d.actual.as_adt()?.as_enum()?;
+    let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(call_expr.syntax())?.krate());
+    let core_option = famous_defs.core_option_Option();
+    let core_result = famous_defs.core_result_Result();
+    if Some(actual_enum) != core_option && Some(actual_enum) != core_result {
+        return None;
+    }
+
+    let inner_type = variant.fields(db).first()?.ty_with_args(db, d.actual.type_arguments());
+    if !d.expected.could_unify_with(db, &inner_type) {
+        return None;
+    }
+
+    let inner_arg = call_expr.arg_list()?.args().next()?;
+
+    let mut builder = SourceChangeBuilder::new(expr_ptr.file_id.original_file(ctx.sema.db));
+
+    match inner_arg {
+        // We're returning `()`
+        Expr::TupleExpr(tup) if tup.fields().next().is_none() => {
+            let parent = call_expr
+                .syntax()
+                .parent()
+                .and_then(Either::::cast)?;
+
+            match parent {
+                Either::Left(ret_expr) => {
+                    let old = builder.make_mut(ret_expr);
+                    let new = make::expr_return(None).clone_for_update();
+
+                    ted::replace(old.syntax(), new.syntax());
+                }
+                Either::Right(stmt_list) => {
+                    if stmt_list.statements().count() == 0 {
+                        let block = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)?;
+                        let old = builder.make_mut(block);
+                        let new = make::expr_empty_block().clone_for_update();
+
+                        ted::replace(old.syntax(), new.syntax());
+                    } else {
+                        let old = builder.make_syntax_mut(stmt_list.syntax().parent()?);
+                        let new = make::block_expr(stmt_list.statements(), None).clone_for_update();
+
+                        ted::replace(old, new.syntax());
+                    }
+                }
+            }
+        }
+        _ => {
+            let call_mut = builder.make_mut(call_expr.clone());
+            ted::replace(call_mut.syntax(), inner_arg.clone_for_update().syntax());
+        }
+    }
+
+    let name = format!("Remove unnecessary {}() wrapper", variant.name(db).as_str());
+    acc.push(fix(
+        "remove_unnecessary_wrapper",
+        &name,
+        builder.finish(),
+        call_expr.syntax().text_range(),
+    ));
+    Some(())
+}
+
 fn remove_semicolon(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::TypeMismatch,
@@ -243,7 +331,7 @@ fn str_ref_to_owned(
 #[cfg(test)]
 mod tests {
     use crate::tests::{
-        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_no_fix,
+        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_has_fix, check_no_fix,
     };
 
     #[test]
@@ -260,7 +348,7 @@ fn test(_arg: &i32) {}
     }
 
     #[test]
-    fn test_add_reference_to_int() {
+    fn add_reference_to_int() {
         check_fix(
             r#"
 fn main() {
@@ -278,7 +366,7 @@ fn test(_arg: &i32) {}
     }
 
     #[test]
-    fn test_add_mutable_reference_to_int() {
+    fn add_mutable_reference_to_int() {
         check_fix(
             r#"
 fn main() {
@@ -296,7 +384,7 @@ fn test(_arg: &mut i32) {}
     }
 
     #[test]
-    fn test_add_reference_to_array() {
+    fn add_reference_to_array() {
         check_fix(
             r#"
 //- minicore: coerce_unsized
@@ -315,7 +403,7 @@ fn test(_arg: &[i32]) {}
     }
 
     #[test]
-    fn test_add_reference_with_autoderef() {
+    fn add_reference_with_autoderef() {
         check_fix(
             r#"
 //- minicore: coerce_unsized, deref
@@ -348,7 +436,7 @@ fn test(_arg: &Bar) {}
     }
 
     #[test]
-    fn test_add_reference_to_method_call() {
+    fn add_reference_to_method_call() {
         check_fix(
             r#"
 fn main() {
@@ -372,7 +460,7 @@ impl Test {
     }
 
     #[test]
-    fn test_add_reference_to_let_stmt() {
+    fn add_reference_to_let_stmt() {
         check_fix(
             r#"
 fn main() {
@@ -388,7 +476,7 @@ fn main() {
     }
 
     #[test]
-    fn test_add_reference_to_macro_call() {
+    fn add_reference_to_macro_call() {
         check_fix(
             r#"
 macro_rules! thousand {
@@ -416,7 +504,7 @@ fn main() {
     }
 
     #[test]
-    fn test_add_mutable_reference_to_let_stmt() {
+    fn add_mutable_reference_to_let_stmt() {
         check_fix(
             r#"
 fn main() {
@@ -431,29 +519,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn test_wrap_return_type_option() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Option {
-    if y == 0 {
-        return None;
-    }
-    x / y$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Option {
-    if y == 0 {
-        return None;
-    }
-    Some(x / y)
-}
-"#,
-        );
-    }
-
     #[test]
     fn const_generic_type_mismatch() {
         check_diagnostics(
@@ -487,7 +552,53 @@ fn div(x: i32, y: i32) -> Option {
     }
 
     #[test]
-    fn test_wrap_return_type_option_tails() {
+    fn wrap_return_type() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Result {
+    if y == 0 {
+        return Err(());
+    }
+    x / y$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Result {
+    if y == 0 {
+        return Err(());
+    }
+    Ok(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn wrap_return_type_option() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> Option {
+    if y == 0 {
+        return None;
+    }
+    x / y$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> Option {
+    if y == 0 {
+        return None;
+    }
+    Some(x / y)
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn wrap_return_type_option_tails() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -516,30 +627,7 @@ fn div(x: i32, y: i32) -> Option {
     }
 
     #[test]
-    fn test_wrap_return_type() {
-        check_fix(
-            r#"
-//- minicore: option, result
-fn div(x: i32, y: i32) -> Result {
-    if y == 0 {
-        return Err(());
-    }
-    x / y$0
-}
-"#,
-            r#"
-fn div(x: i32, y: i32) -> Result {
-    if y == 0 {
-        return Err(());
-    }
-    Ok(x / y)
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_wrap_return_type_handles_generic_functions() {
+    fn wrap_return_type_handles_generic_functions() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -562,7 +650,7 @@ fn div(x: T) -> Result {
     }
 
     #[test]
-    fn test_wrap_return_type_handles_type_aliases() {
+    fn wrap_return_type_handles_type_aliases() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -589,7 +677,7 @@ fn div(x: i32, y: i32) -> MyResult {
     }
 
     #[test]
-    fn test_wrapped_unit_as_block_tail_expr() {
+    fn wrapped_unit_as_block_tail_expr() {
         check_fix(
             r#"
 //- minicore: result
@@ -619,7 +707,7 @@ fn foo() -> Result<(), ()> {
     }
 
     #[test]
-    fn test_wrapped_unit_as_return_expr() {
+    fn wrapped_unit_as_return_expr() {
         check_fix(
             r#"
 //- minicore: result
@@ -642,7 +730,7 @@ fn foo(b: bool) -> Result<(), String> {
     }
 
     #[test]
-    fn test_in_const_and_static() {
+    fn wrap_in_const_and_static() {
         check_fix(
             r#"
 //- minicore: option, result
@@ -664,7 +752,7 @@ const _: Option<()> = {Some(())};
     }
 
     #[test]
-    fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
+    fn wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
         check_no_fix(
             r#"
 //- minicore: option, result
@@ -674,7 +762,7 @@ fn foo() -> Result<(), i32> { 0$0 }
     }
 
     #[test]
-    fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
+    fn wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() {
         check_no_fix(
             r#"
 //- minicore: option, result
@@ -685,6 +773,231 @@ fn foo() -> SomeOtherEnum { 0$0 }
         );
     }
 
+    #[test]
+    fn unwrap_return_type() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    Ok(x / y)$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_option() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    Some(x / y)$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_option_tails() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        42
+    } else if true {
+        Some(100)$0
+    } else {
+        0
+    }
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        42
+    } else if true {
+        100
+    } else {
+        0
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_handles_generic_functions() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: T) -> T {
+    if x == 0 {
+        panic!();
+    }
+    $0Ok(x)
+}
+"#,
+            r#"
+fn div(x: T) -> T {
+    if x == 0 {
+        panic!();
+    }
+    x
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_handles_type_aliases() {
+        check_fix(
+            r#"
+//- minicore: option, result
+type MyResult = T;
+
+fn div(x: i32, y: i32) -> MyResult {
+    if y == 0 {
+        panic!();
+    }
+    Ok(x $0/ y)
+}
+"#,
+            r#"
+type MyResult = T;
+
+fn div(x: i32, y: i32) -> MyResult {
+    if y == 0 {
+        panic!();
+    }
+    x / y
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_tail_expr() {
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> () {
+    println!("Hello, world!");
+    Ok(())$0
+}
+            "#,
+            r#"
+fn foo() -> () {
+    println!("Hello, world!");
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_to_empty_block() {
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> () {
+    Ok(())$0
+}
+            "#,
+            r#"
+fn foo() -> () {}
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_to_return_expr() {
+        check_has_fix(
+            r#"
+//- minicore: result
+fn foo(b: bool) -> () {
+    if b {
+        return $0Ok(());
+    }
+
+    panic!("oh dear");
+}"#,
+            r#"
+fn foo(b: bool) -> () {
+    if b {
+        return;
+    }
+
+    panic!("oh dear");
+}"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_in_const_and_static() {
+        check_fix(
+            r#"
+//- minicore: option, result
+static A: () = {Some(($0))};
+            "#,
+            r#"
+static A: () = {};
+            "#,
+        );
+        check_fix(
+            r#"
+//- minicore: option, result
+const _: () = {Some(($0))};
+            "#,
+            r#"
+const _: () = {};
+            "#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_not_applicable_when_inner_type_does_not_match_return_type() {
+        check_no_fix(
+            r#"
+//- minicore: result
+fn foo() -> i32 { $0Ok(()) }
+"#,
+        );
+    }
+
+    #[test]
+    fn unwrap_return_type_not_applicable_when_wrapper_type_is_not_result_or_option() {
+        check_no_fix(
+            r#"
+//- minicore: option, result
+enum SomeOtherEnum { Ok(i32), Err(String) }
+
+fn foo() -> i32 { SomeOtherEnum::Ok($042) }
+"#,
+        );
+    }
+
     #[test]
     fn remove_semicolon() {
         check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#);

From 4898f3f5919824c955510a60e09b3353e69f2e2b Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Thu, 14 Nov 2024 15:57:58 -0500
Subject: [PATCH 154/197] fix: Handle the final statement in
 `SyntaxFactory::block_expr` properly

This caused a bug that was rather tricky to hunt down!
---
 .../src/ast/syntax_factory/constructors.rs    | 21 +++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 54f17bd721d5..44f67d83dc6b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -58,22 +58,31 @@ impl SyntaxFactory {
         tail_expr: Option,
     ) -> ast::BlockExpr {
         let stmts = stmts.into_iter().collect_vec();
-        let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec();
+        let mut input = stmts.iter().map(|it| it.syntax().clone()).collect_vec();
 
         let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update();
 
-        if let Some((mut mapping, stmt_list)) = self.mappings().zip(ast.stmt_list()) {
+        if let Some(mut mapping) = self.mappings() {
+            let stmt_list = ast.stmt_list().unwrap();
             let mut builder = SyntaxMappingBuilder::new(stmt_list.syntax().clone());
 
+            if let Some(input) = tail_expr {
+                builder.map_node(
+                    input.syntax().clone(),
+                    stmt_list.tail_expr().unwrap().syntax().clone(),
+                );
+            } else if let Some(ast_tail) = stmt_list.tail_expr() {
+                // The parser interpreted the last statement (probably a statement with a block) as an Expr
+                let last_stmt = input.pop().unwrap();
+
+                builder.map_node(last_stmt, ast_tail.syntax().clone());
+            }
+
             builder.map_children(
                 input.into_iter(),
                 stmt_list.statements().map(|it| it.syntax().clone()),
             );
 
-            if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) {
-                builder.map_node(input.syntax().clone(), output.syntax().clone());
-            }
-
             builder.finish(&mut mapping);
         }
 

From b76734f20e05df0c698b3a00f51f20968a411f59 Mon Sep 17 00:00:00 2001
From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com>
Date: Thu, 14 Nov 2024 21:15:50 -0500
Subject: [PATCH 155/197] minor: Migrate `remove_unnecessary_wrapper` to
 `SyntaxEditor`

---
 .../src/handlers/type_mismatch.rs             | 63 +++++++++++++------
 .../src/ast/syntax_factory/constructors.rs    | 20 ++++++
 2 files changed, 63 insertions(+), 20 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 8994ab50e670..bfdda5374053 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -9,9 +9,10 @@ use syntax::{
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, BlockExpr, Expr, ExprStmt, HasArgList,
+        syntax_factory::SyntaxFactory,
+        BlockExpr, Expr, ExprStmt, HasArgList,
     },
-    ted, AstNode, AstPtr, TextSize,
+    AstNode, AstPtr, TextSize,
 };
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
@@ -223,8 +224,9 @@ fn remove_unnecessary_wrapper(
 
     let inner_arg = call_expr.arg_list()?.args().next()?;
 
-    let mut builder = SourceChangeBuilder::new(expr_ptr.file_id.original_file(ctx.sema.db));
-
+    let file_id = expr_ptr.file_id.original_file(db);
+    let mut builder = SourceChangeBuilder::new(file_id);
+    let mut editor;
     match inner_arg {
         // We're returning `()`
         Expr::TupleExpr(tup) if tup.fields().next().is_none() => {
@@ -233,35 +235,33 @@ fn remove_unnecessary_wrapper(
                 .parent()
                 .and_then(Either::::cast)?;
 
+            editor = builder.make_editor(parent.syntax());
+            let make = SyntaxFactory::new();
+
             match parent {
                 Either::Left(ret_expr) => {
-                    let old = builder.make_mut(ret_expr);
-                    let new = make::expr_return(None).clone_for_update();
-
-                    ted::replace(old.syntax(), new.syntax());
+                    editor.replace(ret_expr.syntax(), make.expr_return(None).syntax());
                 }
                 Either::Right(stmt_list) => {
-                    if stmt_list.statements().count() == 0 {
-                        let block = stmt_list.syntax().parent().and_then(ast::BlockExpr::cast)?;
-                        let old = builder.make_mut(block);
-                        let new = make::expr_empty_block().clone_for_update();
-
-                        ted::replace(old.syntax(), new.syntax());
+                    let new_block = if stmt_list.statements().next().is_none() {
+                        make.expr_empty_block()
                     } else {
-                        let old = builder.make_syntax_mut(stmt_list.syntax().parent()?);
-                        let new = make::block_expr(stmt_list.statements(), None).clone_for_update();
+                        make.block_expr(stmt_list.statements(), None)
+                    };
 
-                        ted::replace(old, new.syntax());
-                    }
+                    editor.replace(stmt_list.syntax().parent()?, new_block.syntax());
                 }
             }
+
+            editor.add_mappings(make.finish_with_mappings());
         }
         _ => {
-            let call_mut = builder.make_mut(call_expr.clone());
-            ted::replace(call_mut.syntax(), inner_arg.clone_for_update().syntax());
+            editor = builder.make_editor(call_expr.syntax());
+            editor.replace(call_expr.syntax(), inner_arg.syntax());
         }
     }
 
+    builder.add_file_edits(file_id, editor);
     let name = format!("Remove unnecessary {}() wrapper", variant.name(db).as_str());
     acc.push(fix(
         "remove_unnecessary_wrapper",
@@ -848,6 +848,29 @@ fn div(x: i32, y: i32) -> i32 {
         );
     }
 
+    #[test]
+    fn unwrap_return_type_option_tail_unit() {
+        check_fix(
+            r#"
+//- minicore: option, result
+fn div(x: i32, y: i32) {
+    if y == 0 {
+        panic!();
+    }
+
+    Ok(())$0
+}
+"#,
+            r#"
+fn div(x: i32, y: i32) {
+    if y == 0 {
+        panic!();
+    }
+}
+"#,
+        );
+    }
+
     #[test]
     fn unwrap_return_type_handles_generic_functions() {
         check_fix(
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 44f67d83dc6b..f6ec18ef306b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -89,6 +89,10 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_empty_block(&self) -> ast::BlockExpr {
+        ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
+    }
+
     pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
         let ast::Expr::BinExpr(ast) =
             make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
@@ -135,6 +139,22 @@ impl SyntaxFactory {
         ast.into()
     }
 
+    pub fn expr_return(&self, expr: Option) -> ast::ReturnExpr {
+        let ast::Expr::ReturnExpr(ast) = make::expr_return(expr.clone()).clone_for_update() else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
+            if let Some(input) = expr {
+                builder.map_node(input.syntax().clone(), ast.expr().unwrap().syntax().clone());
+            }
+            builder.finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn let_stmt(
         &self,
         pattern: ast::Pat,

From 5d1b6bfc6ad95298fe3637857976945bd6ae9d9d Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Tue, 10 Dec 2024 02:28:02 +0000
Subject: [PATCH 156/197] Validate self in host predicates correctly

---
 .../src/collect/predicates_of.rs              | 11 ++++++++--
 .../dont-ice-on-const-pred-for-bounds.rs      | 22 +++++++++++++++++++
 2 files changed, 31 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs

diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ca2597e79fd1..1a6c0a934360 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -711,12 +711,19 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>(
                             `{filter:?}` implied bounds: {clause:?}"
                         );
                     }
+                    ty::ClauseKind::HostEffect(host_effect_predicate) => {
+                        assert_eq!(
+                            host_effect_predicate.self_ty(),
+                            ty,
+                            "expected `Self` predicate when computing \
+                            `{filter:?}` implied bounds: {clause:?}"
+                        );
+                    }
 
                     ty::ClauseKind::RegionOutlives(_)
                     | ty::ClauseKind::ConstArgHasType(_, _)
                     | ty::ClauseKind::WellFormed(_)
-                    | ty::ClauseKind::ConstEvaluatable(_)
-                    | ty::ClauseKind::HostEffect(..) => {
+                    | ty::ClauseKind::ConstEvaluatable(_) => {
                         bug!(
                             "unexpected non-`Self` predicate when computing \
                             `{filter:?}` implied bounds: {clause:?}"
diff --git a/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs
new file mode 100644
index 000000000000..2295c2c3857c
--- /dev/null
+++ b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs
@@ -0,0 +1,22 @@
+// Regression test for .
+
+// Ensures we don't ICE when we encounter a `HostEffectPredicate` when computing
+// the "item super predicates" for `Assoc`.
+
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+#![feature(const_trait_impl)]
+
+#[const_trait]
+trait Trait {
+    type Assoc: const Trait;
+}
+
+const fn needs_trait() {}
+
+fn test() {
+    const { needs_trait::() };
+}
+
+fn main() {}

From 88c8b1056dfbeeeb61ec14e800999596131ae8a3 Mon Sep 17 00:00:00 2001
From: Wesley Wiser 
Date: Tue, 12 Nov 2024 09:33:50 -0600
Subject: [PATCH 157/197] Add compiler-maintainers who requested to be on
 review rotation

---
 triagebot.toml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/triagebot.toml b/triagebot.toml
index c5dbd538f6c2..3f112962b4cb 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -1004,9 +1004,11 @@ compiler = [
     "@lcnr",
     "@Nadrieril",
     "@nnethercote",
+    "@Noratrieb",
     "@oli-obk",
     "@petrochenkov",
     "@pnkfelix",
+    "@SparrowLii",
     "@wesleywiser",
 ]
 libs = [

From 9a6deba8af18e3d69b6c824a989f8647955fd3a1 Mon Sep 17 00:00:00 2001
From: jyn 
Date: Tue, 10 Dec 2024 04:35:20 -0500
Subject: [PATCH 158/197] run-make: Fix `assert_stderr_not_contains_regex`

It asserted on **stdout**, not stderr.
---
 src/tools/run-make-support/src/command.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index 9e09527d6d08..e73413085fad 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -329,7 +329,7 @@ impl CompletedProcess {
     /// Checks that `stderr` does not contain the regex pattern `unexpected`.
     #[track_caller]
     pub fn assert_stderr_not_contains_regex>(&self, unexpected: S) -> &Self {
-        assert_not_contains_regex(&self.stdout_utf8(), unexpected);
+        assert_not_contains_regex(&self.stderr_utf8(), unexpected);
         self
     }
 

From a8d11ea20e282c7e63a965df7a30ab840ea049eb Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Tue, 10 Dec 2024 11:29:01 +0100
Subject: [PATCH 159/197] stabilize const_nonnull_new

---
 library/core/src/ptr/non_null.rs | 2 +-
 library/core/src/ptr/unique.rs   | 2 --
 library/core/tests/lib.rs        | 1 -
 3 files changed, 1 insertion(+), 4 deletions(-)

diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 0ad1cad6914a..6b601405e1c2 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -217,7 +217,7 @@ impl NonNull {
     /// }
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
-    #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")]
+    #[rustc_const_stable(feature = "const_nonnull_new", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn new(ptr: *mut T) -> Option {
         if !ptr.is_null() {
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index ebdc918a729c..4810ebe01f9b 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -92,8 +92,6 @@ impl Unique {
 
     /// Creates a new `Unique` if `ptr` is non-null.
     #[inline]
-    // rustc_const_unstable attribute can be removed when `const_nonnull_new` is stable
-    #[rustc_const_unstable(feature = "ptr_internals", issue = "none")]
     pub const fn new(ptr: *mut T) -> Option {
         if let Some(pointer) = NonNull::new(ptr) {
             Some(Unique { pointer, _marker: PhantomData })
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index a4a794691fe3..89b65eefd027 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -15,7 +15,6 @@
 #![feature(clone_to_uninit)]
 #![feature(const_black_box)]
 #![feature(const_eval_select)]
-#![feature(const_nonnull_new)]
 #![feature(const_swap)]
 #![feature(const_trait_impl)]
 #![feature(core_intrinsics)]

From f94953d7320b2a4d2c7341136e7e63d4c118db0f Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 12:33:13 +0200
Subject: [PATCH 160/197] Address the feedback from Veykril

* Exclude documentation field from hashing
* Do less cloning during initial completion list generation
---
 .../rust-analyzer/crates/rust-analyzer/src/lib.rs  |  6 +++---
 .../crates/rust-analyzer/src/lsp/to_proto.rs       | 14 +++++++-------
 2 files changed, 10 insertions(+), 10 deletions(-)

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 8c8ac8de8144..15d60c873fb5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -120,14 +120,14 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
     }
     // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
     // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
+    //
+    // Documentation hashing is skipped too, as it's a large blob to process,
+    // while not really making completion properties more unique as they are already.
     hasher.update(item.kind.tag());
     hasher.update(&item.lookup);
     if let Some(detail) = &item.detail {
         hasher.update(detail);
     }
-    if let Some(documentation) = &item.documentation {
-        hasher.update(documentation.as_str());
-    }
     hash_completion_relevance(&mut hasher, &item.relevance);
     if let Some((mutability, text_size)) = &item.ref_match {
         hasher.update(mutability.as_keyword_for_ref());
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 f70968d69428..a64e1a862104 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
@@ -275,7 +275,6 @@ fn completion_item(
     completion_trigger_character: Option,
     item: CompletionItem,
 ) {
-    let original_completion_item = item.clone();
     let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
     let ref_match = item.ref_match();
 
@@ -297,7 +296,7 @@ fn completion_item(
         // non-trivial mapping here.
         let mut text_edit = None;
         let source_range = item.source_range;
-        for indel in item.text_edit {
+        for indel in &item.text_edit {
             if indel.delete.contains_range(source_range) {
                 // Extract this indel as the main edit
                 text_edit = Some(if indel.delete == source_range {
@@ -349,7 +348,7 @@ fn completion_item(
         something_to_resolve |= item.documentation.is_some();
         None
     } else {
-        item.documentation.map(documentation)
+        item.documentation.clone().map(documentation)
     };
 
     let mut lsp_item = lsp_types::CompletionItem {
@@ -373,10 +372,10 @@ fn completion_item(
         } else {
             lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
                 detail: item.label_detail.as_ref().map(ToString::to_string),
-                description: item.detail,
+                description: item.detail.clone(),
             });
         }
-    } else if let Some(label_detail) = item.label_detail {
+    } else if let Some(label_detail) = &item.label_detail {
         lsp_item.label.push_str(label_detail.as_str());
     }
 
@@ -385,6 +384,7 @@ fn completion_item(
     let imports =
         if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
             item.import_to_add
+                .clone()
                 .into_iter()
                 .map(|(import_path, import_name)| lsp_ext::CompletionImport {
                     full_import_path: import_path,
@@ -402,7 +402,7 @@ fn completion_item(
                 version,
                 trigger_character: completion_trigger_character,
                 for_ref: true,
-                hash: completion_item_hash(&original_completion_item, true),
+                hash: completion_item_hash(&item, true),
             };
             Some(to_value(ref_resolve_data).unwrap())
         } else {
@@ -414,7 +414,7 @@ fn completion_item(
             version,
             trigger_character: completion_trigger_character,
             for_ref: false,
-            hash: completion_item_hash(&original_completion_item, false),
+            hash: completion_item_hash(&item, false),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {

From 0680155a171d47772302fc4da4cbbfa466378d81 Mon Sep 17 00:00:00 2001
From: Augie Fackler 
Date: Tue, 10 Dec 2024 04:54:12 -0500
Subject: [PATCH 161/197] rustc_target: ppc64 target string fixes for LLVM 20

LLVM continues to clean these up, and we continue to make this
consistent. This is similar to 9caced7badc337ced7ad89eb614621c39bd996e9,
e9853961452b56997cc127b51308879b9cd09482, and
a10e744fafa7eb3afef9a938097509bf4b225f84.

`@rustbot` label: +llvm-main
---
 compiler/rustc_codegen_llvm/src/context.rs                   | 5 +++++
 compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs  | 2 +-
 .../src/spec/targets/powerpc64_unknown_freebsd.rs            | 2 +-
 .../src/spec/targets/powerpc64_unknown_linux_gnu.rs          | 2 +-
 .../src/spec/targets/powerpc64_unknown_linux_musl.rs         | 2 +-
 .../src/spec/targets/powerpc64_unknown_openbsd.rs            | 2 +-
 .../rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs   | 2 +-
 .../src/spec/targets/powerpc64le_unknown_freebsd.rs          | 2 +-
 .../src/spec/targets/powerpc64le_unknown_linux_gnu.rs        | 2 +-
 .../src/spec/targets/powerpc64le_unknown_linux_musl.rs       | 2 +-
 10 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 8218126ea29c..e0506c0c5fd1 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -159,6 +159,11 @@ pub(crate) unsafe fn create_module<'ll>(
             // See https://github.com/llvm/llvm-project/pull/112084
             target_data_layout = target_data_layout.replace("-i128:128", "");
         }
+        if sess.target.arch.starts_with("powerpc64") {
+            // LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit.
+            // See https://github.com/llvm/llvm-project/pull/118004
+            target_data_layout = target_data_layout.replace("-i128:128", "");
+        }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
index 0f361054f7a0..edabbbf5f005 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
@@ -19,7 +19,7 @@ pub(crate) fn target() -> Target {
             std: None, // ?
         },
         pointer_width: 64,
-        data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index 680b024cb6e6..68a3718035cd 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
+        data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index 5acd9205a8c7..351ffa65eba8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index 62c30aebc518..a964f417799f 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index c723847cada7..31fbb1415240 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-Fn32-i64:64-n32:64".into(),
+        data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 1d3d9f1b77df..c37aa8d502ad 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -17,7 +17,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { endian: Endian::Big, ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 0c1218bd0593..13885c7326a7 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "e-m:e-Fn32-i64:64-n32:64".into(),
+        data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index 23913687a1fd..06ae54063cef 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index 50946ae4ce66..04fe5f9af335 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 64,
-        data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
+        data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
         arch: "powerpc64".into(),
         options: TargetOptions { mcount: "_mcount".into(), ..base },
     }

From 1ce15606f2157b955e87608a20492160f4a74ae1 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov 
Date: Tue, 10 Dec 2024 13:01:23 +0200
Subject: [PATCH 162/197] Address the feedback from pascalkuthe

* Use Base64 to minify the hash representation in the JSON data
* Do hash checks only for items with similar labels
---
 src/tools/rust-analyzer/Cargo.lock                     |  7 +++++++
 .../rust-analyzer/crates/rust-analyzer/Cargo.toml      |  1 +
 .../crates/rust-analyzer/src/handlers/request.rs       | 10 ++++++++--
 .../rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs  |  2 +-
 .../crates/rust-analyzer/src/lsp/to_proto.rs           |  5 +++--
 src/tools/rust-analyzer/docs/dev/lsp-extensions.md     |  2 +-
 6 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index b6f2c6faf867..8b156a540134 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -84,6 +84,12 @@ dependencies = [
  "vfs",
 ]
 
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -1649,6 +1655,7 @@ version = "0.0.0"
 dependencies = [
  "always-assert",
  "anyhow",
+ "base64",
  "cargo_metadata",
  "cfg",
  "crossbeam-channel",
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 58d871270d9f..7c8610280b3a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -21,6 +21,7 @@ path = "src/bin/main.rs"
 
 [dependencies]
 anyhow.workspace = true
+base64 = "0.22"
 crossbeam-channel.workspace = true
 dirs = "5.0.1"
 dissimilar.workspace = true
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 3f2ef7616be5..e51b14f61181 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
@@ -10,6 +10,7 @@ use std::{
 
 use anyhow::Context;
 
+use base64::{prelude::BASE64_STANDARD, Engine};
 use ide::{
     AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
     FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
@@ -1136,10 +1137,15 @@ pub(crate) fn handle_completion_resolve(
     else {
         return Ok(original_completion);
     };
+    let Ok(resolve_data_hash) = BASE64_STANDARD.decode(resolve_data.hash) else {
+        return Ok(original_completion);
+    };
 
     let Some(corresponding_completion) = completions.into_iter().find(|completion_item| {
-        let hash = completion_item_hash(completion_item, resolve_data.for_ref);
-        hash == resolve_data.hash
+        // Avoid computing hashes for items that obviously do not match
+        // r-a might append a detail-based suffix to the label, so we cannot check for equality
+        original_completion.label.starts_with(completion_item.label.as_str())
+            && resolve_data_hash == completion_item_hash(completion_item, resolve_data.for_ref)
     }) else {
         return Ok(original_completion);
     };
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 afb9c909c68f..df06270a8b1b 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
@@ -827,7 +827,7 @@ pub struct CompletionResolveData {
     pub version: Option,
     pub trigger_character: Option,
     pub for_ref: bool,
-    pub hash: [u8; 20],
+    pub hash: String,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
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 a64e1a862104..612cb547b413 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
@@ -5,6 +5,7 @@ use std::{
     sync::atomic::{AtomicU32, Ordering},
 };
 
+use base64::{prelude::BASE64_STANDARD, Engine};
 use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
     CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
@@ -402,7 +403,7 @@ fn completion_item(
                 version,
                 trigger_character: completion_trigger_character,
                 for_ref: true,
-                hash: completion_item_hash(&item, true),
+                hash: BASE64_STANDARD.encode(completion_item_hash(&item, true)),
             };
             Some(to_value(ref_resolve_data).unwrap())
         } else {
@@ -414,7 +415,7 @@ fn completion_item(
             version,
             trigger_character: completion_trigger_character,
             for_ref: false,
-            hash: completion_item_hash(&item, false),
+            hash: BASE64_STANDARD.encode(completion_item_hash(&item, false)),
         };
         (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
     } else {
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 80b35d453a32..2aad2cfa3613 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 @@
  $DIR/overcaptures-2024.rs:45:28
+   |
+LL | pub fn parens(x: &i32) -> &impl Clone { x }
+   |                            ^^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: for more information, see 
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:45:18
+   |
+LL | pub fn parens(x: &i32) -> &impl Clone { x }
+   |                  ^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL | pub fn parens(x: &i32) -> &(impl Clone + use<>) { x }
+   |                            +           ++++++++
+
+error: aborting due to 8 previous errors
 

From ec68498317f90221eeca4c5a14593914b42c2d0e Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 11 Dec 2024 00:59:39 +0000
Subject: [PATCH 182/197] Rename projection_def_id to item_def_id

---
 .../src/hir_ty_lowering/dyn_compatibility.rs                  | 4 ++--
 compiler/rustc_hir_typeck/src/closure.rs                      | 2 +-
 compiler/rustc_middle/src/ty/print/pretty.rs                  | 2 +-
 .../rustc_next_trait_solver/src/solve/normalizes_to/mod.rs    | 2 +-
 compiler/rustc_trait_selection/src/traits/project.rs          | 4 ++--
 compiler/rustc_trait_selection/src/traits/select/mod.rs       | 2 +-
 compiler/rustc_type_ir/src/predicate.rs                       | 2 +-
 7 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 321a8aba7f72..d3c86989440e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -203,7 +203,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         // corresponding `Projection` clause
         for def_ids in associated_types.values_mut() {
             for (projection_bound, span) in &projection_bounds {
-                let def_id = projection_bound.projection_def_id();
+                let def_id = projection_bound.item_def_id();
                 def_ids.swap_remove(&def_id);
                 if tcx.generics_require_sized_self(def_id) {
                     tcx.emit_node_span_lint(
@@ -413,7 +413,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             late_bound_in_projection_term,
             late_bound_in_term,
             |br_name| {
-                let item_name = tcx.item_name(pred.projection_def_id());
+                let item_name = tcx.item_name(pred.item_def_id());
                 struct_span_code_err!(
                     self.dcx(),
                     span,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 9037caf0066f..b8652d82d91b 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -454,7 +454,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         closure_kind: hir::ClosureKind,
         projection: ty::PolyProjectionPredicate<'tcx>,
     ) -> Option> {
-        let def_id = projection.projection_def_id();
+        let def_id = projection.item_def_id();
 
         // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
         // for closures and async closures, respectively.
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index cd4123f0a3f5..40e0fb0087f5 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1020,7 +1020,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
                     self.insert_trait_and_projection(
                         trait_ref,
-                        Some((proj.projection_def_id(), proj.term())),
+                        Some((proj.item_def_id(), proj.term())),
                         &mut traits,
                         &mut fn_traits,
                     );
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index f5b1b23b8e97..63dbee2640bf 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -144,7 +144,7 @@ where
         then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult,
     ) -> Result, NoSolution> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
-            if projection_pred.projection_def_id() == goal.predicate.def_id() {
+            if projection_pred.item_def_id() == goal.predicate.def_id() {
                 let cx = ecx.cx();
                 if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
                     goal.predicate.alias.args,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 49c34550f8e0..541c0c915ffd 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -744,7 +744,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
             let Some(clause) = clause.as_projection_clause() else {
                 return ControlFlow::Continue(());
             };
-            if clause.projection_def_id() != obligation.predicate.def_id {
+            if clause.item_def_id() != obligation.predicate.def_id {
                 return ControlFlow::Continue(());
             }
 
@@ -847,7 +847,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
         let bound_predicate = predicate.kind();
         if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() {
             let data = bound_predicate.rebind(data);
-            if data.projection_def_id() != obligation.predicate.def_id {
+            if data.item_def_id() != obligation.predicate.def_id {
                 continue;
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index d362866cbc38..25fe43e3a0e6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1737,7 +1737,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         env_predicate: PolyProjectionPredicate<'tcx>,
         potentially_unnormalized_candidates: bool,
     ) -> ProjectionMatchesProjection {
-        debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id());
+        debug_assert_eq!(obligation.predicate.def_id, env_predicate.item_def_id());
 
         let mut nested_obligations = PredicateObligations::new();
         let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 4213ef4803be..9a80f97e274d 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -692,7 +692,7 @@ impl ty::Binder> {
     ///
     /// Note that this is not the `DefId` of the `TraitRef` containing this
     /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
-    pub fn projection_def_id(&self) -> I::DefId {
+    pub fn item_def_id(&self) -> I::DefId {
         // Ok to skip binder since trait `DefId` does not care about regions.
         self.skip_binder().projection_term.def_id
     }

From e37d7c0f1517be79e81264719867495fd7aa767a Mon Sep 17 00:00:00 2001
From: Tobias Bucher 
Date: Mon, 9 Dec 2024 14:48:13 +0100
Subject: [PATCH 183/197] Add a note saying that
 `{u8,i8}::from_{be,le,ne}_bytes` is meaningless

---
 library/core/src/num/mod.rs | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index e36f20fd576f..357a85ae843c 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -77,6 +77,31 @@ pub use saturating::Saturating;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use wrapping::Wrapping;
 
+macro_rules! u8_xe_bytes_doc {
+    () => {
+        "
+
+**Note**: This function is meaningless on `u8`. Byte order does not exist as a
+concept for byte-sized integers. This function is only provided in symmetry
+with larger integer types.
+
+"
+    };
+}
+
+macro_rules! i8_xe_bytes_doc {
+    () => {
+        "
+
+**Note**: This function is meaningless on `i8`. Byte order does not exist as a
+concept for byte-sized integers. This function is only provided in symmetry
+with larger integer types. You can cast from and to `u8` using `as i8` and `as
+u8`.
+
+"
+    };
+}
+
 macro_rules! usize_isize_to_xe_bytes_doc {
     () => {
         "
@@ -348,8 +373,8 @@ impl i8 {
         reversed = "0x48",
         le_bytes = "[0x12]",
         be_bytes = "[0x12]",
-        to_xe_bytes_doc = "",
-        from_xe_bytes_doc = "",
+        to_xe_bytes_doc = i8_xe_bytes_doc!(),
+        from_xe_bytes_doc = i8_xe_bytes_doc!(),
         bound_condition = "",
     }
     midpoint_impl! { i8, i16, signed }
@@ -547,8 +572,8 @@ impl u8 {
         reversed = "0x48",
         le_bytes = "[0x12]",
         be_bytes = "[0x12]",
-        to_xe_bytes_doc = "",
-        from_xe_bytes_doc = "",
+        to_xe_bytes_doc = u8_xe_bytes_doc!(),
+        from_xe_bytes_doc = u8_xe_bytes_doc!(),
         bound_condition = "",
     }
     widening_impl! { u8, u16, 8, unsigned }

From 45ad5a573584170c86b41c98002102033c378f88 Mon Sep 17 00:00:00 2001
From: "Celina G. Val" 
Date: Tue, 10 Dec 2024 19:36:52 -0800
Subject: [PATCH 184/197] Add vacation entry in triagebot.toml

---
 triagebot.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/triagebot.toml b/triagebot.toml
index 665108cccd38..f7ee04ac3394 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -995,6 +995,7 @@ warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
     "jyn514",
+    "celinval",
 ]
 
 [assign.adhoc_groups]

From 7c4ac71ad1bef9b1e4cb5a3fd10d0b2ef7b418c4 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Wed, 11 Dec 2024 14:28:55 +1100
Subject: [PATCH 185/197] coverage: Extract function metadata handling to a
 `covfun` submodule

---
 .../src/coverageinfo/mapgen.rs                | 174 +--------------
 .../src/coverageinfo/mapgen/covfun.rs         | 198 ++++++++++++++++++
 2 files changed, 206 insertions(+), 166 deletions(-)
 create mode 100644 compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index a6c3caf9e2b5..5da7848b39c0 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -1,4 +1,3 @@
-use std::ffi::CString;
 use std::iter;
 
 use itertools::Itertools as _;
@@ -9,21 +8,21 @@ use rustc_codegen_ssa::traits::{
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::IndexVec;
-use rustc_middle::mir::coverage::MappingKind;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_session::RemapFileNameExt;
 use rustc_session::config::RemapPathScopeComponents;
 use rustc_span::def_id::DefIdSet;
 use rustc_span::{Span, Symbol};
-use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
 use crate::common::CodegenCx;
+use crate::coverageinfo::llvm_cov;
 use crate::coverageinfo::map_data::FunctionCoverage;
-use crate::coverageinfo::{ffi, llvm_cov};
 use crate::llvm;
 
+mod covfun;
+
 /// Generates and exports the coverage map, which is embedded in special
 /// linker sections in the final binary.
 ///
@@ -88,38 +87,13 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
 
     // Encode coverage mappings and generate function records
     for (instance, function_coverage) in function_coverage_map {
-        debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
-
-        let mangled_function_name = tcx.symbol_name(instance).name;
-        let source_hash = function_coverage.source_hash();
-        let is_used = function_coverage.is_used();
-
-        let coverage_mapping_buffer =
-            encode_mappings_for_function(tcx, &global_file_table, &function_coverage);
-
-        if coverage_mapping_buffer.is_empty() {
-            if function_coverage.is_used() {
-                bug!(
-                    "A used function should have had coverage mapping data but did not: {}",
-                    mangled_function_name
-                );
-            } else {
-                debug!("unused function had no coverage mapping data: {}", mangled_function_name);
-                continue;
-            }
-        }
-
-        if !is_used {
-            unused_function_names.push(mangled_function_name);
-        }
-
-        generate_covfun_record(
+        covfun::prepare_and_generate_covfun_record(
             cx,
-            mangled_function_name,
-            source_hash,
+            &global_file_table,
             filenames_ref,
-            coverage_mapping_buffer,
-            is_used,
+            &mut unused_function_names,
+            instance,
+            &function_coverage,
         );
     }
 
@@ -236,83 +210,6 @@ fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol {
     Symbol::intern(&name)
 }
 
-/// Using the expressions and counter regions collected for a single function,
-/// generate the variable-sized payload of its corresponding `__llvm_covfun`
-/// entry. The payload is returned as a vector of bytes.
-///
-/// Newly-encountered filenames will be added to the global file table.
-fn encode_mappings_for_function(
-    tcx: TyCtxt<'_>,
-    global_file_table: &GlobalFileTable,
-    function_coverage: &FunctionCoverage<'_>,
-) -> Vec {
-    let counter_regions = function_coverage.counter_regions();
-    if counter_regions.is_empty() {
-        return Vec::new();
-    }
-
-    let expressions = function_coverage.counter_expressions().collect::>();
-
-    let mut virtual_file_mapping = VirtualFileMapping::default();
-    let mut code_regions = vec![];
-    let mut branch_regions = vec![];
-    let mut mcdc_branch_regions = vec![];
-    let mut mcdc_decision_regions = vec![];
-
-    // Currently a function's mappings must all be in the same file as its body span.
-    let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
-
-    // Look up the global file ID for that filename.
-    let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
-
-    // Associate that global file ID with a local file ID for this function.
-    let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
-    debug!("  file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
-
-    // For each counter/region pair in this function+file, convert it to a
-    // form suitable for FFI.
-    for (mapping_kind, region) in counter_regions {
-        debug!("Adding counter {mapping_kind:?} to map for {region:?}");
-        let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
-        match mapping_kind {
-            MappingKind::Code(term) => {
-                code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
-            }
-            MappingKind::Branch { true_term, false_term } => {
-                branch_regions.push(ffi::BranchRegion {
-                    span,
-                    true_counter: ffi::Counter::from_term(true_term),
-                    false_counter: ffi::Counter::from_term(false_term),
-                });
-            }
-            MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
-                mcdc_branch_regions.push(ffi::MCDCBranchRegion {
-                    span,
-                    true_counter: ffi::Counter::from_term(true_term),
-                    false_counter: ffi::Counter::from_term(false_term),
-                    mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
-                });
-            }
-            MappingKind::MCDCDecision(mcdc_decision_params) => {
-                mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
-                    span,
-                    mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
-                });
-            }
-        }
-    }
-
-    // Encode the function's coverage mappings into a buffer.
-    llvm_cov::write_function_mappings_to_buffer(
-        &virtual_file_mapping.into_vec(),
-        &expressions,
-        &code_regions,
-        &branch_regions,
-        &mcdc_branch_regions,
-        &mcdc_decision_regions,
-    )
-}
-
 /// Generates the contents of the covmap record for this CGU, which mostly
 /// consists of a header and a list of filenames. The record is then stored
 /// as a global variable in the `__llvm_covmap` section.
@@ -350,61 +247,6 @@ fn generate_covmap_record<'ll>(
     cx.add_used_global(llglobal);
 }
 
-/// Generates the contents of the covfun record for this function, which
-/// contains the function's coverage mapping data. The record is then stored
-/// as a global variable in the `__llvm_covfun` section.
-fn generate_covfun_record(
-    cx: &CodegenCx<'_, '_>,
-    mangled_function_name: &str,
-    source_hash: u64,
-    filenames_ref: u64,
-    coverage_mapping_buffer: Vec,
-    is_used: bool,
-) {
-    // Concatenate the encoded coverage mappings
-    let coverage_mapping_size = coverage_mapping_buffer.len();
-    let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
-
-    let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes());
-    let func_name_hash_val = cx.const_u64(func_name_hash);
-    let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
-    let source_hash_val = cx.const_u64(source_hash);
-    let filenames_ref_val = cx.const_u64(filenames_ref);
-    let func_record_val = cx.const_struct(
-        &[
-            func_name_hash_val,
-            coverage_mapping_size_val,
-            source_hash_val,
-            filenames_ref_val,
-            coverage_mapping_val,
-        ],
-        /*packed=*/ true,
-    );
-
-    // Choose a variable name to hold this function's covfun data.
-    // Functions that are used have a suffix ("u") to distinguish them from
-    // unused copies of the same function (from different CGUs), so that if a
-    // linker sees both it won't discard the used copy's data.
-    let func_record_var_name =
-        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
-            .unwrap();
-    debug!("function record var name: {:?}", func_record_var_name);
-
-    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
-    llvm::set_initializer(llglobal, func_record_val);
-    llvm::set_global_constant(llglobal, true);
-    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
-    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
-    llvm::set_section(llglobal, cx.covfun_section_name());
-    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
-    // 
-    llvm::set_alignment(llglobal, Align::EIGHT);
-    if cx.target_spec().supports_comdat() {
-        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
-    }
-    cx.add_used_global(llglobal);
-}
-
 /// Each CGU will normally only emit coverage metadata for the functions that it actually generates.
 /// But since we don't want unused functions to disappear from coverage reports, we also scan for
 /// functions that were instrumented but are not participating in codegen.
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
new file mode 100644
index 000000000000..aaa6bbcdfc91
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -0,0 +1,198 @@
+//! For each function that was instrumented for coverage, we need to embed its
+//! corresponding coverage mapping metadata inside the `__llvm_covfun`[^win]
+//! linker section of the final binary.
+//!
+//! [^win]: On Windows the section name is `.lcovfun`.
+
+use std::ffi::CString;
+
+use rustc_abi::Align;
+use rustc_codegen_ssa::traits::{
+    BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods,
+};
+use rustc_middle::bug;
+use rustc_middle::mir::coverage::MappingKind;
+use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_target::spec::HasTargetSpec;
+use tracing::debug;
+
+use crate::common::CodegenCx;
+use crate::coverageinfo::map_data::FunctionCoverage;
+use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file_name};
+use crate::coverageinfo::{ffi, llvm_cov};
+use crate::llvm;
+
+pub(crate) fn prepare_and_generate_covfun_record<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    global_file_table: &GlobalFileTable,
+    filenames_ref: u64,
+    unused_function_names: &mut Vec<&'tcx str>,
+    instance: Instance<'tcx>,
+    function_coverage: &FunctionCoverage<'tcx>,
+) {
+    let tcx = cx.tcx;
+
+    let mangled_function_name = tcx.symbol_name(instance).name;
+    let source_hash = function_coverage.source_hash();
+    let is_used = function_coverage.is_used();
+
+    let coverage_mapping_buffer =
+        encode_mappings_for_function(tcx, global_file_table, function_coverage);
+
+    if coverage_mapping_buffer.is_empty() {
+        if function_coverage.is_used() {
+            bug!(
+                "A used function should have had coverage mapping data but did not: {}",
+                mangled_function_name
+            );
+        } else {
+            debug!("unused function had no coverage mapping data: {}", mangled_function_name);
+            return;
+        }
+    }
+
+    if !is_used {
+        unused_function_names.push(mangled_function_name);
+    }
+
+    generate_covfun_record(
+        cx,
+        mangled_function_name,
+        source_hash,
+        filenames_ref,
+        coverage_mapping_buffer,
+        is_used,
+    );
+}
+
+/// Using the expressions and counter regions collected for a single function,
+/// generate the variable-sized payload of its corresponding `__llvm_covfun`
+/// entry. The payload is returned as a vector of bytes.
+///
+/// Newly-encountered filenames will be added to the global file table.
+fn encode_mappings_for_function(
+    tcx: TyCtxt<'_>,
+    global_file_table: &GlobalFileTable,
+    function_coverage: &FunctionCoverage<'_>,
+) -> Vec {
+    let counter_regions = function_coverage.counter_regions();
+    if counter_regions.is_empty() {
+        return Vec::new();
+    }
+
+    let expressions = function_coverage.counter_expressions().collect::>();
+
+    let mut virtual_file_mapping = VirtualFileMapping::default();
+    let mut code_regions = vec![];
+    let mut branch_regions = vec![];
+    let mut mcdc_branch_regions = vec![];
+    let mut mcdc_decision_regions = vec![];
+
+    // Currently a function's mappings must all be in the same file as its body span.
+    let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
+
+    // Look up the global file ID for that filename.
+    let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
+
+    // Associate that global file ID with a local file ID for this function.
+    let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
+    debug!("  file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
+
+    // For each counter/region pair in this function+file, convert it to a
+    // form suitable for FFI.
+    for (mapping_kind, region) in counter_regions {
+        debug!("Adding counter {mapping_kind:?} to map for {region:?}");
+        let span = ffi::CoverageSpan::from_source_region(local_file_id, region);
+        match mapping_kind {
+            MappingKind::Code(term) => {
+                code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
+            }
+            MappingKind::Branch { true_term, false_term } => {
+                branch_regions.push(ffi::BranchRegion {
+                    span,
+                    true_counter: ffi::Counter::from_term(true_term),
+                    false_counter: ffi::Counter::from_term(false_term),
+                });
+            }
+            MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
+                mcdc_branch_regions.push(ffi::MCDCBranchRegion {
+                    span,
+                    true_counter: ffi::Counter::from_term(true_term),
+                    false_counter: ffi::Counter::from_term(false_term),
+                    mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
+                });
+            }
+            MappingKind::MCDCDecision(mcdc_decision_params) => {
+                mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
+                    span,
+                    mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params),
+                });
+            }
+        }
+    }
+
+    // Encode the function's coverage mappings into a buffer.
+    llvm_cov::write_function_mappings_to_buffer(
+        &virtual_file_mapping.into_vec(),
+        &expressions,
+        &code_regions,
+        &branch_regions,
+        &mcdc_branch_regions,
+        &mcdc_decision_regions,
+    )
+}
+
+/// Generates the contents of the covfun record for this function, which
+/// contains the function's coverage mapping data. The record is then stored
+/// as a global variable in the `__llvm_covfun` section.
+fn generate_covfun_record(
+    cx: &CodegenCx<'_, '_>,
+    mangled_function_name: &str,
+    source_hash: u64,
+    filenames_ref: u64,
+    coverage_mapping_buffer: Vec,
+    is_used: bool,
+) {
+    // Concatenate the encoded coverage mappings
+    let coverage_mapping_size = coverage_mapping_buffer.len();
+    let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);
+
+    let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes());
+    let func_name_hash_val = cx.const_u64(func_name_hash);
+    let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32);
+    let source_hash_val = cx.const_u64(source_hash);
+    let filenames_ref_val = cx.const_u64(filenames_ref);
+    let func_record_val = cx.const_struct(
+        &[
+            func_name_hash_val,
+            coverage_mapping_size_val,
+            source_hash_val,
+            filenames_ref_val,
+            coverage_mapping_val,
+        ],
+        /*packed=*/ true,
+    );
+
+    // Choose a variable name to hold this function's covfun data.
+    // Functions that are used have a suffix ("u") to distinguish them from
+    // unused copies of the same function (from different CGUs), so that if a
+    // linker sees both it won't discard the used copy's data.
+    let func_record_var_name =
+        CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
+            .unwrap();
+    debug!("function record var name: {:?}", func_record_var_name);
+
+    let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name);
+    llvm::set_initializer(llglobal, func_record_val);
+    llvm::set_global_constant(llglobal, true);
+    llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage);
+    llvm::set_visibility(llglobal, llvm::Visibility::Hidden);
+    llvm::set_section(llglobal, cx.covfun_section_name());
+    // LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
+    // 
+    llvm::set_alignment(llglobal, Align::EIGHT);
+    if cx.target_spec().supports_comdat() {
+        llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
+    }
+    cx.add_used_global(llglobal);
+}

From 6a8c016266a6b7514ff8284dc6d8b056e34b9399 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Wed, 11 Dec 2024 15:03:31 +1100
Subject: [PATCH 186/197] coverage: Reify `CovfunRecord` as an intermediate
 step

---
 .../src/coverageinfo/mapgen.rs                | 22 +++----
 .../src/coverageinfo/mapgen/covfun.rs         | 59 +++++++++++--------
 2 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 5da7848b39c0..39fb0aeed071 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -19,6 +19,7 @@ use tracing::debug;
 use crate::common::CodegenCx;
 use crate::coverageinfo::llvm_cov;
 use crate::coverageinfo::map_data::FunctionCoverage;
+use crate::coverageinfo::mapgen::covfun::prepare_covfun_record;
 use crate::llvm;
 
 mod covfun;
@@ -85,16 +86,17 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
 
     let mut unused_function_names = Vec::new();
 
-    // Encode coverage mappings and generate function records
-    for (instance, function_coverage) in function_coverage_map {
-        covfun::prepare_and_generate_covfun_record(
-            cx,
-            &global_file_table,
-            filenames_ref,
-            &mut unused_function_names,
-            instance,
-            &function_coverage,
-        );
+    let covfun_records = function_coverage_map
+        .into_iter()
+        .filter_map(|(instance, function_coverage)| {
+            prepare_covfun_record(tcx, &global_file_table, instance, &function_coverage)
+        })
+        .collect::>();
+
+    for covfun in &covfun_records {
+        unused_function_names.extend(covfun.mangled_function_name_if_unused());
+
+        covfun::generate_covfun_record(cx, filenames_ref, covfun)
     }
 
     // For unused functions, we need to take their mangled names and store them
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index aaa6bbcdfc91..a68b026a4c06 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -22,16 +22,30 @@ use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file
 use crate::coverageinfo::{ffi, llvm_cov};
 use crate::llvm;
 
-pub(crate) fn prepare_and_generate_covfun_record<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
+/// Intermediate coverage metadata for a single function, used to help build
+/// the final record that will be embedded in the `__llvm_covfun` section.
+#[derive(Debug)]
+pub(crate) struct CovfunRecord<'tcx> {
+    mangled_function_name: &'tcx str,
+    source_hash: u64,
+    is_used: bool,
+    coverage_mapping_buffer: Vec,
+}
+
+impl<'tcx> CovfunRecord<'tcx> {
+    /// FIXME(Zalathar): Make this the responsibility of the code that determines
+    /// which functions are unused.
+    pub(crate) fn mangled_function_name_if_unused(&self) -> Option<&'tcx str> {
+        (!self.is_used).then_some(self.mangled_function_name)
+    }
+}
+
+pub(crate) fn prepare_covfun_record<'tcx>(
+    tcx: TyCtxt<'tcx>,
     global_file_table: &GlobalFileTable,
-    filenames_ref: u64,
-    unused_function_names: &mut Vec<&'tcx str>,
     instance: Instance<'tcx>,
     function_coverage: &FunctionCoverage<'tcx>,
-) {
-    let tcx = cx.tcx;
-
+) -> Option> {
     let mangled_function_name = tcx.symbol_name(instance).name;
     let source_hash = function_coverage.source_hash();
     let is_used = function_coverage.is_used();
@@ -47,22 +61,11 @@ pub(crate) fn prepare_and_generate_covfun_record<'ll, 'tcx>(
             );
         } else {
             debug!("unused function had no coverage mapping data: {}", mangled_function_name);
-            return;
+            return None;
         }
     }
 
-    if !is_used {
-        unused_function_names.push(mangled_function_name);
-    }
-
-    generate_covfun_record(
-        cx,
-        mangled_function_name,
-        source_hash,
-        filenames_ref,
-        coverage_mapping_buffer,
-        is_used,
-    );
+    Some(CovfunRecord { mangled_function_name, source_hash, is_used, coverage_mapping_buffer })
 }
 
 /// Using the expressions and counter regions collected for a single function,
@@ -145,14 +148,18 @@ fn encode_mappings_for_function(
 /// Generates the contents of the covfun record for this function, which
 /// contains the function's coverage mapping data. The record is then stored
 /// as a global variable in the `__llvm_covfun` section.
-fn generate_covfun_record(
-    cx: &CodegenCx<'_, '_>,
-    mangled_function_name: &str,
-    source_hash: u64,
+pub(crate) fn generate_covfun_record<'tcx>(
+    cx: &CodegenCx<'_, 'tcx>,
     filenames_ref: u64,
-    coverage_mapping_buffer: Vec,
-    is_used: bool,
+    covfun: &CovfunRecord<'tcx>,
 ) {
+    let &CovfunRecord {
+        mangled_function_name,
+        source_hash,
+        is_used,
+        ref coverage_mapping_buffer, // Previously-encoded coverage mappings
+    } = covfun;
+
     // Concatenate the encoded coverage mappings
     let coverage_mapping_size = coverage_mapping_buffer.len();
     let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);

From 1649eb6dd74507bbd9513464609fcd5a9bcc655b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= 
Date: Wed, 11 Dec 2024 11:48:46 +0200
Subject: [PATCH 187/197] Preparing for merge from rust-lang/rust

---
 src/tools/rust-analyzer/rust-version | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 945939a2ff47..7d60fa6cb76a 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-9b4d7c6a40b328d212095c28670c629facf1557d
+5a6036a1802262f8cf02192b02026688d396f1d7

From 884f57f9fc157c7d07d22234c7614870929c2d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= 
Date: Wed, 11 Dec 2024 11:50:19 +0200
Subject: [PATCH 188/197] Bump rustc crates

---
 src/tools/rust-analyzer/Cargo.lock | 25 ++++++++++++-------------
 src/tools/rust-analyzer/Cargo.toml | 10 +++++-----
 2 files changed, 17 insertions(+), 18 deletions(-)

diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8b156a540134..8c1d82de1da4 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1502,9 +1502,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613760a3071b25a67a8d7bc97b37c7fd4722562e9479137b83ae9cf8f8c1601a"
+checksum = "af462c3a2d524b84a51b6848b439787f01b35c6c1086d3e3086a5f5eea92ed9a"
 dependencies = [
  "bitflags 2.6.0",
  "ra-ap-rustc_index",
@@ -1513,20 +1513,19 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b2bc6b4ecede8ff28295041e22c2e66853f8e0125990c05135bad3c30bad12c"
+checksum = "be6bb8cb0ab78d94a222f1ffd3e87254cdfb57413382b8d6ebe26a85482f99d1"
 dependencies = [
- "arrayvec",
  "ra-ap-rustc_index_macros",
  "smallvec",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2374a39fb2d92d0509178c2b442eadca3cc10e403ef9729a040c1855b08ff261"
+checksum = "c24b1641455b46e87435b7321219672077066e678963d239a4a2904732979b16"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1535,9 +1534,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a2cf8e48b69af3ecc29ed3449892e8a999111d2f75212a78aa242e117cf1711"
+checksum = "94daa86974417981fed2f12bd8fb00158dfa6fee561152bed689278c846d0272"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1545,9 +1544,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d6f59a22b559263c5c42747ae362cf5d4fb272293fa119a4623f8ec288f9656"
+checksum = "fc07f6bd581746f358e39c4b6bfe8d455b3d6ad1a857821016d0d42eeb5e1e3e"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1555,9 +1554,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.80.0"
+version = "0.85.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7d0575b54ffe09bc5d2f158454bc05f0c30c01d9992310965f854be50ae22b8"
+checksum = "2f49b86e1276c1c3c72898410def29b699415f4e7d1dfb3531daf79794694372"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 632b290ba984..f7074f913542 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -84,11 +84,11 @@ tt = { path = "./crates/tt", version = "0.0.0" }
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.80", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.80", default-features = false }
-ra-ap-rustc_index = { version = "0.80", default-features = false }
-ra-ap-rustc_abi = { version = "0.80", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.80", default-features = false }
+ra-ap-rustc_lexer = { version = "0.85", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.85", default-features = false }
+ra-ap-rustc_index = { version = "0.85", default-features = false }
+ra-ap-rustc_abi = { version = "0.85", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.85", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 test-fixture = { path = "./crates/test-fixture" }

From e6fbb5c8e6fe33d9922d7b80bf07a0ff7f0d3f89 Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Wed, 11 Dec 2024 10:30:01 +0100
Subject: [PATCH 189/197] fix: Swallow rustfmt parsing panics

---
 .../crates/rust-analyzer/src/handlers/request.rs              | 4 ++++
 1 file changed, 4 insertions(+)

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 e51b14f61181..fa78be5cb602 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
@@ -2352,6 +2352,10 @@ fn run_rustfmt(
                 );
                 Ok(None)
             }
+            // rustfmt panicked at lexing/parsing the file
+            Some(101) if !rustfmt_not_installed && captured_stderr.starts_with("error[") => {
+                Ok(None)
+            }
             _ => {
                 // Something else happened - e.g. `rustfmt` is missing or caught a signal
                 Err(LspError::new(

From 9e6b7c17c8d39563074c8ed8ba8a2ece72b3d243 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Wed, 11 Dec 2024 21:34:48 +1100
Subject: [PATCH 190/197] coverage: Adjust a codegen test to ignore the order
 of covmap/covfun globals

---
 tests/codegen/instrument-coverage/testprog.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs
index 655fe779fca6..9e918499d577 100644
--- a/tests/codegen/instrument-coverage/testprog.rs
+++ b/tests/codegen/instrument-coverage/testprog.rs
@@ -73,11 +73,9 @@ fn main() {
 
 // WIN:          $__llvm_profile_runtime_user = comdat any
 
-// CHECK:        @__llvm_coverage_mapping = private constant
-// CHECK-SAME:   section "[[INSTR_PROF_COVMAP]]", align 8
+// CHECK-DAG:    @__llvm_coverage_mapping = private constant {{.*}}, section "[[INSTR_PROF_COVMAP]]", align 8
 
-// CHECK:        @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant
-// CHECK-SAME:   section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
+// CHECK-DAG:    @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant {{.*}}, section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
 
 // WIN:          @__llvm_profile_runtime = external{{.*}}global i32
 

From 512f3fdebe72532a435238435f0e16eff61fbf38 Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Wed, 11 Dec 2024 15:12:23 +1100
Subject: [PATCH 191/197] coverage: Only generate a CGU's covmap record if it
 has covfun records

---
 .../src/coverageinfo/mapgen.rs                 | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 39fb0aeed071..f7c3193a4499 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -80,10 +80,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
     let filenames_val = cx.const_bytes(&filenames_buffer);
     let filenames_ref = llvm_cov::hash_bytes(&filenames_buffer);
 
-    // Generate the coverage map header, which contains the filenames used by
-    // this CGU's coverage mappings, and store it in a well-known global.
-    generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
-
     let mut unused_function_names = Vec::new();
 
     let covfun_records = function_coverage_map
@@ -93,6 +89,15 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         })
         .collect::>();
 
+    // If there are no covfun records for this CGU, don't generate a covmap record.
+    // Emitting a covmap record without any covfun records causes `llvm-cov` to
+    // fail when generating coverage reports, and if there are no covfun records
+    // then the covmap record isn't useful anyway.
+    // This should prevent a repeat of .
+    if covfun_records.is_empty() {
+        return;
+    }
+
     for covfun in &covfun_records {
         unused_function_names.extend(covfun.mangled_function_name_if_unused());
 
@@ -117,6 +122,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
         llvm::set_initializer(array, initializer);
     }
+
+    // Generate the coverage map header, which contains the filenames used by
+    // this CGU's coverage mappings, and store it in a well-known global.
+    // (This is skipped if we returned early due to having no covfun records.)
+    generate_covmap_record(cx, covmap_version, filenames_size, filenames_val);
 }
 
 /// Maps "global" (per-CGU) file ID numbers to their underlying filenames.

From 3f3a9bf7f50afbfde72cd0b9479323dddc84fe6d Mon Sep 17 00:00:00 2001
From: Zalathar 
Date: Wed, 11 Dec 2024 15:41:02 +1100
Subject: [PATCH 192/197] coverage: Store intermediate region tables in
 `CovfunRecord`

This defers the call to `llvm_cov::write_function_mappings_to_buffer` until
just before its enclosing global variable is created.
---
 .../src/coverageinfo/ffi.rs                   | 28 +++++++
 .../src/coverageinfo/llvm_cov.rs              |  7 +-
 .../src/coverageinfo/mapgen.rs                | 10 +--
 .../src/coverageinfo/mapgen/covfun.rs         | 83 +++++++++----------
 4 files changed, 75 insertions(+), 53 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
index a6e07ea2a60e..1f133141c18f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
@@ -152,6 +152,34 @@ impl CoverageSpan {
     }
 }
 
+/// Holds tables of the various region types in one struct.
+///
+/// Don't pass this struct across FFI; pass the individual region tables as
+/// pointer/length pairs instead.
+///
+/// Each field name has a `_regions` suffix for improved readability after
+/// exhaustive destructing, which ensures that all region types are handled.
+#[derive(Clone, Debug, Default)]
+pub(crate) struct Regions {
+    pub(crate) code_regions: Vec,
+    pub(crate) branch_regions: Vec,
+    pub(crate) mcdc_branch_regions: Vec,
+    pub(crate) mcdc_decision_regions: Vec,
+}
+
+impl Regions {
+    /// Returns true if none of this structure's tables contain any regions.
+    pub(crate) fn has_no_regions(&self) -> bool {
+        let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
+            self;
+
+        code_regions.is_empty()
+            && branch_regions.is_empty()
+            && mcdc_branch_regions.is_empty()
+            && mcdc_decision_regions.is_empty()
+    }
+}
+
 /// Must match the layout of `LLVMRustCoverageCodeRegion`.
 #[derive(Clone, Debug)]
 #[repr(C)]
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
index 99c2d12b2612..086cf1f44a03 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs
@@ -62,11 +62,10 @@ pub(crate) fn write_filenames_to_buffer<'a>(
 pub(crate) fn write_function_mappings_to_buffer(
     virtual_file_mapping: &[u32],
     expressions: &[ffi::CounterExpression],
-    code_regions: &[ffi::CodeRegion],
-    branch_regions: &[ffi::BranchRegion],
-    mcdc_branch_regions: &[ffi::MCDCBranchRegion],
-    mcdc_decision_regions: &[ffi::MCDCDecisionRegion],
+    regions: &ffi::Regions,
 ) -> Vec {
+    let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
+        regions;
     llvm::build_byte_buffer(|buffer| unsafe {
         llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer(
             virtual_file_mapping.as_ptr(),
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index f7c3193a4499..a573a37beb3f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -194,7 +194,7 @@ rustc_index::newtype_index! {
 
 /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
 /// file IDs.
-#[derive(Default)]
+#[derive(Debug, Default)]
 struct VirtualFileMapping {
     local_to_global: IndexVec,
     global_to_local: FxIndexMap,
@@ -208,10 +208,10 @@ impl VirtualFileMapping {
             .or_insert_with(|| self.local_to_global.push(global_file_id))
     }
 
-    fn into_vec(self) -> Vec {
-        // This conversion should be optimized away to ~zero overhead.
-        // In any case, it's probably not hot enough to worry about.
-        self.local_to_global.into_iter().map(|global| global.as_u32()).collect()
+    fn to_vec(&self) -> Vec {
+        // This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`,
+        // but it isn't hot or expensive enough to justify the extra unsafety.
+        self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect()
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index a68b026a4c06..530e6827f55d 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -29,7 +29,10 @@ pub(crate) struct CovfunRecord<'tcx> {
     mangled_function_name: &'tcx str,
     source_hash: u64,
     is_used: bool,
-    coverage_mapping_buffer: Vec,
+
+    virtual_file_mapping: VirtualFileMapping,
+    expressions: Vec,
+    regions: ffi::Regions,
 }
 
 impl<'tcx> CovfunRecord<'tcx> {
@@ -46,51 +49,41 @@ pub(crate) fn prepare_covfun_record<'tcx>(
     instance: Instance<'tcx>,
     function_coverage: &FunctionCoverage<'tcx>,
 ) -> Option> {
-    let mangled_function_name = tcx.symbol_name(instance).name;
-    let source_hash = function_coverage.source_hash();
-    let is_used = function_coverage.is_used();
+    let mut covfun = CovfunRecord {
+        mangled_function_name: tcx.symbol_name(instance).name,
+        source_hash: function_coverage.source_hash(),
+        is_used: function_coverage.is_used(),
+        virtual_file_mapping: VirtualFileMapping::default(),
+        expressions: function_coverage.counter_expressions().collect::>(),
+        regions: ffi::Regions::default(),
+    };
 
-    let coverage_mapping_buffer =
-        encode_mappings_for_function(tcx, global_file_table, function_coverage);
+    fill_region_tables(tcx, global_file_table, function_coverage, &mut covfun);
 
-    if coverage_mapping_buffer.is_empty() {
-        if function_coverage.is_used() {
-            bug!(
-                "A used function should have had coverage mapping data but did not: {}",
-                mangled_function_name
-            );
+    if covfun.regions.has_no_regions() {
+        if covfun.is_used {
+            bug!("a used function should have had coverage mapping data but did not: {covfun:?}");
         } else {
-            debug!("unused function had no coverage mapping data: {}", mangled_function_name);
+            debug!(?covfun, "unused function had no coverage mapping data");
             return None;
         }
     }
 
-    Some(CovfunRecord { mangled_function_name, source_hash, is_used, coverage_mapping_buffer })
+    Some(covfun)
 }
 
-/// Using the expressions and counter regions collected for a single function,
-/// generate the variable-sized payload of its corresponding `__llvm_covfun`
-/// entry. The payload is returned as a vector of bytes.
-///
-/// Newly-encountered filenames will be added to the global file table.
-fn encode_mappings_for_function(
-    tcx: TyCtxt<'_>,
+/// Populates the mapping region tables in the current function's covfun record.
+fn fill_region_tables<'tcx>(
+    tcx: TyCtxt<'tcx>,
     global_file_table: &GlobalFileTable,
-    function_coverage: &FunctionCoverage<'_>,
-) -> Vec {
+    function_coverage: &FunctionCoverage<'tcx>,
+    covfun: &mut CovfunRecord<'tcx>,
+) {
     let counter_regions = function_coverage.counter_regions();
     if counter_regions.is_empty() {
-        return Vec::new();
+        return;
     }
 
-    let expressions = function_coverage.counter_expressions().collect::>();
-
-    let mut virtual_file_mapping = VirtualFileMapping::default();
-    let mut code_regions = vec![];
-    let mut branch_regions = vec![];
-    let mut mcdc_branch_regions = vec![];
-    let mut mcdc_decision_regions = vec![];
-
     // Currently a function's mappings must all be in the same file as its body span.
     let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span);
 
@@ -98,9 +91,12 @@ fn encode_mappings_for_function(
     let global_file_id = global_file_table.global_file_id_for_file_name(file_name);
 
     // Associate that global file ID with a local file ID for this function.
-    let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id);
+    let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
     debug!("  file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'");
 
+    let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } =
+        &mut covfun.regions;
+
     // For each counter/region pair in this function+file, convert it to a
     // form suitable for FFI.
     for (mapping_kind, region) in counter_regions {
@@ -133,16 +129,6 @@ fn encode_mappings_for_function(
             }
         }
     }
-
-    // Encode the function's coverage mappings into a buffer.
-    llvm_cov::write_function_mappings_to_buffer(
-        &virtual_file_mapping.into_vec(),
-        &expressions,
-        &code_regions,
-        &branch_regions,
-        &mcdc_branch_regions,
-        &mcdc_decision_regions,
-    )
 }
 
 /// Generates the contents of the covfun record for this function, which
@@ -157,9 +143,18 @@ pub(crate) fn generate_covfun_record<'tcx>(
         mangled_function_name,
         source_hash,
         is_used,
-        ref coverage_mapping_buffer, // Previously-encoded coverage mappings
+        ref virtual_file_mapping,
+        ref expressions,
+        ref regions,
     } = covfun;
 
+    // Encode the function's coverage mappings into a buffer.
+    let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer(
+        &virtual_file_mapping.to_vec(),
+        expressions,
+        regions,
+    );
+
     // Concatenate the encoded coverage mappings
     let coverage_mapping_size = coverage_mapping_buffer.len();
     let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer);

From 48b883287adbe5c913e473e361c07f7c61c6bc5a Mon Sep 17 00:00:00 2001
From: Augie Fackler 
Date: Wed, 11 Dec 2024 04:14:16 -0500
Subject: [PATCH 193/197] wasm(32|64): update alignment string

See llvm/llvm-project@c5ab70c508457eaece5d7ff4ab79a2f90bc67f06

@rustbot label: +llvm-main
---
 compiler/rustc_codegen_llvm/src/context.rs                   | 5 +++++
 .../src/spec/targets/wasm32_unknown_emscripten.rs            | 3 ++-
 .../rustc_target/src/spec/targets/wasm32_unknown_unknown.rs  | 2 +-
 compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs      | 2 +-
 .../rustc_target/src/spec/targets/wasm32_wasip1_threads.rs   | 2 +-
 compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs      | 2 +-
 compiler/rustc_target/src/spec/targets/wasm32v1_none.rs      | 2 +-
 .../rustc_target/src/spec/targets/wasm64_unknown_unknown.rs  | 2 +-
 8 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index e0506c0c5fd1..c602d99ff9d8 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -164,6 +164,11 @@ pub(crate) unsafe fn create_module<'ll>(
             // See https://github.com/llvm/llvm-project/pull/118004
             target_data_layout = target_data_layout.replace("-i128:128", "");
         }
+        if sess.target.arch.starts_with("wasm32") || sess.target.arch.starts_with("wasm64") {
+            // LLVM 20 updates the wasm(32|64) layout to correctly align 128 bit integers to 128 bit.
+            // See https://github.com/llvm/llvm-project/pull/119204
+            target_data_layout = target_data_layout.replace("-i128:128", "");
+        }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index a70cebbd9c88..bdb1fc557112 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -32,7 +32,8 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
+            .into(),
         arch: "wasm32".into(),
         options: opts,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
index e7165533b9c0..96237f208917 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs
@@ -37,7 +37,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm32".into(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
index 1cd30f21bec1..0862958d05da 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs
@@ -55,7 +55,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm32".into(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
index 19bc5db4d9bc..0c2e2bfeda6d 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
@@ -66,7 +66,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm32".into(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
index f06112160d16..3f4618fad5aa 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
@@ -66,7 +66,7 @@ pub(crate) fn target() -> Target {
             std: Some(true),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm32".into(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
index bf35ae009c6e..5c35e9c21d3c 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs
@@ -44,7 +44,7 @@ pub(crate) fn target() -> Target {
             std: Some(false),
         },
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm32".into(),
         options,
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
index 5ba0fca9f64f..22fa26d3cdbd 100644
--- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs
@@ -40,7 +40,7 @@ pub(crate) fn target() -> Target {
             std: None, // ?
         },
         pointer_width: 64,
-        data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(),
         arch: "wasm64".into(),
         options,
     }

From 55806e565503f8d9e519f3c958f3c51836304cd2 Mon Sep 17 00:00:00 2001
From: Orion Gonzalez 
Date: Tue, 10 Dec 2024 23:19:45 +0100
Subject: [PATCH 194/197] document check_expr_field

---
 compiler/rustc_errors/src/lib.rs      |  2 +-
 compiler/rustc_hir_typeck/src/expr.rs | 27 ++++++++++++++++++++++-----
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 6232c875ee81..fc44340851c4 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1291,7 +1291,7 @@ impl<'a> DiagCtxtHandle<'a> {
         Diag::::new(self, DelayedBug, msg.into()).emit()
     }
 
-    /// Ensures that an error is printed. See `Level::DelayedBug`.
+    /// Ensures that an error is printed. See [`Level::DelayedBug`].
     ///
     /// Note: this function used to be called `delay_span_bug`. It was renamed
     /// to match similar functions like `span_err`, `span_warn`, etc.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0e079b037691..5ec97804ca98 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2688,33 +2688,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         None
     }
 
-    // Check field access expressions
+    /// Check field access expressions, this works for both structs and tuples.
+    /// Returns the Ty of the field.
+    ///
+    /// ```not_rust
+    ///  base.field
+    ///  ^^^^^^^^^^ expr
+    ///  ^^^^       base
+    ///       ^^^^^ field
+    ///  ```
     fn check_expr_field(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         base: &'tcx hir::Expr<'tcx>,
         field: Ident,
+        // The expected type hint of the field.
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
         let base_ty = self.check_expr(base);
         let base_ty = self.structurally_resolve_type(base.span, base_ty);
+
+        // Whether we are trying to access a private field. Used for error reporting.
         let mut private_candidate = None;
+
+        // Field expressions automatically deref
         let mut autoderef = self.autoderef(expr.span, base_ty);
         while let Some((deref_base_ty, _)) = autoderef.next() {
             debug!("deref_base_ty: {:?}", deref_base_ty);
             match deref_base_ty.kind() {
                 ty::Adt(base_def, args) if !base_def.is_enum() => {
                     debug!("struct named {:?}", deref_base_ty);
-                    let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
-                    let (ident, def_scope) =
-                        self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
-
                     // we don't care to report errors for a struct if the struct itself is tainted
                     if let Err(guar) = base_def.non_enum_variant().has_errors() {
                         return Ty::new_error(self.tcx(), guar);
                     }
 
+                    let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
+                    let (ident, def_scope) =
+                        self.tcx.adjust_ident_and_get_scope(field, base_def.did(), fn_body_hir_id);
+
                     if let Some((idx, field)) = self.find_adt_field(*base_def, ident) {
                         self.write_field_index(expr.hir_id, idx);
 
@@ -2748,6 +2761,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => {}
             }
         }
+        // We failed to check the expression, report an error.
+
+        // Emits an error if we deref an infer variable, like calling `.field` on a base type of &_.
         self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false));
 
         if let Some((adjustments, did)) = private_candidate {
@@ -2772,6 +2788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             expr.hir_id,
             expected.only_has_type(self),
         ) {
+            // If taking a method instead of calling it
             self.ban_take_value_of_method(expr, base_ty, field)
         } else if !base_ty.is_primitive_ty() {
             self.ban_nonexisting_field(field, base, expr, base_ty)

From cc797a2b741be734289ba857e99dc72be908d92d Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Thu, 12 Dec 2024 12:24:25 +0100
Subject: [PATCH 195/197] Preparing for merge from rustc

---
 src/tools/miri/rust-version | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 50710f55266e..03ad4a74a2c5 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-1b3fb316751227d30b1523ed0e3f00d83956d4d0
+903d2976fdb6ceeb65526b7555d8d1e6f8c02134

From a4ef751e26a90dd3b6b35fdbfef1e4854f9d80e1 Mon Sep 17 00:00:00 2001
From: jyn 
Date: Sun, 24 Dec 2023 19:49:23 -0500
Subject: [PATCH 196/197] don't show the full linker args unless `--verbose` is
 passed

the linker arguments can be *very* long, especially for crates with many dependencies. some parts of them are not very useful. unless specifically requested:
- omit object files specific to the current invocation
- fold rlib files into a single braced argument (in shell expansion format)

this shortens the output significantly without removing too much information.
---
 compiler/rustc_codegen_ssa/src/back/link.rs   |  4 +-
 compiler/rustc_codegen_ssa/src/errors.rs      | 70 +++++++++++++++++--
 .../src/external_deps/rustc.rs                |  6 ++
 tests/run-make/link-args-order/rmake.rs       |  6 +-
 tests/run-make/link-dedup/rmake.rs            | 12 ++--
 tests/run-make/linker-warning/fake-linker.rs  | 13 ++++
 tests/run-make/linker-warning/main.rs         |  1 +
 tests/run-make/linker-warning/rmake.rs        | 28 ++++++++
 8 files changed, 126 insertions(+), 14 deletions(-)
 create mode 100644 tests/run-make/linker-warning/fake-linker.rs
 create mode 100644 tests/run-make/linker-warning/main.rs
 create mode 100644 tests/run-make/linker-warning/rmake.rs

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 35d18d0206db..b030ea3f6df8 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -992,12 +992,12 @@ fn link_natively(
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_linker_output(&output, flavor);
-                // FIXME: Add UI tests for this error.
                 let err = errors::LinkingFailed {
                     linker_path: &linker_path,
                     exit_status: prog.status,
-                    command: &cmd,
+                    command: cmd,
                     escaped_output,
+                    verbose: sess.opts.verbose,
                 };
                 sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 00f8654e670b..c7213bbc801f 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,6 +1,7 @@
 //! Errors emitted by codegen_ssa
 
 use std::borrow::Cow;
+use std::ffi::OsString;
 use std::io::Error;
 use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
@@ -345,21 +346,82 @@ impl Diagnostic<'_, G> for ThorinErrorWrapper {
 }
 
 pub(crate) struct LinkingFailed<'a> {
-    pub linker_path: &'a PathBuf,
+    pub linker_path: &'a Path,
     pub exit_status: ExitStatus,
-    pub command: &'a Command,
+    pub command: Command,
     pub escaped_output: String,
+    pub verbose: bool,
 }
 
 impl Diagnostic<'_, G> for LinkingFailed<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+    fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
         let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
         diag.arg("linker_path", format!("{}", self.linker_path.display()));
         diag.arg("exit_status", format!("{}", self.exit_status));
 
         let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
 
-        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+        if self.verbose {
+            diag.note(format!("{:?}", self.command));
+        } else {
+            enum ArgGroup {
+                Regular(OsString),
+                Objects(usize),
+                Rlibs(PathBuf, Vec),
+            }
+
+            // Omit rust object files and fold rlibs in the error by default to make linker errors a
+            // bit less verbose.
+            let orig_args = self.command.take_args();
+            let mut args: Vec = vec![];
+            for arg in orig_args {
+                if arg.as_encoded_bytes().ends_with(b".rcgu.o") {
+                    if let Some(ArgGroup::Objects(n)) = args.last_mut() {
+                        *n += 1;
+                    } else {
+                        args.push(ArgGroup::Objects(1));
+                    }
+                } else if arg.as_encoded_bytes().ends_with(b".rlib") {
+                    let rlib_path = Path::new(&arg);
+                    let dir = rlib_path.parent().unwrap();
+                    let filename = rlib_path.file_name().unwrap().to_owned();
+                    if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() {
+                        if parent == dir {
+                            rlibs.push(filename);
+                        } else {
+                            args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                        }
+                    } else {
+                        args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                    }
+                } else {
+                    args.push(ArgGroup::Regular(arg));
+                }
+            }
+            self.command.args(args.into_iter().map(|arg_group| match arg_group {
+                ArgGroup::Regular(arg) => arg,
+                ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
+                ArgGroup::Rlibs(dir, rlibs) => {
+                    let mut arg = dir.into_os_string();
+                    arg.push("/{");
+                    let mut first = true;
+                    for rlib in rlibs {
+                        if !first {
+                            arg.push(",");
+                        }
+                        first = false;
+                        arg.push(rlib);
+                    }
+                    arg.push("}");
+                    arg
+                }
+            }));
+
+            diag.note(format!("{:?}", self.command));
+            diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
+        }
+
+        diag.note(self.escaped_output);
 
         // Trying to match an error from OS linkers
         // which by now we have no way to translate.
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index ffe10092cc28..8894ea7fb209 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -325,6 +325,12 @@ impl Rustc {
         self
     }
 
+    /// Pass the `--verbose` flag.
+    pub fn verbose(&mut self) -> &mut Self {
+        self.cmd.arg("--verbose");
+        self
+    }
+
     /// `EXTRARSCXXFLAGS`
     pub fn extra_rs_cxx_flags(&mut self) -> &mut Self {
         // Adapted from tools.mk (trimmed):
diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs
index b7ef8333267f..fe0d02926eff 100644
--- a/tests/run-make/link-args-order/rmake.rs
+++ b/tests/run-make/link-args-order/rmake.rs
@@ -15,8 +15,9 @@ fn main() {
         .link_args("b c")
         .link_args("d e")
         .link_arg("f")
+        .arg("--print=link-args")
         .run_fail()
-        .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
+        .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
     rustc()
         .input("empty.rs")
         .linker_flavor(linker)
@@ -24,6 +25,7 @@ fn main() {
         .arg("-Zpre-link-args=b c")
         .arg("-Zpre-link-args=d e")
         .arg("-Zpre-link-arg=f")
+        .arg("--print=link-args")
         .run_fail()
-        .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
+        .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#);
 }
diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs
index 6075f3109542..f38603dee8cb 100644
--- a/tests/run-make/link-dedup/rmake.rs
+++ b/tests/run-make/link-dedup/rmake.rs
@@ -14,13 +14,13 @@ fn main() {
     rustc().input("depb.rs").run();
     rustc().input("depc.rs").run();
 
-    let output = rustc().input("empty.rs").cfg("bar").run_fail();
-    output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
+    let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail();
+    output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"]));
 
-    let output = rustc().input("empty.rs").run_fail();
-    output.assert_stderr_contains(needle_from_libs(&["testa"]));
-    output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
-    output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
+    let output = rustc().input("empty.rs").arg("--print=link-args").run_fail();
+    output.assert_stdout_contains(needle_from_libs(&["testa"]));
+    output.assert_stdout_not_contains(needle_from_libs(&["testb"]));
+    output.assert_stdout_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
     // Adjacent identical native libraries are no longer deduplicated if
     // they come from different crates (https://github.com/rust-lang/rust/pull/103311)
     // so the following will fail:
diff --git a/tests/run-make/linker-warning/fake-linker.rs b/tests/run-make/linker-warning/fake-linker.rs
new file mode 100644
index 000000000000..30497eea2ccd
--- /dev/null
+++ b/tests/run-make/linker-warning/fake-linker.rs
@@ -0,0 +1,13 @@
+fn main() {
+    for arg in std::env::args() {
+        match &*arg {
+            "run_make_info" => println!("foo"),
+            "run_make_warn" => eprintln!("warning: bar"),
+            "run_make_error" => {
+                eprintln!("error: baz");
+                std::process::exit(1);
+            }
+            _ => (),
+        }
+    }
+}
diff --git a/tests/run-make/linker-warning/main.rs b/tests/run-make/linker-warning/main.rs
new file mode 100644
index 000000000000..f328e4d9d04c
--- /dev/null
+++ b/tests/run-make/linker-warning/main.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
new file mode 100644
index 000000000000..4d21c5ea5690
--- /dev/null
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -0,0 +1,28 @@
+use run_make_support::{Rustc, rustc};
+
+fn run_rustc() -> Rustc {
+    let mut rustc = rustc();
+    rustc.arg("main.rs").output("main").linker("./fake-linker");
+    rustc
+}
+
+fn main() {
+    // first, compile our linker
+    rustc().arg("fake-linker.rs").output("fake-linker").run();
+
+    // Make sure we don't show the linker args unless `--verbose` is passed
+    run_rustc()
+        .link_arg("run_make_error")
+        .verbose()
+        .run_fail()
+        .assert_stderr_contains_regex("fake-linker.*run_make_error")
+        .assert_stderr_not_contains("object files omitted")
+        .assert_stderr_contains_regex(r"lib(/|\\\\)libstd");
+    run_rustc()
+        .link_arg("run_make_error")
+        .run_fail()
+        .assert_stderr_contains("fake-linker")
+        .assert_stderr_contains("object files omitted")
+        .assert_stderr_contains_regex(r"\{")
+        .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd");
+}

From 202098e049bfd0e505ad7f698ed281e58bcdfa58 Mon Sep 17 00:00:00 2001
From: Ralf Jung 
Date: Thu, 12 Dec 2024 12:27:01 +0100
Subject: [PATCH 197/197] fix use of this.allocate_bytes

---
 src/tools/miri/src/shims/time.rs | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 11557d51c8e5..72d98bc1c487 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -5,8 +5,6 @@ use std::time::{Duration, SystemTime};
 
 use chrono::{DateTime, Datelike, Offset, Timelike, Utc};
 use chrono_tz::Tz;
-use rustc_abi::Align;
-use rustc_ast::ast::Mutability;
 
 use crate::*;
 
@@ -202,12 +200,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             tm_zone.push('\0');
 
             // Deduplicate and allocate the string.
-            let tm_zone_ptr = this.allocate_bytes(
-                tm_zone.as_bytes(),
-                Align::ONE,
-                MiriMemoryKind::Machine.into(),
-                Mutability::Not,
-            )?;
+            let tm_zone_ptr = this.allocate_bytes_dedup(tm_zone.as_bytes())?;
 
             // Write the timezone pointer and offset into the result structure.
             this.write_pointer(tm_zone_ptr, &this.project_field_named(&result, "tm_zone")?)?;