From bcdc0d397f8cd36acce54facde45aea548e7603f Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 25 Aug 2026 01:02:57 +0800 Subject: [PATCH 01/27] fix: do not panic when inline call param usages in macro Example --- ```rust macro_rules! identity { ($($t:tt)*) => { $($t)* }; } struct Foo; impl Foo { fn foo(self, r1: u32, r2: u32, (complex,): (u32,)) { identity! { let _ = self; let _ = r1; let _ = (r2, r2); let _ = complex; } } } fn bar() { Foo.$0foo(1, 2, (3,)); } ``` **Before this PR** request handler panicked: TextRange -offset overflowed **After this PR** ```rust fn bar() { { let this = Foo; let r1 = 1; let r2 = 2; let (complex,) = (3,); identity! { let _ = this; let _ = r1; let _ = (r2, r2); let _ = complex; } }; } ``` --- .../ide-assists/src/handlers/inline_call.rs | 98 ++++++++++++++++++- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs index 621ac9223abd9..78c4d3007e565 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs @@ -13,7 +13,7 @@ use ide_db::{ }; use itertools::{Itertools, izip}; use syntax::{ - AstNode, NodeOrToken, SyntaxKind, TextRange, + AstNode, NodeOrToken, SyntaxKind, T, TextRange, ast::{ self, HasArgList, HasGenericArgs, Pat, PathExpr, edit::{AstNodeEdit, IndentLevel}, @@ -345,6 +345,7 @@ fn inline<'db>( file_editor: &SyntaxEditor, ) -> ast::Expr { let make = file_editor.make(); + // Do not use original range as the body may be generated by a macro without mapping let file_id = sema.hir_file_for(fn_body.syntax()); // Capture before `with_ast_node` re-roots and loses the source-relative position. @@ -353,6 +354,7 @@ fn inline<'db>( let (editor, body) = SyntaxEditor::with_ast_node(fn_body); let usages_for_locals = |local| { + let body_root = fn_body.syntax().tree_top(); Definition::Local(local) .usages(sema) .all() @@ -360,6 +362,7 @@ fn inline<'db>( .remove(&function_def_file_id) .unwrap_or_default() .into_iter() + .filter(move |it| it.name.syntax().tree_top() == body_root) }; let param_use_nodes: Vec> = params .iter() @@ -471,6 +474,27 @@ fn inline<'db>( for usage in &self_token_usages { editor.replace(usage.clone(), this_token.clone()); } + // Due to the difficulty in handling the parameters referenced by macro calls + // in macro generation functions, so add a syntax-based fallback + let mut depth = 0u32; + let not_replaced = |it: &syntax::SyntaxElement| { + self_token_usages + .iter() + .all(|usage| !usage.text_range().contains_range(it.text_range())) + }; + let is_item_like = |kind| ast::Item::can_cast(kind) && !ast::MacroCall::can_cast(kind); + for event in body.syntax().preorder_with_tokens() { + match event { + syntax::WalkEvent::Enter(it) if is_item_like(it.kind()) => depth += 1, + syntax::WalkEvent::Leave(it) if is_item_like(it.kind()) => depth -= 1, + syntax::WalkEvent::Enter(it) + if it.kind() == T![self] && depth == 0 && not_replaced(&it) => + { + editor.replace(it, this_token.clone()); + } + _ => (), + } + } }; // Inline parameter expressions or generate `let` statements depending on whether inlining works or not. @@ -611,10 +635,15 @@ fn inline<'db>( body = ast::BlockExpr::cast(body_prettified).unwrap(); } + fn reindent(value: T) -> T { + value.reset_indent().indent(1.into()) + } let is_async_fn = function.is_async(sema.db); if is_async_fn { cov_mark::hit!(inline_call_async_fn); - body = make.async_move_block_expr(body.statements(), body.tail_expr()); + body = make + .async_move_block_expr(body.statements().map(reindent), body.tail_expr().map(reindent)); + original_body_indent = IndentLevel(0); // Arguments should be evaluated outside the async block, and then moved into it. if !let_stmts.is_empty() { @@ -624,8 +653,9 @@ fn inline<'db>( } } else if !let_stmts.is_empty() { // Prepend let statements to the body's existing statements - let stmts: Vec = let_stmts.into_iter().chain(body.statements()).collect(); - body = make.block_expr(stmts, body.tail_expr()); + let stmts: Vec = + let_stmts.into_iter().chain(body.statements().map(reindent)).collect(); + body = make.block_expr(stmts, body.tail_expr().map(reindent)); original_body_indent = IndentLevel(0); } @@ -1917,6 +1947,64 @@ pub fn main() { #[test] fn inline_call_with_reference_in_macros() { + check_assist( + inline_call, + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +struct Foo; +impl Foo { + fn foo(self, r1: u32, r2: u32, (complex,): (u32,)) { + identity! { + let _ = self; + let _ = r1; + let _ = (r2, r2); + let _ = complex; + } + impl Foo { + fn nested(self) { _ = self; } + } + } +} +fn bar() { + Foo.$0foo(1, 2, (3,)); +} +"#, + r#" +macro_rules! identity { ($($t:tt)*) => { $($t)* }; } +struct Foo; +impl Foo { + fn foo(self, r1: u32, r2: u32, (complex,): (u32,)) { + identity! { + let _ = self; + let _ = r1; + let _ = (r2, r2); + let _ = complex; + } + impl Foo { + fn nested(self) { _ = self; } + } + } +} +fn bar() { + { + let this = Foo; + let r1 = 1; + let r2 = 2; + let (complex,) = (3,); + identity! { + let _ = this; + let _ = r1; + let _ = (r2, r2); + let _ = complex; + } + impl Foo { + fn nested(self) { _ = self; } + } + }; +} +"#, + ); + check_assist( inline_call, r#" @@ -1955,7 +2043,7 @@ fn _hash2(self_: &u64, state: &mut u64) { }; } "#, - ) + ); } #[test] From 21b075e843ce8cb1062c80d35f8274827fa1b87d Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 26 Sep 2026 12:20:08 +0200 Subject: [PATCH 02/27] Fix NamedTempFile issues on windows --- .../rust-analyzer/crates/stdx/src/tempfile.rs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/stdx/src/tempfile.rs b/src/tools/rust-analyzer/crates/stdx/src/tempfile.rs index 8907f4ca18b80..1498f0322bb50 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/tempfile.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/tempfile.rs @@ -21,7 +21,7 @@ impl NamedTempFile { /// Creates a new `NamedTempFile` that is a copy of an existing file. pub fn new_from_existing(prefix: &str, existing: &Path) -> io::Result { let result = NamedTempFile::new(prefix)?; - std::fs::copy(existing, &result.path)?; + io::copy(&mut File::open(existing)?, &mut File::options().write(true).open(&result.path)?)?; Ok(result) } @@ -160,10 +160,12 @@ mod imp { const FILE_ATTRIBUTE_TEMPORARY: u32 = 0x100; const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; + const GENERIC_READ: u32 = 0x80000000; pub(super) fn create(prefix: &str) -> io::Result { let (file, path) = general_imp::create(prefix, |mut options, path| { options + .access_mode(GENERIC_READ) .attributes(FILE_ATTRIBUTE_TEMPORARY) .custom_flags(FILE_FLAG_DELETE_ON_CLOSE) .open(path) @@ -194,6 +196,39 @@ mod tests { use super::*; + #[test] + fn named_temp_file_new_from_existing_copies_file() { + let dir = NamedTempDir::new("test-").unwrap(); + let source = dir.path().join("source"); + fs::write(&source, b"contents").unwrap(); + + let file = NamedTempFile::new_from_existing("test-copy-", &source).unwrap(); + assert_eq!(fs::read(file.path()).unwrap(), b"contents"); + fs::write(&source, b"changed").unwrap(); + assert_eq!(fs::read(file.path()).unwrap(), b"contents"); + + let path = file.path().to_owned(); + drop(file); + assert!(!fs::exists(path).unwrap()); + assert_eq!(fs::read(source).unwrap(), b"changed"); + } + + #[cfg(windows)] + #[test] + fn named_temp_file_allows_read_only_sharing() { + use std::os::windows::fs::OpenOptionsExt; + + const FILE_SHARE_READ: u32 = 1; + const FILE_SHARE_DELETE: u32 = 4; + + let file = NamedTempFile::new("test-").unwrap(); + let _reader = fs::OpenOptions::new() + .read(true) + .share_mode(FILE_SHARE_READ | FILE_SHARE_DELETE) + .open(file.path()) + .unwrap(); + } + #[test] fn named_temp_file_new_creates_file() { let file = NamedTempFile::new("test-").unwrap(); From 43ab58dfd986d46d960200e703136cfb30a66e21 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 8 Oct 2026 02:18:55 +0800 Subject: [PATCH 03/27] fix: compute ref-match on undotted self MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - And fix method call name-match Example --- ```rust struct S { info: u32 } impl S { fn info(&self) -> u32 { self.info } fn foo(&self) { needs(i$0); } } fn needs(info: &mut u32) {} ``` **Before this PR** ```text fd self.info u32 [name] lc self &S [local] st S S [] sp Self S [] fn needs(…) fn(&mut u32) [] me self.foo() fn(&self) [] me self.info() fn(&self) -> u32 [] ``` **After this PR** ```text fd self.info u32 [name] fd &mut self.info [type+name] me self.info() fn(&self) -> u32 [name] me &mut self.info() [type+name] lc self &S [local] st S S [] sp Self S [] fn needs(…) fn(&mut u32) [] me self.foo() fn(&self) [] ``` --- .../ide-completion/src/completions/dot.rs | 45 ++++++------------- .../crates/ide-completion/src/render.rs | 23 ++++++++++ .../ide-completion/src/render/function.rs | 2 +- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index fb6a747a64803..07ac8675dab57 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -5,7 +5,7 @@ use std::{collections::hash_map, ops::ControlFlow}; use hir::{Complete, Function, HasContainer, ItemContainer, MethodCandidateCallback, Name}; use ide_db::{FxHashMap, FxHashSet}; use itertools::Either; -use syntax::SmolStr; +use syntax::{AstNode, SmolStr, ast}; use crate::{ CompletionItem, CompletionItemKind, Completions, @@ -150,6 +150,17 @@ pub(crate) fn complete_undotted_self( _ => return, }; + let receiver = + path_ctx.original_path.as_ref().and_then(|it| ast::Expr::cast(it.syntax().parent()?)); + let fake_dot_access = &DotAccess { + receiver, + receiver_ty: None, + kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, + ctx: DotAccessExprCtx { + in_block_expr: expr_ctx.in_block_expr, + in_breakable: expr_ctx.in_breakable, + }, + }; let (param_name, ty) = match self_param { Either::Left(self_param) => ("self", &self_param.ty(ctx.db)), Either::Right(this_param) => ("this", this_param.ty()), @@ -159,21 +170,7 @@ pub(crate) fn complete_undotted_self( ctx, ty, |acc, field, ty| { - acc.add_field( - ctx, - &DotAccess { - receiver: None, - receiver_ty: None, - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, - ctx: DotAccessExprCtx { - in_block_expr: expr_ctx.in_block_expr, - in_breakable: expr_ctx.in_breakable, - }, - }, - Some(SmolStr::new_static(param_name)), - field, - &ty, - ) + acc.add_field(ctx, fake_dot_access, Some(SmolStr::new_static(param_name)), field, &ty) }, |acc, field, ty| { acc.add_tuple_field(ctx, Some(SmolStr::new_static(param_name)), field, &ty) @@ -181,21 +178,7 @@ pub(crate) fn complete_undotted_self( false, ); complete_methods(ctx, ty, &ctx.traits_in_scope(), |func| { - acc.add_method( - ctx, - &DotAccess { - receiver: None, - receiver_ty: None, - kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }, - ctx: DotAccessExprCtx { - in_block_expr: expr_ctx.in_block_expr, - in_breakable: expr_ctx.in_breakable, - }, - }, - func, - Some(SmolStr::new_static(param_name)), - None, - ) + acc.add_method(ctx, fake_dot_access, func, Some(SmolStr::new_static(param_name)), None) }); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 79f1c9da7f435..1676bc833ebdc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -3568,6 +3568,29 @@ fn main() { fn main() fn() [] "#]], ); + check_relevance( + r#" +struct S { info: u32 } +impl S { + fn info(&self) -> u32 { self.info } + fn foo(&self) { + needs(i$0); + } +} +fn needs(info: &mut u32) {} + "#, + expect![[r#" + fd self.info u32 [name] + fd &mut self.info [type+name] + me self.info() fn(&self) -> u32 [name] + me &mut self.info() [type+name] + lc self &S [local] + st S S [] + sp Self S [] + fn needs(…) fn(&mut u32) [] + me self.foo() fn(&self) [] + "#]], + ); // Regression test https://github.com/rust-lang/rust-analyzer/issues/22324 check_relevance( r#" diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 0ed4d7c9c648e..446c60fb1496a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -121,7 +121,7 @@ fn render( } else { compute_type_match(completion, &ctx.completion.rebase_ty(&func.ty(db))) }, - exact_name_match: compute_exact_name_match(completion, &call), + exact_name_match: compute_exact_name_match(completion, name.as_str()), function, trait_: trait_info, is_skipping_completion: matches!(func_kind, FuncKind::Method(_, Some(_))), From fc8acabf29943b68aab01ad1d90ba305ce607b0d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 19 Oct 2026 14:44:55 +0800 Subject: [PATCH 04/27] fix: complete 'main' 'lib' module in sub module Example --- ```rust //- /lib.rs mod sub { mod $0 } //- /sub/lib.rs //- /sub/main.rs ``` **Before this PR** Cannot complete any modules **After this PR** ```rust md lib; md main; ``` --- .../ide-completion/src/completions/mod_.rs | 89 ++++++++++++++++--- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index bea829465552d..ac38460dc1c92 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -41,15 +41,16 @@ pub(crate) fn complete_mod( } let module_definition_file = - current_module.definition_source_file_id(ctx.db).original_file(ctx.db); - let source_root_id = - ctx.db.file_source_root(module_definition_file.file_id(ctx.db)).source_root_id(ctx.db); + current_module.definition_source_file_id(ctx.db).original_file(ctx.db).file_id(ctx.db); + let source_root_id = ctx.db.file_source_root(module_definition_file).source_root_id(ctx.db); let source_root = ctx.db.source_root(source_root_id).source_root(ctx.db); + let root_path = source_root.path_for_file(&ctx.krate.root_file(ctx.db))?; let directory_to_look_for_submodules = directory_to_look_for_submodules( current_module, ctx.db, - source_root.path_for_file(&module_definition_file.file_id(ctx.db))?, + root_path, + source_root.path_for_file(&module_definition_file)?, )?; let existing_mod_declarations = current_module @@ -65,9 +66,7 @@ pub(crate) fn complete_mod( source_root .iter() - .filter(|&submodule_candidate_file| { - submodule_candidate_file != module_definition_file.file_id(ctx.db) - }) + .filter(|&submodule_candidate_file| submodule_candidate_file != module_definition_file) .filter(|&submodule_candidate_file| { module_declaration_file.is_none_or(|it| it.file_id(ctx.db) != submodule_candidate_file) }) @@ -75,11 +74,10 @@ pub(crate) fn complete_mod( let submodule_path = source_root.path_for_file(&submodule_file)?; let directory_with_submodule = submodule_path.parent()?; let (name, ext) = submodule_path.name_and_extension()?; - if ext != Some("rs") { + if ext != Some("rs") || is_source_root(root_path, submodule_path) { return None; } match name { - "lib" | "main" => None, "mod" => { if directory_with_submodule.parent()? == directory_to_look_for_submodules { match directory_with_submodule.name_and_extension()? { @@ -118,6 +116,7 @@ pub(crate) fn complete_mod( fn directory_to_look_for_submodules( module: Module, db: &RootDatabase, + root_path: &VfsPath, module_file_path: &VfsPath, ) -> Option { let directory_with_module_path = module_file_path.parent()?; @@ -126,7 +125,8 @@ fn directory_to_look_for_submodules( return None; } let base_directory = match name { - "mod" | "lib" | "main" => Some(directory_with_module_path), + "mod" => Some(directory_with_module_path), + _ if is_source_root(root_path, module_file_path) => Some(directory_with_module_path), regular_rust_file_name => { if matches!( ( @@ -164,6 +164,13 @@ fn module_chain_to_containing_module_file( path } +// FIXME: It doesn't seem to support custom crate roots +fn is_source_root(root_path: &VfsPath, path: &VfsPath) -> bool { + let Some(root_dir) = root_path.parent() else { return false }; + let Some((name, _)) = path.name_and_extension() else { return false }; + path.parent() == Some(root_dir) && matches!(name, "main" | "lib") +} + #[cfg(test)] mod tests { use expect_test::expect; @@ -225,6 +232,68 @@ mod $0 ); } + #[test] + fn exclude_crate_roots() { + check( + r#" +//- /lib.rs crate:lib +mod $0 +//- /main.rs crate:main +//- /sub.rs +"#, + expect![[r#" + md sub; + "#]], + ); + check( + r#" +//- /main.rs crate:main +mod $0 +//- /lib.rs crate:lib +//- /sub.rs +"#, + expect![[r#" + md sub; + "#]], + ); + } + + #[test] + fn contained_submodule_name_same_as_root() { + check( + r#" +//- /lib.rs +mod sub { + mod $0 +} +//- /sub/lib.rs +//- /sub/main.rs +"#, + expect![[r#" + md lib; + md main; + "#]], + ); + } + + #[test] + fn inside_name_same_as_root() { + check( + r#" +//- /foo/lib.rs +mod $0 +//- /foo/lib/loader.rs +//- /lib.rs +mod foo { + mod lib; +} +"#, + expect![[r#" + md loader; + "#]], + ); + } + #[test] fn main_module_completion() { check( From 20986b67a2cfee969ce90a25eed10f05adc9c1f0 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Wed, 14 Oct 2026 08:30:56 +0100 Subject: [PATCH 05/27] Remove the 'sub' method from 'At' and migrate to 'sub_raw' --- compiler/rustc_infer/src/infer/at.rs | 60 +++++++------------ compiler/rustc_infer/src/infer/mod.rs | 2 +- .../rustc_infer/src/infer/relate/lattice.rs | 25 ++++++-- .../src/traits/engine.rs | 3 +- 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 8eabbc0dcb06f..0dfadda1f3958 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -171,7 +171,7 @@ impl<'tcx> InferCtxt<'tcx> { /// If possible, prefer the wrapper methods on `ObligationCtxt`, /// `FnCtxt`, or `TypeChecker`. pub fn sub_raw( - self, + &self, cause: &ObligationCause<'tcx>, param_env: ParamEnv<'tcx>, define_opaque_types: DefineOpaqueTypes, @@ -181,7 +181,20 @@ impl<'tcx> InferCtxt<'tcx> { where T: ToTrace<'tcx>, { - self.at(cause, param_env).sub(define_opaque_types, expected, actual) + if self.next_trait_solver { + NextSolverRelate::relate(self, param_env, expected, ty::Covariant, actual, cause.span) + .map(|goals| self.goals_to_obligations(cause, goals)) + } else { + let mut op = TypeRelating::new( + self, + ToTrace::to_trace(cause, expected, actual), + param_env, + define_opaque_types, + ty::Covariant, + ); + op.relate(expected, actual)?; + Ok(InferOk { value: (), obligations: op.into_obligations() }) + } } /// Makes `expected == actual`. @@ -288,41 +301,6 @@ pub trait ToTrace<'tcx>: Relate> + Copy { } impl<'a, 'tcx> At<'a, 'tcx> { - /// Makes `expected <: actual`. - /// - /// FIXME: To be removed in favor of the [`InferCtxt::sub_raw`] method instead. - pub fn sub( - self, - define_opaque_types: DefineOpaqueTypes, - expected: T, - actual: T, - ) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - if self.infcx.next_trait_solver { - NextSolverRelate::relate( - self.infcx, - self.param_env, - expected, - ty::Covariant, - actual, - self.cause.span, - ) - .map(|goals| self.goals_to_obligations(goals)) - } else { - let mut op = TypeRelating::new( - self.infcx, - ToTrace::to_trace(self.cause, expected, actual), - self.param_env, - define_opaque_types, - ty::Covariant, - ); - op.relate(expected, actual)?; - Ok(InferOk { value: (), obligations: op.into_obligations() }) - } - } - /// Makes `expected == actual`. /// /// FIXME: To be removed in favor of the [`InferCtxt::eq_raw`] method instead. @@ -391,7 +369,13 @@ impl<'a, 'tcx> At<'a, 'tcx> { T: ToTrace<'tcx>, { match variance { - ty::Covariant => self.sub(define_opaque_types, expected, actual), + ty::Covariant => self.infcx.sub_raw( + self.cause, + self.param_env, + define_opaque_types, + expected, + actual, + ), ty::Invariant => self.eq(define_opaque_types, expected, actual), ty::Contravariant => self.infcx.sup_raw( self.cause, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 76234c7459f84..7623a591f2b39 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -883,7 +883,7 @@ impl<'tcx> InferCtxt<'tcx> { self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { if a_is_expected { - Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) + Ok(self.sub_raw(cause, param_env, DefineOpaqueTypes::Yes, a, b)) } else { Ok(self.sup_raw(cause, param_env, DefineOpaqueTypes::Yes, b, a)) } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 648bccbb618bc..875631eef1f65 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -255,15 +255,30 @@ impl<'infcx, 'tcx> LatticeOp<'infcx, 'tcx> { // relates `v` to `a` first, which may help us to avoid unnecessary // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let at = self.infcx.at(&self.trace.cause, self.param_env); match self.kind { LatticeOpKind::Glb => { - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, a)?.into_obligations()); - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, v, b)?.into_obligations()); + self.obligations.extend( + self.infcx + .sub_raw(&self.trace.cause, self.param_env, DefineOpaqueTypes::Yes, v, a)? + .into_obligations(), + ); + self.obligations.extend( + self.infcx + .sub_raw(&self.trace.cause, self.param_env, DefineOpaqueTypes::Yes, v, b)? + .into_obligations(), + ); } LatticeOpKind::Lub => { - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, a, v)?.into_obligations()); - self.obligations.extend(at.sub(DefineOpaqueTypes::Yes, b, v)?.into_obligations()); + self.obligations.extend( + self.infcx + .sub_raw(&self.trace.cause, self.param_env, DefineOpaqueTypes::Yes, a, v)? + .into_obligations(), + ); + self.obligations.extend( + self.infcx + .sub_raw(&self.trace.cause, self.param_env, DefineOpaqueTypes::Yes, b, v)? + .into_obligations(), + ); } } Ok(()) diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 8f57c3c222d6a..a2afa9faea97f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -255,8 +255,7 @@ where actual: T, ) -> Result<(), TypeError<'tcx>> { self.infcx - .at(cause, param_env) - .sub(DefineOpaqueTypes::Yes, expected, actual) + .sub_raw(cause, param_env, DefineOpaqueTypes::Yes, expected, actual) .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } From 35e265ad068090b2517644975bc125ec20e07f2e Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 19 Oct 2026 19:50:21 +0800 Subject: [PATCH 06/27] minor: 'pd' snippet use `$1` instead of multi `$0` This is convenient for jumping out and makes it work on some clients that do not support multi-`$0` tabstop Example --- **Before this PR** ```rust snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);") ``` **After this PR** ```rust snippet(ctx, cap, "pd", "eprintln!(\"$1 = {:?}\", $1);") ``` --- .../crates/ide-completion/src/completions/snippet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs index 7432c5226bfad..a93679a2b9d79 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs @@ -31,8 +31,8 @@ pub(crate) fn complete_expr_snippet( } if in_block_expr { - snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc, ctx.db); - snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc, ctx.db); + snippet(ctx, cap, "pd", "eprintln!(\"$1 = {:?}\", $1);").add_to(acc, ctx.db); + snippet(ctx, cap, "ppd", "eprintln!(\"$1 = {:#?}\", $1);").add_to(acc, ctx.db); let item = snippet( ctx, cap, From d37951b894a92dadab1e4ac997a6ddd3aea9d26a Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 20 Oct 2026 13:21:39 +0800 Subject: [PATCH 07/27] minor: add '(' to item recover, improve fn missing name Example --- ```rust fn () {} ``` ```diff SOURCE_FILE FN FN_KW "fn" WHITESPACE " " - ERROR + PARAM_LIST L_PAREN "(" - ERROR R_PAREN ")" WHITESPACE " " BLOCK_EXPR STMT_LIST L_CURLY "{" R_CURLY "}" WHITESPACE "\n" -error 3: expected a name -error 4: expected function arguments -error 4: expected a curly brace +error 2: expected a name ``` --- .../crates/parser/src/grammar/items.rs | 3 +++ .../crates/parser/test_data/generated/runner.rs | 4 ++++ .../parser/inline/err/function_missing_name.rast | 14 ++++++++++++++ .../parser/inline/err/function_missing_name.rs | 1 + 4 files changed, 22 insertions(+) create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rast create mode 100644 src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rs 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 88a43972329ba..c563a44612b0f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -43,6 +43,7 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![use], T![macro], T![;], + T!['('], ]); pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool, is_in_extern: bool) { @@ -432,6 +433,8 @@ fn macro_def(p: &mut Parser<'_>, m: Marker) { fn fn_(p: &mut Parser<'_>, m: Marker) { p.bump(T![fn]); + // test_err function_missing_name + // fn () {} name_r(p, ITEM_RECOVERY_SET); // test function_type_params // fn foo(){} 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 71e536c35896b..30a4f67865ec0 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 @@ -867,6 +867,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/fn_ret_recovery.rs"); } #[test] + fn function_missing_name() { + run_and_expect_errors("test_data/parser/inline/err/function_missing_name.rs"); + } + #[test] fn function_ret_type_missing_arrow() { run_and_expect_errors("test_data/parser/inline/err/function_ret_type_missing_arrow.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rast new file mode 100644 index 0000000000000..02de0263ad98b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rast @@ -0,0 +1,14 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 2: expected a name diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rs new file mode 100644 index 0000000000000..a0f0fb1bf5671 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/function_missing_name.rs @@ -0,0 +1 @@ +fn () {} From 01425434bf9a2c942696d5d3a149a303abaf98a5 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 20 Oct 2026 13:43:11 +0800 Subject: [PATCH 08/27] Update macro_expansion_tests Example --- ```rust const _=x::() ``` ```diff CONST CONST_KW "const" WHITESPACE " " UNDERSCORE "_" EQ "=" PATH_EXPR PATH PATH PATH_SEGMENT NAME_REF IDENT "x" COLON2 "::" - PATH_SEGMENT - ERROR - L_PAREN "(" -ERROR - R_PAREN ")" + ARG_LIST + L_PAREN "(" + R_PAREN ")" ``` --- .../hir-def/src/macro_expansion_tests/mbe.rs | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 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 0a2d0bf12e7d4..fee7275b06311 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 @@ -1737,9 +1737,6 @@ macro_rules! m { ($k:expr) => { fn f() { K::$k; } } } /* 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 */ fn f() { K::(C("0")); } @@ -1754,32 +1751,30 @@ fn f() { // BLOCK_EXPR@5..19 // STMT_LIST@5..19 // L_CURLY@5..6 "{" -// EXPR_STMT@6..10 -// PATH_EXPR@6..10 -// PATH@6..10 -// PATH@6..7 -// PATH_SEGMENT@6..7 -// NAME_REF@6..7 -// IDENT@6..7 "K" -// COLON2@7..9 "::" -// PATH_SEGMENT@9..10 -// ERROR@9..10 -// L_PAREN@9..10 "(" -// EXPR_STMT@10..16 -// CALL_EXPR@10..16 -// PATH_EXPR@10..11 -// PATH@10..11 -// PATH_SEGMENT@10..11 -// NAME_REF@10..11 -// IDENT@10..11 "C" -// ARG_LIST@11..16 -// L_PAREN@11..12 "(" -// LITERAL@12..15 -// STRING@12..15 "\"0\"" -// R_PAREN@15..16 ")" -// ERROR@16..17 -// R_PAREN@16..17 ")" -// SEMICOLON@17..18 ";" +// EXPR_STMT@6..18 +// CALL_EXPR@6..17 +// PATH_EXPR@6..9 +// PATH@6..9 +// PATH@6..7 +// PATH_SEGMENT@6..7 +// NAME_REF@6..7 +// IDENT@6..7 "K" +// COLON2@7..9 "::" +// ARG_LIST@9..17 +// L_PAREN@9..10 "(" +// CALL_EXPR@10..16 +// PATH_EXPR@10..11 +// PATH@10..11 +// PATH_SEGMENT@10..11 +// NAME_REF@10..11 +// IDENT@10..11 "C" +// ARG_LIST@11..16 +// L_PAREN@11..12 "(" +// LITERAL@12..15 +// STRING@12..15 "\"0\"" +// R_PAREN@15..16 ")" +// R_PAREN@16..17 ")" +// SEMICOLON@17..18 ";" // R_CURLY@18..19 "}" "#]], From f7b5e44004edb4743b1bd7715558f89b528db33b Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 20 Oct 2026 15:50:48 +0800 Subject: [PATCH 09/27] Bump smol_str to 0.3.7 --- src/tools/rust-analyzer/Cargo.lock | 20 +++++++++---------- .../rust-analyzer/lib/smol_str/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index aaf1c30505ac8..3cd4e6af6acda 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2649,25 +2649,25 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smol_str" version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" dependencies = [ - "arbitrary", "borsh", - "criterion", - "proptest", - "rand", - "serde", "serde_core", - "serde_json", ] [[package]] name = "smol_str" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" +version = "0.3.7" dependencies = [ + "arbitrary", "borsh", + "criterion", + "proptest", + "rand", + "serde", "serde_core", + "serde_json", ] [[package]] @@ -2759,7 +2759,7 @@ dependencies = [ "rustc-literal-escaper", "rustc_apfloat", "smallvec", - "smol_str 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smol_str 0.3.6", "stdx", "test-utils", "tracing", diff --git a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml index 719462bc9a5d9..a42940fad44e7 100644 --- a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml +++ b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smol_str" -version = "0.3.6" +version = "0.3.7" description = "small-string optimized string type with O(1) clone" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/smol_str" From 0798f0e5a99fd5e92fc8d6ddefc69b95c4bba639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 20 Oct 2026 15:37:20 +0200 Subject: [PATCH 10/27] Use `publish = false` for the `toolchain` crate --- src/tools/rust-analyzer/crates/toolchain/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml index 8ba63ae868655..fbe5febc01ccc 100644 --- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml +++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml @@ -3,7 +3,7 @@ name = "toolchain" version = "0.0.0" repository.workspace = true description = "Discovery of `cargo` & `rustc` executables for rust-analyzer." - +publish = false authors.workspace = true edition.workspace = true license.workspace = true From 9ff528a3d5fd40a26a491158ee21dab940123ab2 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 20 Oct 2026 21:46:19 +0800 Subject: [PATCH 11/27] Split `T!['(']` to sub recovery set --- .../crates/parser/src/grammar/expressions/atom.rs | 2 +- src/tools/rust-analyzer/crates/parser/src/grammar/items.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 d4147f38b2aaf..fbcd5d672ebc1 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 @@ -68,7 +68,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = ])); pub(in crate::grammar) const EXPR_RECOVERY_SET: TokenSet = - TokenSet::new(&[T!['}'], T![')'], T![']'], T![,]]); + TokenSet::new(&[T!['('], T!['}'], T![')'], T![']'], T![,]]); pub(super) fn atom_expr( p: &mut Parser<'_>, 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 c563a44612b0f..593b7dbafd236 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -43,8 +43,8 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![use], T![macro], T![;], - T!['('], ]); +const ITEM_PAREN_RECOVERY_SET: TokenSet = ITEM_RECOVERY_SET.union(TokenSet::new(&[T!['(']])); pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool, is_in_extern: bool) { let m = p.start(); @@ -435,7 +435,7 @@ fn fn_(p: &mut Parser<'_>, m: Marker) { // test_err function_missing_name // fn () {} - name_r(p, ITEM_RECOVERY_SET); + name_r(p, ITEM_PAREN_RECOVERY_SET); // test function_type_params // fn foo(){} generic_params::opt_generic_param_list(p); From 6ddf12055c1394700906fb56e6c4f2211b37e634 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Tue, 20 Oct 2026 22:01:34 +0800 Subject: [PATCH 12/27] Update smolstr CHANGELOG and publish --- src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md index 6327275d07dcb..1980f484c39b9 100644 --- a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md +++ b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.3.7 - 2026-10-20 + +- Add `SmolStr::INLINE_CAP` +- Add some missing methods and trait implements for `SmolStr` and `SmolStrBuilder` +- Fix incorrect `eq` implements for `SmolStrBuilder` +- Fix borsh deserialization off-by-one for inline threshold + ## 0.3.6 - 2026-03-04 - Fix the `borsh` feature. From 1babbb65793f0a0421687bf6488dfdacb56d077a Mon Sep 17 00:00:00 2001 From: jgespiga Date: Sun, 18 Oct 2026 20:26:37 +0200 Subject: [PATCH 13/27] fix: emit E0029 for range patterns with inferred invalid types --- .../crates/hir-ty/src/infer/pat.rs | 2 +- .../src/handlers/invalid_range_pat_type.rs | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 24617c512966d..96d9404250030 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -868,7 +868,7 @@ impl<'db> InferenceContext<'db> { expected, ); if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { - // FIXME: Emit an error. + self.push_diagnostic(InferenceDiagnostic::InvalidRangePatType { pat }); return self.types.types.error; } ty diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs index 465f59559d294..d1ddd114cb4c2 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_range_pat_type.rs @@ -49,6 +49,68 @@ fn f(x: u8, c: char) { _ => {} } } +"#, + ); + } + + #[test] + fn inferred_invalid_type_range_patterns() { + check_diagnostics( + r#" +trait Zero { + const ZERO: Self; +} + +struct S; + +impl Zero for S { + const ZERO: Self = S; +} + +fn f() { + match S { + Zero::ZERO..=Zero::ZERO => {} + //^^^^^^^^^^^^^^^^^^^^^^^ error: only `char` and numeric types are allowed in range patterns + Zero::ZERO.. => {} + //^^^^^^^^^^^^ error: only `char` and numeric types are allowed in range patterns + ..Zero::ZERO => {} + //^^^^^^^^^^^^ error: only `char` and numeric types are allowed in range patterns + _ => {} + } +} +"#, + ); + } + + #[test] + fn inferred_valid_type_range_patterns() { + check_diagnostics( + r#" +trait Zero { + const ZERO: Self; +} + +impl Zero for u8 { + const ZERO: Self = 0; +} + +impl Zero for char { + const ZERO: Self = '0'; +} + +fn f(x: u8) { + match x { + Zero::ZERO..=Zero::ZERO => {} + _ => {} + } +} + +fn g(x: char) { + match x { + Zero::ZERO..=Zero::ZERO => {} + _ => {} + } +} "#, ); } From abf49d4422f526177f96edc8f6720e3d40f91c3d Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 21 Oct 2026 11:36:37 +0800 Subject: [PATCH 14/27] fix: use absolute path in format_smolstr About macro hygiene, avoid error when user defined a `format_args!` in scope --- src/tools/rust-analyzer/lib/smol_str/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/lib/smol_str/src/lib.rs b/src/tools/rust-analyzer/lib/smol_str/src/lib.rs index c592cb25d2373..63e3d42e11b37 100644 --- a/src/tools/rust-analyzer/lib/smol_str/src/lib.rs +++ b/src/tools/rust-analyzer/lib/smol_str/src/lib.rs @@ -947,7 +947,7 @@ mod private { macro_rules! format_smolstr { ($($tt:tt)*) => {{ let mut w = $crate::SmolStrBuilder::new(); - ::core::fmt::Write::write_fmt(&mut w, format_args!($($tt)*)).expect("a formatting trait implementation returned an error"); + ::core::fmt::Write::write_fmt(&mut w, ::core::format_args!($($tt)*)).expect("a formatting trait implementation returned an error"); w.finish() }}; } From 869e9878f925af31dca2a825ca3b0ecb6bfb2936 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 21 Oct 2026 04:58:16 +0000 Subject: [PATCH 15/27] minor: Fix fuzz CI --- src/tools/rust-analyzer/Cargo.lock | 2 +- src/tools/rust-analyzer/crates/hir-def/Cargo.toml | 7 ------- src/tools/rust-analyzer/crates/syntax/Cargo.toml | 7 +++++++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 3cd4e6af6acda..89c76b20feee3 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -873,7 +873,6 @@ dependencies = [ "tracing", "triomphe", "tt", - "unicode-ident", ] [[package]] @@ -2764,6 +2763,7 @@ dependencies = [ "test-utils", "tracing", "triomphe", + "unicode-ident", ] [[package]] diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index eb2d47b7b8261..eb1e774b8f41b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -9,9 +9,6 @@ edition.workspace = true license.workspace = true rust-version.workspace = true -[package.metadata.cargo-machete] -ignored = ["unicode-ident"] - [lib] doctest = false @@ -47,10 +44,6 @@ span.workspace = true thin-vec.workspace = true syntax-bridge.workspace = true -# This is a transitive dep, but we need to specify this -# for the workspace-wide pinning -unicode-ident.workspace = true - [dev-dependencies] expect-test.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index a9df1acdae9a7..b2ff2c08fb9a8 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -9,6 +9,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[package.metadata.cargo-machete] +ignored = ["unicode-ident"] + [lib] doctest = false @@ -27,6 +30,10 @@ smallvec.workspace = true parser.workspace = true stdx.workspace = true +# This is a transitive dep, but we need to specify this +# for the workspace-wide pinning +unicode-ident.workspace = true + [dev-dependencies] rayon.workspace = true expect-test = "1.5.1" From cb04287790196bd24b4ae354f4405cf020ab1d3e Mon Sep 17 00:00:00 2001 From: Senthilnathan Date: Wed, 21 Oct 2026 13:01:57 +0530 Subject: [PATCH 16/27] Use a NoSpan marker for region constraints without spans `LeafRegionConstraint`, `Or`, `And`, and `RegionConstraint` defaulted their span parameter to `()`, which reads as an empty tuple rather than as "this constraint has no span". Add a `NoSpan` unit struct and use it as the default, and add a `ConstraintSpan` trait implemented for `NoSpan` and `rustc_span::Span`. This replaces the repeated `Clone + Debug + Eq + Hash` bounds on the constructors and span conversion helpers. No behavior change. --- .../eval_ctxt/solver_region_constraints.rs | 10 +- .../rustc_next_trait_solver/src/solve/mod.rs | 6 +- compiler/rustc_type_ir/src/macros.rs | 1 + .../rustc_type_ir/src/region_constraint.rs | 114 ++++++++++-------- 4 files changed, 72 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs index 8a4d3fba99a39..84fb63d6311ac 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs @@ -7,7 +7,7 @@ use rustc_type_ir::outlives::{Component, push_outlives_components}; #[cfg(not(feature = "nightly"))] use rustc_type_ir::region_constraint::TransitiveRelationBuilder; use rustc_type_ir::region_constraint::{ - And, Assumptions, LeafRegionConstraint, Or, eagerly_handle_placeholders_in_universe, + And, Assumptions, LeafRegionConstraint, NoSpan, Or, eagerly_handle_placeholders_in_universe, }; use rustc_type_ir::{ AliasTy, Binder, ClauseKind, Const, InferCtxtLike, Interner, Region, TypeVisitable, @@ -168,9 +168,9 @@ where use Component::*; use LeafRegionConstraint::*; match c { - Region(c_r) => Or::new_leaf(RegionOutlives(*c_r, r, ())), + Region(c_r) => Or::new_leaf(RegionOutlives(*c_r, r, NoSpan)), Placeholder(p) => { - Or::new_leaf(PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r, ())) + Or::new_leaf(PlaceholderTyOutlives(Ty::new_placeholder(self.cx(), *p), r, NoSpan)) } Alias(_, alias) => self.destructure_alias_outlives(*alias, r), UnresolvedInferenceVariable(_) => { @@ -194,11 +194,11 @@ where let item_bounds = rustc_type_ir::outlives::declared_bounds_from_definition(self.cx(), alias) - .map(|bound| And::new([RegionOutlives(bound, r, ())])); + .map(|bound| And::new([RegionOutlives(bound, r, NoSpan)])); let item_bound_outlives = Or::new(item_bounds); let where_clause_outlives = - Or::new_leaf(AliasTyOutlivesViaEnv(Binder::dummy((alias, r)), ())); + Or::new_leaf(AliasTyOutlivesViaEnv(Binder::dummy((alias, r)), NoSpan)); let mut components = Default::default(); rustc_type_ir::outlives::compute_alias_components_recursive( diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 3da905741c03b..d944ae765c4f4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -155,10 +155,12 @@ where let ty::OutlivesClause(a, b) = goal.predicate; if self.cx().assumptions_on_binders() { - use rustc_type_ir::region_constraint::{LeafRegionConstraint, RegionConstraint}; + use rustc_type_ir::region_constraint::{ + LeafRegionConstraint, NoSpan, RegionConstraint, + }; let constraint = - RegionConstraint::new_leaf(LeafRegionConstraint::RegionOutlives(a, b, ())); + RegionConstraint::new_leaf(LeafRegionConstraint::RegionOutlives(a, b, NoSpan)); self.register_solver_region_constraint(constraint); } else { self.register_region_outlives(a, b, VisibleForLeakCheck::Yes); diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 096f43f81e608..2fdbdec7ceb81 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -75,6 +75,7 @@ TrivialTypeTraversalImpls! { crate::UintTy, crate::UniverseIndex, crate::Variance, + crate::region_constraint::NoSpan, crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 257d0a776403e..15ab6f74ca88e 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -168,10 +168,28 @@ impl Assumptions { } } +/// The span stored in a [`RegionConstraint`] and friends. +/// +/// Constraints are created with spans during type checking, but are also stored +/// without any span, e.g. in query responses, in which case [`NoSpan`] is used. +/// This trait exists so that code which is generic over the span only needs a +/// single bound instead of repeating all of the supertrait bounds. +pub trait ConstraintSpan: Clone + std::fmt::Debug + Eq + std::hash::Hash {} + +/// Placeholder for constraints which do not carry a span, see [`ConstraintSpan`]. +#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] +pub struct NoSpan; + +impl ConstraintSpan for NoSpan {} + +#[cfg(feature = "nightly")] +impl ConstraintSpan for rustc_span::Span {} + #[derive_where(Clone, Hash, PartialEq, Eq; I: Interner, S)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(StableHash_NoContext))] -pub enum LeafRegionConstraint { +pub enum LeafRegionConstraint { Ambiguity(S), RegionOutlives(Region, Region, S), /// Requirement that a (potentially higher ranked) alias outlives some (potentially higher ranked) @@ -224,32 +242,31 @@ impl std::fmt::Debug for LeafRegionConstraint { } impl LeafRegionConstraint { - pub fn with_span( - self, - span: S, - ) -> LeafRegionConstraint { + pub fn with_span(self, span: S) -> LeafRegionConstraint { use LeafRegionConstraint::*; match self { - Ambiguity(()) => Ambiguity(span), - RegionOutlives(r1, r2, ()) => RegionOutlives(r1, r2, span), - AliasTyOutlivesViaEnv(bound_outlives, ()) => { + Ambiguity(NoSpan) => Ambiguity(span), + RegionOutlives(r1, r2, NoSpan) => RegionOutlives(r1, r2, span), + AliasTyOutlivesViaEnv(bound_outlives, NoSpan) => { AliasTyOutlivesViaEnv(bound_outlives, span) } - PlaceholderTyOutlives(ty, r, ()) => PlaceholderTyOutlives(ty, r, span), + PlaceholderTyOutlives(ty, r, NoSpan) => PlaceholderTyOutlives(ty, r, span), } } } -impl LeafRegionConstraint { +impl LeafRegionConstraint { pub fn without_span(self) -> LeafRegionConstraint { use LeafRegionConstraint::*; match self { - Ambiguity(_) => Ambiguity(()), - RegionOutlives(r1, r2, _) => RegionOutlives(r1, r2, ()), - AliasTyOutlivesViaEnv(bound_outlives, _) => AliasTyOutlivesViaEnv(bound_outlives, ()), - PlaceholderTyOutlives(ty, r, _) => PlaceholderTyOutlives(ty, r, ()), + Ambiguity(_) => Ambiguity(NoSpan), + RegionOutlives(r1, r2, _) => RegionOutlives(r1, r2, NoSpan), + AliasTyOutlivesViaEnv(bound_outlives, _) => { + AliasTyOutlivesViaEnv(bound_outlives, NoSpan) + } + PlaceholderTyOutlives(ty, r, _) => PlaceholderTyOutlives(ty, r, NoSpan), } } @@ -277,16 +294,13 @@ impl LeafRegionC /// than proving the subset, so it can never be the candidate which makes the OR hold. E.g. /// `OR(AND('a: 'b), AND('a: 'b, 'b: 'c))` really ought to just be `OR(AND('a: 'b))`. Only keeping /// an empty AND is the degenerate case of that rule. -pub struct Or(pub SmallVec<[And; 1]>); +pub struct Or(pub SmallVec<[And; 1]>); impl Or { - pub fn with_spans( - self, - span: S, - ) -> Or { + pub fn with_spans(self, span: S) -> Or { Or(self.0.into_iter().map(|and| and.with_spans(span.clone())).collect()) } } -impl Or { +impl Or { pub fn new_true() -> Self { Self(SmallVec::from_buf([And::new_true()])) } @@ -385,18 +399,15 @@ impl std::fmt::Debug for Or { /// An AND of leaf constraints. Always in "canonical form", meaning: /// - No leaf constraints are present twice in this AND /// - No leaf constraint is trivially true, i.e. a reflexive `'a: 'a` -pub struct And( +pub struct And( pub SmallVec<[LeafRegionConstraint; 1]>, ); impl And { - pub fn with_spans( - self, - span: S, - ) -> And { + pub fn with_spans(self, span: S) -> And { And(self.0.into_iter().map(|leaf| leaf.with_span(span.clone())).collect()) } } -impl And { +impl And { pub fn new_true() -> Self { Self(SmallVec::new()) } @@ -466,23 +477,20 @@ impl std::fmt::Debug for And { /// /// This should be thought of as an AND consisting of a set of LEAF constraints as well /// as a single OR constraint. -pub struct RegionConstraint { +pub struct RegionConstraint { pub and_constraint: And, pub or_constraint: Or, } impl RegionConstraint { - pub fn with_spans( - self, - span: S, - ) -> RegionConstraint { + pub fn with_spans(self, span: S) -> RegionConstraint { RegionConstraint { and_constraint: self.and_constraint.with_spans(span.clone()), or_constraint: self.or_constraint.with_spans(span.clone()), } } } -impl RegionConstraint { +impl RegionConstraint { pub fn new_from_or(or: Or) -> Self { let Some(fst) = or.0.get(0).clone() else { return RegionConstraint::new_false(); @@ -666,10 +674,10 @@ fn compute_new_region_constraints, I: Interne and: &And| { for c in &and.0 { match c { - Ambiguity(()) | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { + Ambiguity(NoSpan) | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { constraints.push(c.clone()) } - RegionOutlives(r1, r2, ()) => { + RegionOutlives(r1, r2, NoSpan) => { regions.insert(*r1); regions.insert(*r2); builder.add(*r2, *r1); @@ -711,7 +719,7 @@ fn compute_new_region_constraints, I: Interne }; if is_placeholder_like(r) && is_placeholder_like(ub) { - constraints.push(RegionOutlives(ub, r, ())); + constraints.push(RegionOutlives(ub, r, NoSpan)); } } } @@ -770,11 +778,11 @@ fn pull_region_outlives_constraints_out_of_universe< let mut pulled_constraints = Vec::new(); for c in and.0 { match c { - Ambiguity(()) | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { + Ambiguity(NoSpan) | PlaceholderTyOutlives(..) | AliasTyOutlivesViaEnv(..) => { assert!(max_universe(infcx, c.clone()) < u); pulled_constraints.push(Or::new_leaf(c.clone())); } - RegionOutlives(region_1, region_2, ()) => { + RegionOutlives(region_1, region_2, NoSpan) => { let region_1_u = max_universe(infcx, region_1); let region_2_u = max_universe(infcx, region_2); @@ -805,7 +813,7 @@ fn pull_region_outlives_constraints_out_of_universe< // As long as any region outlived by `region_1` outlives any region region which // `region_2` outlives, we know that `region_1: region_2` holds. In other words, // there exists some set of 4 regions for which `'r1: 'i1` `'i1: 'i2` `'i2: 'r2` - candidates.push(RegionOutlives(ub, lb, ())); + candidates.push(RegionOutlives(ub, lb, NoSpan)); } } @@ -834,7 +842,7 @@ fn pull_region_outlives_constraints_out_of_universe< pub fn destructure_type_outlives_constraints_in_root< Infcx: InferCtxtLike, I: Interner, - S: Clone + std::fmt::Debug + Eq + std::hash::Hash, + S: ConstraintSpan, >( infcx: &Infcx, constraint: RegionConstraint, @@ -920,11 +928,13 @@ fn rewrite_type_outlives_constraints_in_universe_for_eager_placeholder_handling< let mut rewritten_constraints = Vec::new(); for c in and.0 { match c { - Ambiguity(()) | RegionOutlives(..) => rewritten_constraints.push(Or::new_leaf(c)), - PlaceholderTyOutlives(ty, region, ()) => { + Ambiguity(NoSpan) | RegionOutlives(..) => { + rewritten_constraints.push(Or::new_leaf(c)) + } + PlaceholderTyOutlives(ty, region, NoSpan) => { rewritten_constraints.push(rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder_handling(infcx, ty, region, u, assumptions)); } - AliasTyOutlivesViaEnv(bound_outlives, ()) => { + AliasTyOutlivesViaEnv(bound_outlives, NoSpan) => { rewritten_constraints.push(rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handling(infcx, bound_outlives, u, assumptions)); } } @@ -959,7 +969,7 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder let region_u = max_universe(infcx, region); if region_u != u && ty_u != u { - return Or::new_leaf(PlaceholderTyOutlives(ty, region, ())); + return Or::new_leaf(PlaceholderTyOutlives(ty, region, NoSpan)); } let mut candidates = vec![]; @@ -968,7 +978,7 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder // smaller universe candidates.extend( regions_outlived_by_placeholder(ty, assumptions, infcx.cx()) - .map(move |assumption_r| RegionOutlives(assumption_r, region, ())), + .map(move |assumption_r| RegionOutlives(assumption_r, region, NoSpan)), ); // We can express `!T: 'region` as `!T: 'r` where `'r: 'region`. This is only necessary @@ -978,7 +988,7 @@ fn rewrite_placeholder_ty_outlives_constraints_in_universe_for_eager_placeholder candidates.extend( regions_outliving::(region, assumptions, infcx.cx()) .filter(|r| max_universe(infcx, *r) < u) - .map(|r| PlaceholderTyOutlives(ty, r, ())), + .map(|r| PlaceholderTyOutlives(ty, r, NoSpan)), ); } @@ -998,7 +1008,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl use LeafRegionConstraint::*; if max_universe(infcx, bound_outlives) != u { - return Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, ())); + return Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, NoSpan)); } let mut candidates = Vec::new(); @@ -1040,11 +1050,11 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl // a placeholder type in `u`, so this type-outlives constraint cannot be // handled by the region-outlives-only eager placeholder machinery. if max_universe(infcx, bound_outlives) == u { - return Or::new_ambig(()); + return Or::new_ambig(NoSpan); } debug!("higher ranked candidate: {bound_outlives:?}"); - Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, ())) + Or::new_leaf(AliasTyOutlivesViaEnv(bound_outlives, NoSpan)) }; // We elaborate something like `Alias<'a_u2>: 'b_u2` into alias outlives involving each @@ -1076,7 +1086,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl // let's be conservative and not let alias outlives' cause NoSolution // in coherence match infcx.typing_mode_raw() { - TypingMode::Coherence => candidates.push(Or::new_ambig(())), + TypingMode::Coherence => candidates.push(Or::new_ambig(NoSpan)), TypingMode::Typeck { .. } | TypingMode::Reflection | TypingMode::ErasedNotCoherence { .. } @@ -1211,7 +1221,7 @@ fn alias_outlives_candidates_from_assumptions let mut relation = HigherRankedAliasMatcher { infcx, - region_constraints: vec![LeafRegionConstraint::RegionOutlives(r2, r, ())], + region_constraints: vec![LeafRegionConstraint::RegionOutlives(r2, r, NoSpan)], }; // FIXME(#155345): Both sides should be rigid in the future. @@ -1283,8 +1293,8 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeRelation fn regions(&mut self, a: Region, b: Region) -> RelateResult> { if a != b { - self.region_constraints.push(LeafRegionConstraint::RegionOutlives(a, b, ())); - self.region_constraints.push(LeafRegionConstraint::RegionOutlives(b, a, ())); + self.region_constraints.push(LeafRegionConstraint::RegionOutlives(a, b, NoSpan)); + self.region_constraints.push(LeafRegionConstraint::RegionOutlives(b, a, NoSpan)); } Ok(a) } From a8227a058de23c41c566ea47606c955eac913c7b Mon Sep 17 00:00:00 2001 From: Angad Tendulkar Date: Wed, 21 Oct 2026 17:41:34 -0400 Subject: [PATCH 17/27] Use the rustc-src lockfile when fetching metadata for the rustc workspace The rustc-dev component ships the compiler sources with `rustc-src/rust/compiler/rustc/Cargo.toml` as the entry manifest, but without the workspace root manifest next to the lockfile at `rustc-src/rust/Cargo.lock`. FetchMetadata only looked for a lockfile right next to the manifest, so the rustc workspace's metadata fetch always ran with `--locked` and no lockfile. cargo then fails, and rust-analyzer silently degrades to `--no-deps` metadata, dropping rustc_middle and friends from the crate graph entirely. For the rustc workspace only, copy the lockfile from the root of the rust source tree instead. Co-Authored-By: Claude Opus 5.5 --- .../project-model/src/cargo_workspace.rs | 29 +++++++++++++++---- .../crates/project-model/src/workspace.rs | 12 ++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 9d2588380c22c..3c978bd91f868 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -332,12 +332,21 @@ pub struct CargoMetadataConfig { /// Extra env vars to set when invoking the cargo command pub extra_env: FxHashMap>, /// What kind of metadata are we fetching: workspace, rustc, or sysroot. - pub kind: &'static str, + pub kind: CargoMetadataKind, /// The toolchain version, if known. /// Used to conditionally enable unstable cargo features. pub toolchain_version: Option, } +#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] +pub enum CargoMetadataKind { + #[default] + Workspace, + DetachedFile, + Rustc, + Sysroot, +} + // Deserialize helper for the cargo metadata #[derive(Deserialize, Default)] struct PackageMetadata { @@ -637,7 +646,7 @@ pub(crate) struct FetchMetadata { manifest_path: ManifestPath, lockfile_copy: Option, #[expect(dead_code)] - kind: &'static str, + kind: CargoMetadataKind, no_deps: bool, no_deps_result: anyhow::Result, other_options: Vec, @@ -704,10 +713,18 @@ impl FetchMetadata { if cargo_toml.is_rust_manifest() { other_options.push("-Zscript".to_owned()); } else if let Some(v) = config.toolchain_version.as_ref() { - lockfile_copy = make_lockfile_copy( - v, - &<_ as AsRef>::as_ref(cargo_toml).with_extension("lock"), - ); + let manifest: &Utf8Path = cargo_toml.as_ref(); + let lockfile_path = if config.kind == CargoMetadataKind::Rustc { + // The `rustc-dev` component ships `rustc-src/rust/compiler/rustc/Cargo.toml` + // without the workspace root manifest, so the lockfile at + // `rustc-src/rust/Cargo.lock` is neither next to the manifest nor discoverable + // by cargo. Without a copy of it, `cargo metadata --locked` fails and we degrade + // to `--no-deps` metadata, losing all rustc crates (e.g. `rustc_middle`). + manifest.ancestors().nth(3).map(|dir| dir.join("Cargo.lock")) + } else { + Some(manifest.with_extension("lock")) + }; + lockfile_copy = lockfile_path.and_then(|path| make_lockfile_copy(v, &path)); } if !config.targets.is_empty() { 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 0b2a023ba2a52..f54eccc384b8f 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -28,7 +28,9 @@ use crate::{ WorkspaceBuildScripts, build_dependencies::{BuildScriptOutput, ProcMacroDylibPath}, cargo_config_file::CargoConfigFile, - cargo_workspace::{CargoMetadataConfig, DepKind, FetchMetadata, PackageData, RustLibSource}, + cargo_workspace::{ + CargoMetadataConfig, CargoMetadataKind, DepKind, FetchMetadata, PackageData, RustLibSource, + }, env::{cargo_config_env, inject_cargo_env, inject_cargo_package_env, inject_rustc_tool_env}, project_json::{Crate, CrateArrayIdx}, sysroot::RustLibSrcWorkspace, @@ -296,7 +298,7 @@ impl ProjectWorkspace { config_path: config_path.clone(), extra_env: extra_env.clone(), toolchain_version: toolchain.clone(), - kind: "workspace", + kind: CargoMetadataKind::Workspace, }, &sysroot, *no_deps, @@ -357,7 +359,7 @@ impl ProjectWorkspace { config_path: config_path.clone(), extra_env: extra_env.clone(), toolchain_version: toolchain.clone(), - kind: "rustc-dev" + kind: CargoMetadataKind::Rustc }, &sysroot, *no_deps, @@ -602,7 +604,7 @@ impl ProjectWorkspace { config_path: config.config_path.clone(), extra_env: config.extra_env.clone(), toolchain_version: toolchain.clone(), - kind: "detached-file", + kind: CargoMetadataKind::DetachedFile, }, &sysroot, config.no_deps, @@ -1999,6 +2001,6 @@ fn sysroot_metadata_config( // extra_args. extra_env: config.extra_env.clone(), toolchain_version, - kind: "sysroot", + kind: CargoMetadataKind::Sysroot, } } From f802ea3dd21ada7025f98601215100a270196c97 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Thu, 22 Oct 2026 11:51:16 +0800 Subject: [PATCH 18/27] Use base_db::all_crates Co-authored-by: Chayim Refael Friedman --- .../ide-completion/src/completions/mod_.rs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index ac38460dc1c92..b0d34bfc44ecb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -44,12 +44,15 @@ pub(crate) fn complete_mod( current_module.definition_source_file_id(ctx.db).original_file(ctx.db).file_id(ctx.db); let source_root_id = ctx.db.file_source_root(module_definition_file).source_root_id(ctx.db); let source_root = ctx.db.source_root(source_root_id).source_root(ctx.db); - let root_path = source_root.path_for_file(&ctx.krate.root_file(ctx.db))?; + let crate_roots = base_db::all_crates(ctx.db) + .iter() + .map(|krate| krate.root_file_id(ctx.db).file_id(ctx.db)) + .collect::>(); let directory_to_look_for_submodules = directory_to_look_for_submodules( current_module, ctx.db, - root_path, + crate_roots.contains(&module_definition_file), source_root.path_for_file(&module_definition_file)?, )?; @@ -74,7 +77,7 @@ pub(crate) fn complete_mod( let submodule_path = source_root.path_for_file(&submodule_file)?; let directory_with_submodule = submodule_path.parent()?; let (name, ext) = submodule_path.name_and_extension()?; - if ext != Some("rs") || is_source_root(root_path, submodule_path) { + if ext != Some("rs") || crate_roots.contains(&submodule_file) { return None; } match name { @@ -116,7 +119,7 @@ pub(crate) fn complete_mod( fn directory_to_look_for_submodules( module: Module, db: &RootDatabase, - root_path: &VfsPath, + is_root: bool, module_file_path: &VfsPath, ) -> Option { let directory_with_module_path = module_file_path.parent()?; @@ -126,7 +129,7 @@ fn directory_to_look_for_submodules( } let base_directory = match name { "mod" => Some(directory_with_module_path), - _ if is_source_root(root_path, module_file_path) => Some(directory_with_module_path), + _ if is_root => Some(directory_with_module_path), regular_rust_file_name => { if matches!( ( @@ -164,13 +167,6 @@ fn module_chain_to_containing_module_file( path } -// FIXME: It doesn't seem to support custom crate roots -fn is_source_root(root_path: &VfsPath, path: &VfsPath) -> bool { - let Some(root_dir) = root_path.parent() else { return false }; - let Some((name, _)) = path.name_and_extension() else { return false }; - path.parent() == Some(root_dir) && matches!(name, "main" | "lib") -} - #[cfg(test)] mod tests { use expect_test::expect; From 839288e8d6a6a62a9423b01eaafd582f35f3b96e Mon Sep 17 00:00:00 2001 From: TechnoPorg Date: Tue, 6 Oct 2026 14:42:36 -0400 Subject: [PATCH 19/27] Implement an automated sync for target feature implications --- .../{gen-lints.yml => update-generated.yml} | 13 +- .../crates/hir-ty/src/target_feature.rs | 988 +----------------- .../hir-ty/src/target_feature/generated.rs | 961 +++++++++++++++++ src/tools/rust-analyzer/xtask/src/codegen.rs | 27 +- .../rust-analyzer/xtask/src/codegen/lints.rs | 20 +- .../xtask/src/codegen/target_features.rs | 110 ++ src/tools/rust-analyzer/xtask/src/flags.rs | 3 + 7 files changed, 1113 insertions(+), 1009 deletions(-) rename src/tools/rust-analyzer/.github/workflows/{gen-lints.yml => update-generated.yml} (76%) create mode 100644 src/tools/rust-analyzer/crates/hir-ty/src/target_feature/generated.rs create mode 100644 src/tools/rust-analyzer/xtask/src/codegen/target_features.rs diff --git a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml b/src/tools/rust-analyzer/.github/workflows/update-generated.yml similarity index 76% rename from src/tools/rust-analyzer/.github/workflows/gen-lints.yml rename to src/tools/rust-analyzer/.github/workflows/update-generated.yml index 4fd7bb6200622..611d7d40bc6a2 100644 --- a/src/tools/rust-analyzer/.github/workflows/gen-lints.yml +++ b/src/tools/rust-analyzer/.github/workflows/update-generated.yml @@ -1,4 +1,4 @@ -name: Generate lints and feature flags +name: Update generated code on: workflow_dispatch: @@ -26,6 +26,9 @@ jobs: - name: Generate lints/feature flags run: cargo codegen lint-definitions + - name: Generate target feature implications + run: cargo codegen target-features + - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0 id: app-token with: @@ -36,10 +39,10 @@ jobs: uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0 with: token: ${{ steps.app-token.outputs.token }} - commit-message: "internal: update generated lints" - branch: "ci/gen-lints" + commit-message: "internal: update generated lints and target features" + branch: "ci/gen-sync" delete-branch: true sign-commits: true - title: "Update generated lints" - body: "Weekly lint updates for `crates/ide-db/src/generated/lints.rs`." + title: "Update generated lints and target features" + body: "Weekly lint updates for `crates/ide-db/src/generated/lints.rs` and `crates/hir-ty/src/generated/target_features.rs`." labels: "A-infra" diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs index 92ffa472548da..8206a1f8c436c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature.rs @@ -9,6 +9,9 @@ use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; use crate::db::HirDatabase; +use generated::TARGET_FEATURE_IMPLICATIONS_RAW; + +mod generated; #[derive(Debug, Default, Clone)] pub struct TargetFeatures<'db> { @@ -68,988 +71,3 @@ static TARGET_FEATURE_IMPLICATIONS: LazyLock>> = result.shrink_to_fit(); result }); - -#[expect(dead_code, reason = "stubs for rustc_target")] -enum Stability { - Stable, - Unstable(()), - InternalOnly { reason: &'static str, hard_error: bool }, -} -use Stability::*; - -type ImpliedFeatures = &'static [&'static str]; - -// spellchecker:off - -#[expect(non_upper_case_globals, reason = "stubs for rustc_target")] -mod sym { - // ARM - pub(super) const arm_target_feature: () = (); - // AArch64 - pub(super) const aarch64_unstable_target_feature: () = (); - pub(super) const aarch64_ver_target_feature: () = (); - // x86 - pub(super) const x86_amx_intrinsics: () = (); - pub(super) const apx_target_feature: () = (); - pub(super) const avx10_target_feature: () = (); - pub(super) const clflushopt_target_feature: () = (); - pub(super) const fma4_target_feature: () = (); - pub(super) const ermsb_target_feature: () = (); - pub(super) const lahfsahf_target_feature: () = (); - pub(super) const movrs_target_feature: () = (); - pub(super) const prfchw_target_feature: () = (); - pub(super) const rtm_target_feature: () = (); - pub(super) const x87_target_feature: () = (); - pub(super) const xop_target_feature: () = (); - pub(super) const movdir64b_target_feature: () = (); - pub(super) const movdiri_target_feature: () = (); - // Hexagon - pub(super) const hexagon_target_feature: () = (); - // PowerPC - pub(super) const powerpc_target_feature: () = (); - // MIPS - pub(super) const mips_target_feature: () = (); - // NVPTX - pub(super) const nvptx_target_feature: () = (); - // RISC-V - pub(super) const riscv_target_feature: () = (); - // WASM - pub(super) const wasm_target_feature: () = (); - // BPF - pub(super) const bpf_target_feature: () = (); - // CSKY - pub(super) const csky_target_feature: () = (); - // LoongArch - pub(super) const loongarch_target_feature: () = (); - // s390x - pub(super) const s390x_target_feature: () = (); - // SPARC - pub(super) const sparc_target_feature: () = (); - // m68k - pub(super) const m68k_target_feature: () = (); - // AVR - pub(super) const avr_target_feature: () = (); - // Xtensa - pub(super) const xtensa_target_feature: () = (); -} - -// The following code is copied verbatim from compiler/rustc_target/src/target_features.rs. - -static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("aclass", Unstable(sym::arm_target_feature), &[]), - ("acquire-release", Unstable(sym::arm_target_feature), &[]), - ("aes", Unstable(sym::arm_target_feature), &["neon"]), - ( - "atomics-32", - // Not implied by any CPU model or other feature. - Stability::InternalOnly { - reason: "unsound because it changes the ABI of atomic operations", - hard_error: false, - }, - &[], - ), - ("crc", Unstable(sym::arm_target_feature), &[]), - ("d32", Unstable(sym::arm_target_feature), &[]), - ("dotprod", Unstable(sym::arm_target_feature), &["neon"]), - ("dsp", Unstable(sym::arm_target_feature), &[]), - ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]), - ("fp16", Unstable(sym::arm_target_feature), &["neon"]), - ("fp64", Unstable(sym::arm_target_feature), &[]), - ("fpregs", Unstable(sym::arm_target_feature), &[]), - ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), - ("mclass", Unstable(sym::arm_target_feature), &[]), - ("mve", Unstable(sym::arm_target_feature), &["v8.1m.main", "dsp", "fpregs"]), - ("mve.fp", Unstable(sym::arm_target_feature), &["mve"]), - ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), - ("rclass", Unstable(sym::arm_target_feature), &[]), - ("sha2", Unstable(sym::arm_target_feature), &["neon"]), - // This can be *disabled* on non-`hf` targets to enable the use - // of hardfloats while keeping the softfloat ABI. - // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of - // matching the odd negative feature LLVM uses? - ("soft-float", Unstable(sym::arm_target_feature), &[]), - // This is needed for inline assembly, but shouldn't be stabilized as-is - // since it should be enabled per-function using #[instruction_set], not - // #[target_feature]. - ("thumb-mode", Unstable(sym::arm_target_feature), &[]), - ("thumb2", Unstable(sym::arm_target_feature), &[]), - ("trustzone", Unstable(sym::arm_target_feature), &[]), - ("v5te", Unstable(sym::arm_target_feature), &[]), - ("v6", Unstable(sym::arm_target_feature), &["v5te"]), - ("v6k", Unstable(sym::arm_target_feature), &["v6"]), - ("v6m", Unstable(sym::arm_target_feature), &["v6"]), - ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]), - ("v7", Unstable(sym::arm_target_feature), &["v6t2"]), - ("v8", Unstable(sym::arm_target_feature), &["v7", "acquire-release"]), - ("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]), - ("v8m", Unstable(sym::arm_target_feature), &["v6m"]), - ("v8m.main", Unstable(sym::arm_target_feature), &["v7"]), - ("vfp2", Unstable(sym::arm_target_feature), &["vfp2sp", "fp64"]), - ("vfp2sp", Unstable(sym::arm_target_feature), &["fpregs"]), - ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]), - ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]), - ("virtualization", Unstable(sym::arm_target_feature), &[]), - // tidy-alphabetical-end -]; - -static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - // FEAT_AES & FEAT_PMULL - ("aes", Stable, &["neon"]), - // FEAT_BF16 - ("bf16", Stable, &[]), - // FEAT_BTI - ("bti", Stable, &[]), - // FEAT_CRC - ("crc", Stable, &[]), - // FEAT_CSSC - ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_DIT - ("dit", Stable, &[]), - // FEAT_DotProd - ("dotprod", Stable, &["neon"]), - // FEAT_DPB - ("dpb", Stable, &[]), - // FEAT_DPB2 - ("dpb2", Stable, &["dpb"]), - // FEAT_ECV - ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_F32MM - ("f32mm", Stable, &["sve"]), - // FEAT_F64MM - ("f64mm", Stable, &["sve"]), - // FEAT_FAMINMAX - ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_FCMA - ("fcma", Stable, &["neon"]), - // FEAT_FHM - ("fhm", Stable, &["fp16"]), - // FEAT_FLAGM - ("flagm", Stable, &[]), - // FEAT_FLAGM2 - ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), - // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`. - ( - "fp-armv8", - // Pinned down by [`Target::abi_required_features`] when needed. - Stability::InternalOnly { reason: "Rust ties `fp-armv8` to `neon`", hard_error: false }, - &[], - ), - // FEAT_FP8 - ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), - // FEAT_FP8DOT2 - ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), - // FEAT_FP8DOT4 - ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), - // FEAT_FP8FMA - ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), - // FEAT_FP16 - // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 - ("fp16", Stable, &["neon"]), - // FEAT_FRINTTS - ("frintts", Stable, &[]), - // FEAT_HBC - ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_I8MM - ("i8mm", Stable, &[]), - // FEAT_JSCVT - // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 - ("jsconv", Stable, &["neon"]), - // FEAT_LOR - ("lor", Stable, &[]), - // FEAT_LSE - ("lse", Stable, &[]), - // FEAT_LSE2 - ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_LSE128 - ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), - // FEAT_LUT - ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_MOPS - ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_MTE & FEAT_MTE2 - ("mte", Stable, &[]), - // FEAT_AdvSimd & FEAT_FP - ("neon", Stable, &[]), - // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be - // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally - // using slower non-LSE operations. Unstable since it doesn't need to user-togglable. - ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_PAUTH (address authentication) - ("paca", Stable, &[]), - // FEAT_PAUTH (generic authentication) - ("pacg", Stable, &[]), - // FEAT_PAN - ("pan", Stable, &[]), - // FEAT_PAuth_LR - ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_PMUv3 - ("pmuv3", Stable, &[]), - // FEAT_RNG - ("rand", Stable, &[]), - // FEAT_RAS & FEAT_RASv1p1 - ("ras", Stable, &[]), - // FEAT_LRCPC - ("rcpc", Stable, &[]), - // FEAT_LRCPC2 - ("rcpc2", Stable, &["rcpc"]), - // FEAT_LRCPC3 - ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), - // FEAT_RDM - ("rdm", Stable, &["neon"]), - ( - "reserve-x18", - // Not implied by any CPU model or other feature; the compiler flag is a target modifier. - InternalOnly { reason: "use `-Zfixed-x18` compiler flag instead", hard_error: false }, - &[], - ), - // FEAT_SB - ("sb", Stable, &[]), - // FEAT_SHA1 & FEAT_SHA256 - ("sha2", Stable, &["neon"]), - // FEAT_SHA512 & FEAT_SHA3 - ("sha3", Stable, &["sha2"]), - // FEAT_SM3 & FEAT_SM4 - ("sm4", Stable, &["neon"]), - // FEAT_SME - ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), - // FEAT_SME_B16B16 - ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), - // FEAT_SME_F8F16 - ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), - // FEAT_SME_F8F32 - ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), - // FEAT_SME_F16F16 - ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), - // FEAT_SME_F64F64 - ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), - // FEAT_SME_FA64 - ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), - // FEAT_SME_I16I64 - ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), - // FEAT_SME_LUTv2 - ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]), - // FEAT_SME2 - ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), - // FEAT_SME2p1 - ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), - // FEAT_SPE - ("spe", Stable, &[]), - // FEAT_SSBS & FEAT_SSBS2 - ("ssbs", Stable, &[]), - // FEAT_SSVE_FP8FDOT2 - ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), - // FEAT_SSVE_FP8FDOT4 - ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), - // FEAT_SSVE_FP8FMA - ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), - // FEAT_SVE - // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608 - // - // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always - // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2 - // - // "For backwards compatibility, Neon and VFP are required in the latest architectures." - ("sve", Stable, &["neon", "fp16"]), - // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) - ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), - // FEAT_SVE2 - ("sve2", Stable, &["sve"]), - // FEAT_SVE_AES & FEAT_SVE_PMULL128 - ("sve2-aes", Stable, &["sve2", "aes"]), - // FEAT_SVE2_BitPerm - ("sve2-bitperm", Stable, &["sve2"]), - // FEAT_SVE2_SHA3 - ("sve2-sha3", Stable, &["sve2", "sha3"]), - // FEAT_SVE2_SM4 - ("sve2-sm4", Stable, &["sve2", "sm4"]), - // FEAT_SVE2p1 - ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]), - // FEAT_TME - ("tme", Stable, &[]), - ( - "v8.1a", - Unstable(sym::aarch64_ver_target_feature), - &["crc", "lse", "rdm", "pan", "lor", "vh"], - ), - ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]), - ( - "v8.3a", - Unstable(sym::aarch64_ver_target_feature), - &["v8.2a", "rcpc", "paca", "pacg", "jsconv"], - ), - ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]), - ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]), - ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]), - ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]), - ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]), - ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]), - ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]), - ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]), - ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]), - ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]), - ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]), - ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a"]), - // FEAT_VHE - ("vh", Stable, &[]), - // FEAT_WFxT - ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]), - // tidy-alphabetical-end -]; - -static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("adx", Stable, &[]), - ("aes", Stable, &["sse2"]), - ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), - ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), - ("apxf", Unstable(sym::apx_target_feature), &[]), - ("avx", Stable, &["sse4.2"]), - ("avx2", Stable, &["avx"]), - ( - "avx10.1", - Unstable(sym::avx10_target_feature), - &[ - "avx512bf16", - "avx512bitalg", - "avx512bw", - "avx512cd", - "avx512dq", - "avx512f", - "avx512fp16", - "avx512ifma", - "avx512vbmi", - "avx512vbmi2", - "avx512vl", - "avx512vnni", - "avx512vpopcntdq", - ], - ), - ( - "avx10.2", - Unstable(sym::avx10_target_feature), - &["avx10.1", "avxvnni", "avxvnniint8", "avxvnniint16"], - ), - ("avx512bf16", Stable, &["avx512bw"]), - ("avx512bitalg", Stable, &["avx512bw"]), - ("avx512bw", Stable, &["avx512f"]), - ("avx512cd", Stable, &["avx512f"]), - ("avx512dq", Stable, &["avx512f"]), - ("avx512f", Stable, &["avx2", "fma", "f16c"]), - ("avx512fp16", Stable, &["avx512bw"]), - ("avx512ifma", Stable, &["avx512f"]), - ("avx512vbmi", Stable, &["avx512bw"]), - ("avx512vbmi2", Stable, &["avx512bw"]), - ("avx512vl", Stable, &["avx512f"]), - ("avx512vnni", Stable, &["avx512f"]), - ("avx512vp2intersect", Stable, &["avx512f"]), - ("avx512vpopcntdq", Stable, &["avx512f"]), - ("avxifma", Stable, &["avx2"]), - ("avxneconvert", Stable, &["avx2"]), - ("avxvnni", Stable, &["avx2"]), - ("avxvnniint8", Stable, &["avx2"]), - ("avxvnniint16", Stable, &["avx2"]), - ("bmi1", Stable, &[]), - ("bmi2", Stable, &[]), - ("clflushopt", Unstable(sym::clflushopt_target_feature), &[]), - ("cmpxchg16b", Stable, &[]), - ("ermsb", Unstable(sym::ermsb_target_feature), &[]), - ("f16c", Stable, &["avx"]), - ("fma", Stable, &["avx"]), - ("fma4", Unstable(sym::fma4_target_feature), &["avx", "sse4a"]), - ("fxsr", Stable, &[]), - ("gfni", Stable, &["sse2"]), - ("kl", Stable, &["sse2"]), - ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), - ("lzcnt", Stable, &[]), - ("movbe", Stable, &[]), - ("movdir64b", Unstable(sym::movdir64b_target_feature), &[]), - ("movdiri", Unstable(sym::movdiri_target_feature), &[]), - ("movrs", Unstable(sym::movrs_target_feature), &[]), - ("pclmulqdq", Stable, &["sse2"]), - ("popcnt", Stable, &[]), - ("prfchw", Unstable(sym::prfchw_target_feature), &[]), - ("rdrand", Stable, &[]), - ("rdseed", Stable, &[]), - ( - "retpoline-external-thunk", - // Not implied by any CPU model or other feature; the compiler flag is a target modifier. - Stability::InternalOnly { - reason: "use `-Zretpoline-external-thunk` compiler flag instead", - hard_error: false, - }, - &[], - ), - ( - "retpoline-indirect-branches", - // Not implied by any CPU model or other feature; the compiler flag is a target modifier. - Stability::InternalOnly { - reason: "use `-Zretpoline` compiler flag instead", - hard_error: false, - }, - &[], - ), - ( - "retpoline-indirect-calls", - // Not implied by any CPU model or other feature; the compiler flag is a target modifier. - Stability::InternalOnly { - reason: "use `-Zretpoline` compiler flag instead", - hard_error: false, - }, - &[], - ), - ("rtm", Unstable(sym::rtm_target_feature), &[]), - ("sha", Stable, &["sse2"]), - ("sha512", Stable, &["avx2"]), - ("sm3", Stable, &["avx"]), - ("sm4", Stable, &["avx2"]), - ( - "soft-float", - // Pinned down by [`Target::abi_required_features`]. - Stability::InternalOnly { reason: "use a soft-float target instead", hard_error: false }, - &[], - ), - ("sse", Stable, &[]), - ("sse2", Stable, &["sse"]), - ("sse3", Stable, &["sse2"]), - ("sse4.1", Stable, &["ssse3"]), - ("sse4.2", Stable, &["sse4.1"]), - ("sse4a", Stable, &["sse3"]), - ("ssse3", Stable, &["sse3"]), - ("tbm", Stable, &[]), - ("vaes", Stable, &["avx2", "aes"]), - ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), - ("widekl", Stable, &["kl"]), - ("x87", Unstable(sym::x87_target_feature), &[]), - ("xop", Unstable(sym::xop_target_feature), &["fma4", "avx", "sse4a"]), - ("xsave", Stable, &[]), - ("xsavec", Stable, &["xsave"]), - ("xsaveopt", Stable, &["xsave"]), - ("xsaves", Stable, &["xsave"]), - // tidy-alphabetical-end -]; - -const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("audio", Unstable(sym::hexagon_target_feature), &[]), - ("hvx", Unstable(sym::hexagon_target_feature), &[]), - ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]), - ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]), - ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]), - ("hvx-qfloat", Unstable(sym::hexagon_target_feature), &["hvx"]), - ("hvxv60", Unstable(sym::hexagon_target_feature), &["hvx"]), - ("hvxv62", Unstable(sym::hexagon_target_feature), &["hvxv60"]), - ("hvxv65", Unstable(sym::hexagon_target_feature), &["hvxv62"]), - ("hvxv66", Unstable(sym::hexagon_target_feature), &["hvxv65", "zreg"]), - ("hvxv67", Unstable(sym::hexagon_target_feature), &["hvxv66"]), - ("hvxv68", Unstable(sym::hexagon_target_feature), &["hvxv67"]), - ("hvxv69", Unstable(sym::hexagon_target_feature), &["hvxv68"]), - ("hvxv71", Unstable(sym::hexagon_target_feature), &["hvxv69"]), - ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]), - ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]), - ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]), - ("v60", Unstable(sym::hexagon_target_feature), &[]), - ("v62", Unstable(sym::hexagon_target_feature), &["v60"]), - ("v65", Unstable(sym::hexagon_target_feature), &["v62"]), - ("v66", Unstable(sym::hexagon_target_feature), &["v65"]), - ("v67", Unstable(sym::hexagon_target_feature), &["v66"]), - ("v68", Unstable(sym::hexagon_target_feature), &["v67"]), - ("v69", Unstable(sym::hexagon_target_feature), &["v68"]), - ("v71", Unstable(sym::hexagon_target_feature), &["v69"]), - ("v73", Unstable(sym::hexagon_target_feature), &["v71"]), - ("v75", Unstable(sym::hexagon_target_feature), &["v73"]), - ("v79", Unstable(sym::hexagon_target_feature), &["v75"]), - ("zreg", Unstable(sym::hexagon_target_feature), &[]), - // tidy-alphabetical-end -]; - -static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // If you are thinking of adding "efpu2" here, please double-check that it really does not - // affect the ABI. - // tidy-alphabetical-start - ("altivec", Unstable(sym::powerpc_target_feature), &[]), - ( - "hard-float", - // Pinned down by [`Target::abi_required_features`]. - InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, - &[], - ), - ("msync", Unstable(sym::powerpc_target_feature), &[]), - ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), - ("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"]), - ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), - ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), - ( - "spe", - // Pinned down by [`Target::abi_required_features`]. - InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, - &[], - ), - ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), - // tidy-alphabetical-end -]; - -const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("fp64", Unstable(sym::mips_target_feature), &[]), - // FIXME(#150253): msa requires either fp64 or no hard float support at all: LLVM requires fp64 - // FIXME(#150253): msa requires revision 5 or greater (mips32r5/mips64r5 in LLVM) - ("msa", Unstable(sym::mips_target_feature), &[]), - ("virt", Unstable(sym::mips_target_feature), &[]), - // tidy-alphabetical-end -]; - -const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("sm_70", Unstable(sym::nvptx_target_feature), &[]), - ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), - ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), - ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), - ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]), - ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]), - ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]), - ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]), - ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]), - // tidy-alphabetical-end - // tidy-alphabetical-start - ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]), - ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]), - ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]), - ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]), - ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]), - ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), - // tidy-alphabetical-end - // tidy-alphabetical-start - ("ptx70", Unstable(sym::nvptx_target_feature), &[]), - ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), - ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), - ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), - ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]), - ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]), - ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]), - ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]), - ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]), - ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]), - ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]), - ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]), - ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]), - ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]), - ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]), - ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]), - ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]), - // tidy-alphabetical-end -]; - -static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("a", Stable, &["zaamo", "zalrsc"]), - ("b", Stable, &["zba", "zbb", "zbs"]), - ("c", Stable, &["zca"]), - ("d", Stable, &["f"]), - ("e", Unstable(sym::riscv_target_feature), &[]), // negative feature! needs special care. - ("f", Stable, &["zicsr"]), - ( - "forced-atomics", - // Not implied by any CPU model or other feature. - Stability::InternalOnly { - reason: "unsound because it changes the ABI of atomic operations", - hard_error: false, - }, - &[], - ), - // According to the RISC-V spec, the M ISA extension (integer multiplication/division) is supported only when the M bit - // of the misa register is 1, while Zmmul means integer multiplication is always supported. - // - // The Rust/LLVM "m" target feature means something slightly different: with "m" enabled, it is assumed that integer - // multiplication and division will always be available (M bit will be 1 in misa), so "m" implies "zmmul". - // - // See discussion in the PR adding Zmmul: https://github.com/rust-lang/rust/pull/162552 - ("m", Stable, &["zmmul"]), - ("relax", Unstable(sym::riscv_target_feature), &[]), - ( - "rva23u64", - Unstable(sym::riscv_target_feature), - &[ - "m", - "a", - "f", - "d", - "c", - "b", - "v", - "zicsr", - "zicntr", - "zihpm", - "ziccif", - "ziccrse", - "ziccamoa", - "zicclsm", - "zic64b", - "za64rs", - "zihintpause", - "zba", - "zbb", - "zbs", - "zicbom", - "zicbop", - "zicboz", - "zfhmin", - "zkt", - "zvfhmin", - "zvbb", - "zvkt", - "zihintntl", - "zicond", - "zimop", - "zcmop", - "zcb", - "zfa", - "zawrs", - "supm", - ], - ), - ("supm", Unstable(sym::riscv_target_feature), &[]), - ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), - ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), - ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), - ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs - ("za128rs", Stable, &[]), - ("zaamo", Stable, &[]), - ("zabha", Stable, &["zaamo"]), - ("zacas", Stable, &["zaamo"]), - ("zalrsc", Stable, &[]), - ("zama16b", Stable, &[]), - ("zawrs", Stable, &[]), - ("zba", Stable, &[]), - ("zbb", Stable, &[]), - ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc - ("zbkb", Stable, &[]), - ("zbkc", Stable, &[]), - ("zbkx", Stable, &[]), - ("zbs", Stable, &[]), - ("zca", Stable, &[]), - ("zcb", Stable, &["zca"]), - ("zcmop", Stable, &["zca"]), - ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), - ("zfa", Unstable(sym::riscv_target_feature), &["f"]), - ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin - ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), - ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), - ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), - ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), - ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), - ("zic64b", Stable, &[]), - ("zicbom", Stable, &[]), - ("zicbop", Stable, &[]), - ("zicboz", Stable, &[]), - ("ziccamoa", Stable, &[]), - ("ziccif", Stable, &[]), - ("zicclsm", Stable, &[]), - ("ziccrse", Stable, &[]), - ("zicntr", Stable, &["zicsr"]), - ("zicond", Stable, &[]), - ("zicsr", Stable, &[]), - ("zifencei", Stable, &[]), - ("zihintntl", Stable, &[]), - ("zihintpause", Stable, &[]), - ("zihpm", Stable, &["zicsr"]), - ("zimop", Stable, &[]), - ("zk", Stable, &["zkn", "zkr", "zkt"]), - ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), - ("zknd", Stable, &["zkne_or_zknd"]), - ("zkne", Stable, &["zkne_or_zknd"]), - ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension - ("zknh", Stable, &[]), - ("zkr", Stable, &[]), - ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), - ("zksed", Stable, &[]), - ("zksh", Stable, &[]), - ("zkt", Stable, &[]), - ("zmmul", Unstable(sym::riscv_target_feature), &[]), - ("ztso", Stable, &[]), - ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb - ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), - ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), - ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]), - ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), - ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), - ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), - ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), - ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), - ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin - ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), - ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]), - ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]), - ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]), - ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha - ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]), - ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]), - ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]), - ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]), - ("zvkt", Unstable(sym::riscv_target_feature), &[]), - ("zvl32b", Unstable(sym::riscv_target_feature), &[]), - ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), - ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]), - ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]), - ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]), - ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), - ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), - ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), - ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]), - ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), - ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), - ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), - // tidy-alphabetical-end -]; - -static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("atomics", Unstable(sym::wasm_target_feature), &[]), - ("bulk-memory", Stable, &[]), - ("exception-handling", Unstable(sym::wasm_target_feature), &[]), - ("extended-const", Stable, &[]), - ("gc", Unstable(sym::wasm_target_feature), &["reference-types"]), - ("multivalue", Stable, &[]), - ("mutable-globals", Stable, &[]), - ("nontrapping-fptoint", Stable, &[]), - ("reference-types", Stable, &[]), - ("relaxed-simd", Stable, &["simd128"]), - ("sign-ext", Stable, &[]), - ("simd128", Stable, &[]), - ("tail-call", Stable, &[]), - ("wide-arithmetic", Unstable(sym::wasm_target_feature), &[]), - // tidy-alphabetical-end -]; - -const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - ("alu32", Unstable(sym::bpf_target_feature), &[]), - ("allows-misaligned-mem-access", Unstable(sym::bpf_target_feature), &[]), -]; - -static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("2e3", Unstable(sym::csky_target_feature), &["e2"]), - ("3e3r1", Unstable(sym::csky_target_feature), &[]), - ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]), - ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]), - ("3e7", Unstable(sym::csky_target_feature), &["2e3"]), - ("7e10", Unstable(sym::csky_target_feature), &["3e7"]), - ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), - ("cache", Unstable(sym::csky_target_feature), &[]), - ("doloop", Unstable(sym::csky_target_feature), &[]), - ("dsp1e2", Unstable(sym::csky_target_feature), &[]), - ("dspe60", Unstable(sym::csky_target_feature), &[]), - ("e1", Unstable(sym::csky_target_feature), &["elrw"]), - ("e2", Unstable(sym::csky_target_feature), &["e2"]), - ("edsp", Unstable(sym::csky_target_feature), &[]), - ("elrw", Unstable(sym::csky_target_feature), &[]), - ("float1e2", Unstable(sym::csky_target_feature), &[]), - ("float1e3", Unstable(sym::csky_target_feature), &[]), - ("float3e4", Unstable(sym::csky_target_feature), &[]), - ("float7e60", Unstable(sym::csky_target_feature), &[]), - ("floate1", Unstable(sym::csky_target_feature), &[]), - ("hard-tp", Unstable(sym::csky_target_feature), &[]), - ("high-registers", Unstable(sym::csky_target_feature), &[]), - ("hwdiv", Unstable(sym::csky_target_feature), &[]), - ("mp", Unstable(sym::csky_target_feature), &["2e3"]), - ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]), - ("nvic", Unstable(sym::csky_target_feature), &[]), - ("trust", Unstable(sym::csky_target_feature), &[]), - ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]), - ("vdspv1", Unstable(sym::csky_target_feature), &[]), - ("vdspv2", Unstable(sym::csky_target_feature), &[]), - // tidy-alphabetical-end - //fpu - // tidy-alphabetical-start - ("fdivdu", Unstable(sym::csky_target_feature), &[]), - ("fpuv2_df", Unstable(sym::csky_target_feature), &[]), - ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]), - ("fpuv3_df", Unstable(sym::csky_target_feature), &[]), - ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]), - ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]), - ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]), - ("hard-float", Unstable(sym::csky_target_feature), &[]), - ("hard-float-abi", Unstable(sym::csky_target_feature), &[]), - // tidy-alphabetical-end -]; - -static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("32s", Unstable(sym::loongarch_target_feature), &[]), - ("d", Stable, &["f"]), - ("div32", Stable, &[]), - ("f", Stable, &[]), - ("frecipe", Stable, &[]), - ("lam-bh", Stable, &[]), - ("lamcas", Stable, &[]), - ("lasx", Stable, &["lsx"]), - ("lbt", Stable, &[]), - ("ld-seq-sa", Stable, &[]), - ("lsx", Stable, &["d"]), - ("lvz", Stable, &[]), - ("relax", Unstable(sym::loongarch_target_feature), &[]), - ("scq", Stable, &[]), - ("ual", Unstable(sym::loongarch_target_feature), &[]), - // tidy-alphabetical-end -]; - -#[rustfmt::skip] -const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker - ("backchain", Unstable(sym::s390x_target_feature), &[]), - ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), - ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), - ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), - ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), - ("high-word", Unstable(sym::s390x_target_feature), &[]), - // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. - ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), - ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), - ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), - ("message-security-assist-extension8", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3"]), - ("message-security-assist-extension9", Unstable(sym::s390x_target_feature), &["message-security-assist-extension3", "message-security-assist-extension4"]), - ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), - ("miscellaneous-extensions-2", Stable, &[]), - ("miscellaneous-extensions-3", Stable, &[]), - ("miscellaneous-extensions-4", Stable, &[]), - ("nnp-assist", Stable, &["vector"]), - // Pinned down by [`Target::abi_required_features`]. - ("soft-float", InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, &[]), - ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), - ("vector", Stable, &[]), - ("vector-enhancements-1", Stable, &["vector"]), - ("vector-enhancements-2", Stable, &["vector-enhancements-1"]), - ("vector-enhancements-3", Stable, &["vector-enhancements-2"]), - ("vector-packed-decimal", Stable, &["vector"]), - ("vector-packed-decimal-enhancement", Stable, &["vector-packed-decimal"]), - ("vector-packed-decimal-enhancement-2", Stable, &["vector-packed-decimal-enhancement"]), - ("vector-packed-decimal-enhancement-3", Stable, &["vector-packed-decimal-enhancement-2"]), - // tidy-alphabetical-end -]; - -const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("leoncasa", Unstable(sym::sparc_target_feature), &[]), - ( - "soft-float", - InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, - &[], - ), - ("v8plus", Unstable(sym::sparc_target_feature), &[]), - // FIXME: It's unclear what this feature means when `v8plus` is disabled on 32-bit SPARC. See - // the discussion around https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355. - ("v9", Unstable(sym::sparc_target_feature), &[]), - // tidy-alphabetical-end -]; - -static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("isa-68000", Unstable(sym::m68k_target_feature), &[]), - ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]), - ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]), - ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]), - ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]), - ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]), - // FPU - ("isa-68881", Unstable(sym::m68k_target_feature), &[]), - ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]), - // tidy-alphabetical-end -]; - -static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - // tidy-alphabetical-start - ("addsubiw", Unstable(sym::avr_target_feature), &[]), - ("break", Unstable(sym::avr_target_feature), &[]), - ("eijmpcall", Unstable(sym::avr_target_feature), &[]), - ("elpm", Unstable(sym::avr_target_feature), &[]), - ("elpmx", Unstable(sym::avr_target_feature), &[]), - ("ijmpcall", Unstable(sym::avr_target_feature), &[]), - ("jmpcall", Unstable(sym::avr_target_feature), &[]), - ("lowbytefirst", Unstable(sym::avr_target_feature), &[]), - ("lpm", Unstable(sym::avr_target_feature), &[]), - ("lpmx", Unstable(sym::avr_target_feature), &[]), - ("movw", Unstable(sym::avr_target_feature), &[]), - ("mul", Unstable(sym::avr_target_feature), &[]), - ("rmw", Unstable(sym::avr_target_feature), &[]), - ("spm", Unstable(sym::avr_target_feature), &[]), - ("spmx", Unstable(sym::avr_target_feature), &[]), - ( - "sram", - // Pinned down by [`Target::abi_required_features`]. - InternalOnly { reason: "devices that have no SRAM are unsupported", hard_error: false }, - &[], - ), - ("tinyencoding", Unstable(sym::avr_target_feature), &[]), - // tidy-alphabetical-end -]; - -const XTENSA_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ - ("bool", Unstable(sym::xtensa_target_feature), &[]), - ("fp", Unstable(sym::xtensa_target_feature), &["bool", "coprocessor"]), - ("coprocessor", Unstable(sym::xtensa_target_feature), &[]), - ("highpriinterrupts", Unstable(sym::xtensa_target_feature), &["interrupt"]), - ("interrupt", Unstable(sym::xtensa_target_feature), &["exception"]), - ( - "windowed", - // Pinned down by [`Target::abi_required_features`]. - InternalOnly { - reason: "windowed changes the Xtensa calling convention", - hard_error: false, - }, - &["exception"], - ), - ("loop", Unstable(sym::xtensa_target_feature), &[]), - ("sext", Unstable(sym::xtensa_target_feature), &[]), - ("nsa", Unstable(sym::xtensa_target_feature), &[]), - ("mul32", Unstable(sym::xtensa_target_feature), &[]), - ("mul32high", Unstable(sym::xtensa_target_feature), &["mul32"]), - ("div32", Unstable(sym::xtensa_target_feature), &[]), - ("mac16", Unstable(sym::xtensa_target_feature), &[]), - ("s32c1i", Unstable(sym::xtensa_target_feature), &[]), - ("threadptr", Unstable(sym::xtensa_target_feature), &[]), - ("extendedl32r", Unstable(sym::xtensa_target_feature), &[]), - ("debug", Unstable(sym::xtensa_target_feature), &["exception"]), - ("exception", Unstable(sym::xtensa_target_feature), &[]), - ("rvector", Unstable(sym::xtensa_target_feature), &["exception"]), - ("prid", Unstable(sym::xtensa_target_feature), &[]), - ("regprotect", Unstable(sym::xtensa_target_feature), &[]), - ("miscsr", Unstable(sym::xtensa_target_feature), &[]), -]; - -static TARGET_FEATURE_IMPLICATIONS_RAW: &[&[(&str, Stability, ImpliedFeatures)]] = &[ - ARM_FEATURES, - AARCH64_FEATURES, - X86_FEATURES, - HEXAGON_FEATURES, - POWERPC_FEATURES, - MIPS_FEATURES, - NVPTX_FEATURES, - RISCV_FEATURES, - WASM_FEATURES, - BPF_FEATURES, - XTENSA_FEATURES, - CSKY_FEATURES, - LOONGARCH_FEATURES, - IBMZ_FEATURES, - SPARC_FEATURES, - M68K_FEATURES, - AVR_FEATURES, -]; -// spellchecker:on diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/target_feature/generated.rs b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature/generated.rs new file mode 100644 index 0000000000000..41916d0b08c5c --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/target_feature/generated.rs @@ -0,0 +1,961 @@ +//! Generated by `cargo xtask codegen target-features`, do not edit by hand. + +// spellchecker:off + +#[expect(dead_code, reason = "stubs for rustc_target")] +pub(super) enum Stability { + Stable, + Unstable(()), + InternalOnly { reason: &'static str, hard_error: bool }, +} +use Stability::*; + +type ImpliedFeatures = &'static [&'static str]; +static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("aclass", Unstable(sym::arm_target_feature), &[]), + ("acquire-release", Unstable(sym::arm_target_feature), &[]), + ("aes", Unstable(sym::arm_target_feature), &["neon"]), + ( + "atomics-32", + // Not implied by any CPU model or other feature. + Stability::InternalOnly { + reason: "unsound because it changes the ABI of atomic operations", + hard_error: false, + }, + &[], + ), + ("bf16", Unstable(sym::arm_target_feature), &["neon"]), + ("crc", Unstable(sym::arm_target_feature), &[]), + ("d32", Unstable(sym::arm_target_feature), &[]), + ("dotprod", Unstable(sym::arm_target_feature), &["neon"]), + ("dsp", Unstable(sym::arm_target_feature), &[]), + ("fp-armv8", Unstable(sym::arm_target_feature), &["vfp4"]), + ("fp16", Unstable(sym::arm_target_feature), &["neon"]), + ("fp64", Unstable(sym::arm_target_feature), &[]), + ("fpregs", Unstable(sym::arm_target_feature), &[]), + ("i8mm", Unstable(sym::arm_target_feature), &["neon"]), + ("mclass", Unstable(sym::arm_target_feature), &[]), + ("mve", Unstable(sym::arm_target_feature), &["v8.1m.main", "dsp", "fpregs"]), + ("mve.fp", Unstable(sym::arm_target_feature), &["mve"]), + ("neon", Unstable(sym::arm_target_feature), &["vfp3"]), + ("rclass", Unstable(sym::arm_target_feature), &[]), + ("sha2", Unstable(sym::arm_target_feature), &["neon"]), + // This can be *disabled* on non-`hf` targets to enable the use + // of hardfloats while keeping the softfloat ABI. + // FIXME before stabilization: Should we expose this as a `hard-float` target feature instead of + // matching the odd negative feature LLVM uses? + ("soft-float", Unstable(sym::arm_target_feature), &[]), + // This is needed for inline assembly, but shouldn't be stabilized as-is + // since it should be enabled per-function using #[instruction_set], not + // #[target_feature]. + ("thumb-mode", Unstable(sym::arm_target_feature), &[]), + ("thumb2", Unstable(sym::arm_target_feature), &[]), + ("trustzone", Unstable(sym::arm_target_feature), &[]), + ("v5te", Unstable(sym::arm_target_feature), &[]), + ("v6", Unstable(sym::arm_target_feature), &["v5te"]), + ("v6k", Unstable(sym::arm_target_feature), &["v6"]), + ("v6m", Unstable(sym::arm_target_feature), &["v6"]), + ("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]), + ("v7", Unstable(sym::arm_target_feature), &["v6t2"]), + ("v8", Unstable(sym::arm_target_feature), &["v7", "acquire-release"]), + ("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]), + ("v8m", Unstable(sym::arm_target_feature), &["v6m"]), + ("v8m.main", Unstable(sym::arm_target_feature), &["v7"]), + ("vfp2", Unstable(sym::arm_target_feature), &["vfp2sp", "fp64"]), + ("vfp2sp", Unstable(sym::arm_target_feature), &["fpregs"]), + ("vfp3", Unstable(sym::arm_target_feature), &["vfp2", "d32"]), + ("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]), + ("virtualization", Unstable(sym::arm_target_feature), &[]), + // tidy-alphabetical-end +]; +static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + // FEAT_AES & FEAT_PMULL + ("aes", Stable, &["neon"]), + // FEAT_BF16 + ("bf16", Stable, &[]), + // FEAT_BTI + ("bti", Stable, &[]), + // FEAT_CRC + ("crc", Stable, &[]), + // FEAT_CSSC + ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_DIT + ("dit", Stable, &[]), + // FEAT_DotProd + ("dotprod", Stable, &["neon"]), + // FEAT_DPB + ("dpb", Stable, &[]), + // FEAT_DPB2 + ("dpb2", Stable, &["dpb"]), + // FEAT_ECV + ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_F32MM + ("f32mm", Stable, &["sve"]), + // FEAT_F64MM + ("f64mm", Stable, &["sve"]), + // FEAT_FAMINMAX + ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_FCMA + ("fcma", Stable, &["neon"]), + // FEAT_FHM + ("fhm", Stable, &["fp16"]), + // FEAT_FLAGM + ("flagm", Stable, &[]), + // FEAT_FLAGM2 + ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // We forbid directly toggling just `fp-armv8`; it must be toggled with `neon`. + ( + "fp-armv8", + // Pinned down by [`Target::abi_required_features`] when needed. + Stability::InternalOnly { reason: "Rust ties `fp-armv8` to `neon`", hard_error: false }, + &[], + ), + // FEAT_FP8 + ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), + // FEAT_FP8DOT2 + ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), + // FEAT_FP8DOT4 + ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), + // FEAT_FP8FMA + ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), + // FEAT_FP16 + // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 + ("fp16", Stable, &["neon"]), + // FEAT_FRINTTS + ("frintts", Stable, &[]), + // FEAT_HBC + ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_I8MM + ("i8mm", Stable, &[]), + // FEAT_JSCVT + // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 + ("jsconv", Stable, &["neon"]), + // FEAT_LOR + ("lor", Stable, &[]), + // FEAT_LSE + ("lse", Stable, &[]), + // FEAT_LSE2 + ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_LSE128 + ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), + // FEAT_LUT + ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_MOPS + ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_MTE & FEAT_MTE2 + ("mte", Stable, &[]), + // FEAT_AdvSimd & FEAT_FP + ("neon", Stable, &[]), + // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be + // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally + // using slower non-LSE operations. Unstable since it doesn't need to user-togglable. + ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_PAUTH (address authentication) + ("paca", Stable, &[]), + // FEAT_PAUTH (generic authentication) + ("pacg", Stable, &[]), + // FEAT_PAN + ("pan", Stable, &[]), + // FEAT_PAuth_LR + ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_PMUv3 + ("pmuv3", Stable, &[]), + // FEAT_RNG + ("rand", Stable, &[]), + // FEAT_RAS & FEAT_RASv1p1 + ("ras", Stable, &[]), + // FEAT_LRCPC + ("rcpc", Stable, &[]), + // FEAT_LRCPC2 + ("rcpc2", Stable, &["rcpc"]), + // FEAT_LRCPC3 + ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), + // FEAT_RDM + ("rdm", Stable, &["neon"]), + ( + "reserve-x18", + // Not implied by any CPU model or other feature; the compiler flag is a target modifier. + InternalOnly { reason: "use `-Zfixed-x18` compiler flag instead", hard_error: false }, + &[], + ), + // FEAT_SB + ("sb", Stable, &[]), + // FEAT_SHA1 & FEAT_SHA256 + ("sha2", Stable, &["neon"]), + // FEAT_SHA512 & FEAT_SHA3 + ("sha3", Stable, &["sha2"]), + // FEAT_SM3 & FEAT_SM4 + ("sm4", Stable, &["neon"]), + // FEAT_SME + ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + // FEAT_SME_B16B16 + ("sme-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16", "sme2", "sve-b16b16"]), + // FEAT_SME_F8F16 + ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), + // FEAT_SME_F8F32 + ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + // FEAT_SME_F16F16 + ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + // FEAT_SME_F64F64 + ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME_FA64 + ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), + // FEAT_SME_I16I64 + ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME_LUTv2 + ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_SME2 + ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME2p1 + ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + // FEAT_SPE + ("spe", Stable, &[]), + // FEAT_SSBS & FEAT_SSBS2 + ("ssbs", Stable, &[]), + // FEAT_SSVE_FP8FDOT2 + ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), + // FEAT_SSVE_FP8FDOT4 + ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), + // FEAT_SSVE_FP8FMA + ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + // FEAT_SVE + // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608 + // + // LLVM doesn't enable Neon for SVE. ARM indicates that they're separate, but probably always + // exist together: https://developer.arm.com/documentation/102340/0100/New-features-in-SVE2 + // + // "For backwards compatibility, Neon and VFP are required in the latest architectures." + ("sve", Stable, &["neon", "fp16"]), + // FEAT_SVE_B16B16 (SVE or SME Z-targeting instructions) + ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + // FEAT_SVE2 + ("sve2", Stable, &["sve"]), + // FEAT_SVE_AES & FEAT_SVE_PMULL128 + ("sve2-aes", Stable, &["sve2", "aes"]), + // FEAT_SVE2_BitPerm + ("sve2-bitperm", Stable, &["sve2"]), + // FEAT_SVE2_SHA3 + ("sve2-sha3", Stable, &["sve2", "sha3"]), + // FEAT_SVE2_SM4 + ("sve2-sm4", Stable, &["sve2", "sm4"]), + // FEAT_SVE2p1 + ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]), + // FEAT_TME + ("tme", Stable, &[]), + ( + "v8.1a", + Unstable(sym::aarch64_ver_target_feature), + &["crc", "lse", "rdm", "pan", "lor", "vh"], + ), + ("v8.2a", Unstable(sym::aarch64_ver_target_feature), &["v8.1a", "ras", "dpb"]), + ( + "v8.3a", + Unstable(sym::aarch64_ver_target_feature), + &["v8.2a", "rcpc", "paca", "pacg", "jsconv"], + ), + ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]), + ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]), + ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]), + ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]), + ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]), + ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]), + ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]), + ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]), + ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]), + ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]), + ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]), + ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a"]), + // FEAT_VHE + ("vh", Stable, &[]), + // FEAT_WFxT + ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]), + // tidy-alphabetical-end +]; +static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("adx", Stable, &[]), + ("aes", Stable, &["sse2"]), + ("amx-avx512", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-bf16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-complex", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-fp8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-fp16", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-int8", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-movrs", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), + ("apxf", Unstable(sym::apx_target_feature), &[]), + ("avx", Stable, &["sse4.2"]), + ("avx2", Stable, &["avx"]), + ( + "avx10.1", + Unstable(sym::avx10_target_feature), + &[ + "avx512bf16", + "avx512bitalg", + "avx512bw", + "avx512cd", + "avx512dq", + "avx512f", + "avx512fp16", + "avx512ifma", + "avx512vbmi", + "avx512vbmi2", + "avx512vl", + "avx512vnni", + "avx512vpopcntdq", + ], + ), + ( + "avx10.2", + Unstable(sym::avx10_target_feature), + &["avx10.1", "avxvnni", "avxvnniint8", "avxvnniint16"], + ), + ("avx512bf16", Stable, &["avx512bw"]), + ("avx512bitalg", Stable, &["avx512bw"]), + ("avx512bw", Stable, &["avx512f"]), + ("avx512cd", Stable, &["avx512f"]), + ("avx512dq", Stable, &["avx512f"]), + ("avx512f", Stable, &["avx2", "fma", "f16c"]), + ("avx512fp16", Stable, &["avx512bw"]), + ("avx512ifma", Stable, &["avx512f"]), + ("avx512vbmi", Stable, &["avx512bw"]), + ("avx512vbmi2", Stable, &["avx512bw"]), + ("avx512vl", Stable, &["avx512f"]), + ("avx512vnni", Stable, &["avx512f"]), + ("avx512vp2intersect", Stable, &["avx512f"]), + ("avx512vpopcntdq", Stable, &["avx512f"]), + ("avxifma", Stable, &["avx2"]), + ("avxneconvert", Stable, &["avx2"]), + ("avxvnni", Stable, &["avx2"]), + ("avxvnniint8", Stable, &["avx2"]), + ("avxvnniint16", Stable, &["avx2"]), + ("bmi1", Stable, &[]), + ("bmi2", Stable, &[]), + ("clflushopt", Unstable(sym::clflushopt_target_feature), &[]), + ("cmpxchg16b", Stable, &[]), + ("ermsb", Unstable(sym::ermsb_target_feature), &[]), + ("f16c", Stable, &["avx"]), + ("fma", Stable, &["avx"]), + ("fma4", Unstable(sym::fma4_target_feature), &["avx", "sse4a"]), + ("fxsr", Stable, &[]), + ("gfni", Stable, &["sse2"]), + ("kl", Stable, &["sse2"]), + ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), + ("lzcnt", Stable, &[]), + ("movbe", Stable, &[]), + ("movdir64b", Unstable(sym::movdir64b_target_feature), &[]), + ("movdiri", Unstable(sym::movdiri_target_feature), &[]), + ("movrs", Unstable(sym::movrs_target_feature), &[]), + ("pclmulqdq", Stable, &["sse2"]), + ("popcnt", Stable, &[]), + ("prfchw", Unstable(sym::prfchw_target_feature), &[]), + ("rdrand", Stable, &[]), + ("rdseed", Stable, &[]), + ( + "retpoline-external-thunk", + // Not implied by any CPU model or other feature; the compiler flag is a target modifier. + Stability::InternalOnly { + reason: "use `-Zretpoline-external-thunk` compiler flag instead", + hard_error: false, + }, + &[], + ), + ( + "retpoline-indirect-branches", + // Not implied by any CPU model or other feature; the compiler flag is a target modifier. + Stability::InternalOnly { + reason: "use `-Zretpoline` compiler flag instead", + hard_error: false, + }, + &[], + ), + ( + "retpoline-indirect-calls", + // Not implied by any CPU model or other feature; the compiler flag is a target modifier. + Stability::InternalOnly { + reason: "use `-Zretpoline` compiler flag instead", + hard_error: false, + }, + &[], + ), + ("rtm", Unstable(sym::rtm_target_feature), &[]), + ("sha", Stable, &["sse2"]), + ("sha512", Stable, &["avx2"]), + ("sm3", Stable, &["avx"]), + ("sm4", Stable, &["avx2"]), + ( + "soft-float", + // Pinned down by [`Target::abi_required_features`]. + Stability::InternalOnly { reason: "use a soft-float target instead", hard_error: false }, + &[], + ), + ("sse", Stable, &[]), + ("sse2", Stable, &["sse"]), + ("sse3", Stable, &["sse2"]), + ("sse4.1", Stable, &["ssse3"]), + ("sse4.2", Stable, &["sse4.1"]), + ("sse4a", Stable, &["sse3"]), + ("ssse3", Stable, &["sse3"]), + ("tbm", Stable, &[]), + ("vaes", Stable, &["avx2", "aes"]), + ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), + ("widekl", Stable, &["kl"]), + ("x87", Unstable(sym::x87_target_feature), &[]), + ("xop", Unstable(sym::xop_target_feature), &["fma4", "avx", "sse4a"]), + ("xsave", Stable, &[]), + ("xsavec", Stable, &["xsave"]), + ("xsaveopt", Stable, &["xsave"]), + ("xsaves", Stable, &["xsave"]), + // tidy-alphabetical-end +]; +const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("audio", Unstable(sym::hexagon_target_feature), &[]), + ("hvx", Unstable(sym::hexagon_target_feature), &[]), + ("hvx-ieee-fp", Unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvx-length64b", Unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvx-qfloat", Unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvxv60", Unstable(sym::hexagon_target_feature), &["hvx"]), + ("hvxv62", Unstable(sym::hexagon_target_feature), &["hvxv60"]), + ("hvxv65", Unstable(sym::hexagon_target_feature), &["hvxv62"]), + ("hvxv66", Unstable(sym::hexagon_target_feature), &["hvxv65", "zreg"]), + ("hvxv67", Unstable(sym::hexagon_target_feature), &["hvxv66"]), + ("hvxv68", Unstable(sym::hexagon_target_feature), &["hvxv67"]), + ("hvxv69", Unstable(sym::hexagon_target_feature), &["hvxv68"]), + ("hvxv71", Unstable(sym::hexagon_target_feature), &["hvxv69"]), + ("hvxv73", Unstable(sym::hexagon_target_feature), &["hvxv71"]), + ("hvxv75", Unstable(sym::hexagon_target_feature), &["hvxv73"]), + ("hvxv79", Unstable(sym::hexagon_target_feature), &["hvxv75"]), + ("v60", Unstable(sym::hexagon_target_feature), &[]), + ("v62", Unstable(sym::hexagon_target_feature), &["v60"]), + ("v65", Unstable(sym::hexagon_target_feature), &["v62"]), + ("v66", Unstable(sym::hexagon_target_feature), &["v65"]), + ("v67", Unstable(sym::hexagon_target_feature), &["v66"]), + ("v68", Unstable(sym::hexagon_target_feature), &["v67"]), + ("v69", Unstable(sym::hexagon_target_feature), &["v68"]), + ("v71", Unstable(sym::hexagon_target_feature), &["v69"]), + ("v73", Unstable(sym::hexagon_target_feature), &["v71"]), + ("v75", Unstable(sym::hexagon_target_feature), &["v73"]), + ("v79", Unstable(sym::hexagon_target_feature), &["v75"]), + ("zreg", Unstable(sym::hexagon_target_feature), &[]), + // tidy-alphabetical-end +]; +static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // If you are thinking of adding "efpu2" here, please double-check that it really does not + // affect the ABI. + // tidy-alphabetical-start + ("altivec", Unstable(sym::powerpc_target_feature), &[]), + ( + "hard-float", + // Pinned down by [`Target::abi_required_features`]. + InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, + &[], + ), + ("msync", Unstable(sym::powerpc_target_feature), &[]), + ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), + ("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"]), + ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), + ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), + ( + "spe", + // Pinned down by [`Target::abi_required_features`]. + InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, + &[], + ), + ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), + // tidy-alphabetical-end +]; +const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("fp64", Unstable(sym::mips_target_feature), &[]), + // FIXME(#150253): msa requires either fp64 or no hard float support at all: LLVM requires fp64 + // FIXME(#150253): msa requires revision 5 or greater (mips32r5/mips64r5 in LLVM) + ("msa", Unstable(sym::mips_target_feature), &[]), + ("virt", Unstable(sym::mips_target_feature), &[]), + // tidy-alphabetical-end +]; +const NVPTX_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("sm_70", Unstable(sym::nvptx_target_feature), &[]), + ("sm_72", Unstable(sym::nvptx_target_feature), &["sm_70"]), + ("sm_75", Unstable(sym::nvptx_target_feature), &["sm_72"]), + ("sm_80", Unstable(sym::nvptx_target_feature), &["sm_75"]), + ("sm_86", Unstable(sym::nvptx_target_feature), &["sm_80"]), + ("sm_87", Unstable(sym::nvptx_target_feature), &["sm_86"]), + ("sm_89", Unstable(sym::nvptx_target_feature), &["sm_87"]), + ("sm_90", Unstable(sym::nvptx_target_feature), &["sm_89"]), + ("sm_90a", Unstable(sym::nvptx_target_feature), &["sm_90"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("sm_100", Unstable(sym::nvptx_target_feature), &["sm_90"]), + ("sm_100a", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101", Unstable(sym::nvptx_target_feature), &["sm_100"]), + ("sm_101a", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120", Unstable(sym::nvptx_target_feature), &["sm_101"]), + ("sm_120a", Unstable(sym::nvptx_target_feature), &["sm_120"]), + // tidy-alphabetical-end + // tidy-alphabetical-start + ("ptx70", Unstable(sym::nvptx_target_feature), &[]), + ("ptx71", Unstable(sym::nvptx_target_feature), &["ptx70"]), + ("ptx72", Unstable(sym::nvptx_target_feature), &["ptx71"]), + ("ptx73", Unstable(sym::nvptx_target_feature), &["ptx72"]), + ("ptx74", Unstable(sym::nvptx_target_feature), &["ptx73"]), + ("ptx75", Unstable(sym::nvptx_target_feature), &["ptx74"]), + ("ptx76", Unstable(sym::nvptx_target_feature), &["ptx75"]), + ("ptx77", Unstable(sym::nvptx_target_feature), &["ptx76"]), + ("ptx78", Unstable(sym::nvptx_target_feature), &["ptx77"]), + ("ptx80", Unstable(sym::nvptx_target_feature), &["ptx78"]), + ("ptx81", Unstable(sym::nvptx_target_feature), &["ptx80"]), + ("ptx82", Unstable(sym::nvptx_target_feature), &["ptx81"]), + ("ptx83", Unstable(sym::nvptx_target_feature), &["ptx82"]), + ("ptx84", Unstable(sym::nvptx_target_feature), &["ptx83"]), + ("ptx85", Unstable(sym::nvptx_target_feature), &["ptx84"]), + ("ptx86", Unstable(sym::nvptx_target_feature), &["ptx85"]), + ("ptx87", Unstable(sym::nvptx_target_feature), &["ptx86"]), + // tidy-alphabetical-end +]; +static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("a", Stable, &["zaamo", "zalrsc"]), + ("b", Stable, &["zba", "zbb", "zbs"]), + ("c", Stable, &["zca"]), + ("d", Stable, &["f"]), + ("e", Unstable(sym::riscv_target_feature), &[]), // negative feature! needs special care. + ("f", Stable, &["zicsr"]), + ( + "forced-atomics", + // Not implied by any CPU model or other feature. + Stability::InternalOnly { + reason: "unsound because it changes the ABI of atomic operations", + hard_error: false, + }, + &[], + ), + // According to the RISC-V spec, the M ISA extension (integer multiplication/division) is supported only when the M bit + // of the misa register is 1, while Zmmul means integer multiplication is always supported. + // + // The Rust/LLVM "m" target feature means something slightly different: with "m" enabled, it is assumed that integer + // multiplication and division will always be available (M bit will be 1 in misa), so "m" implies "zmmul". + // + // See discussion in the PR adding Zmmul: https://github.com/rust-lang/rust/pull/162552 + ("m", Stable, &["zmmul"]), + ("relax", Unstable(sym::riscv_target_feature), &[]), + ( + "rva23u64", + Unstable(sym::riscv_target_feature), + &[ + "m", + "a", + "f", + "d", + "c", + "b", + "v", + "zicsr", + "zicntr", + "zihpm", + "ziccif", + "ziccrse", + "ziccamoa", + "zicclsm", + "zic64b", + "za64rs", + "zihintpause", + "zba", + "zbb", + "zbs", + "zicbom", + "zicbop", + "zicboz", + "zfhmin", + "zkt", + "zvfhmin", + "zvbb", + "zvkt", + "zihintntl", + "zicond", + "zimop", + "zcmop", + "zcb", + "zfa", + "zawrs", + "supm", + ], + ), + ("supm", Unstable(sym::riscv_target_feature), &[]), + ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), + ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), + ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), + ("za64rs", Stable, &["za128rs"]), // Za64rs ⊃ Za128rs + ("za128rs", Stable, &[]), + ("zaamo", Stable, &[]), + ("zabha", Stable, &["zaamo"]), + ("zacas", Stable, &["zaamo"]), + ("zalrsc", Stable, &[]), + ("zama16b", Stable, &[]), + ("zawrs", Stable, &[]), + ("zba", Stable, &[]), + ("zbb", Stable, &[]), + ("zbc", Stable, &["zbkc"]), // Zbc ⊃ Zbkc + ("zbkb", Stable, &[]), + ("zbkc", Stable, &[]), + ("zbkx", Stable, &[]), + ("zbs", Stable, &[]), + ("zca", Stable, &[]), + ("zcb", Stable, &["zca"]), + ("zcmop", Stable, &["zca"]), + ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zfa", Unstable(sym::riscv_target_feature), &["f"]), + ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin + ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), + ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), + ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), + ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), + ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zic64b", Stable, &[]), + ("zicbom", Stable, &[]), + ("zicbop", Stable, &[]), + ("zicboz", Stable, &[]), + ("ziccamoa", Stable, &[]), + ("ziccif", Stable, &[]), + ("zicclsm", Stable, &[]), + ("ziccrse", Stable, &[]), + ("zicntr", Stable, &["zicsr"]), + ("zicond", Stable, &[]), + ("zicsr", Stable, &[]), + ("zifencei", Stable, &[]), + ("zihintntl", Stable, &[]), + ("zihintpause", Stable, &[]), + ("zihpm", Stable, &["zicsr"]), + ("zimop", Stable, &[]), + ("zk", Stable, &["zkn", "zkr", "zkt"]), + ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]), + ("zknd", Stable, &["zkne_or_zknd"]), + ("zkne", Stable, &["zkne_or_zknd"]), + ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension + ("zknh", Stable, &[]), + ("zkr", Stable, &[]), + ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]), + ("zksed", Stable, &[]), + ("zksh", Stable, &[]), + ("zkt", Stable, &[]), + ("zmmul", Unstable(sym::riscv_target_feature), &[]), + ("ztso", Stable, &[]), + ("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]), // Zvbb ⊃ Zvkb + ("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]), + ("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]), + ("zve32x", Unstable(sym::riscv_target_feature), &["zvl32b", "zicsr"]), + ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), + ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), + ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), + ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), + ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin + ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkg", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkn", Unstable(sym::riscv_target_feature), &["zvkned", "zvknhb", "zvkb", "zvkt"]), + ("zvknc", Unstable(sym::riscv_target_feature), &["zvkn", "zvbc"]), + ("zvkned", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkng", Unstable(sym::riscv_target_feature), &["zvkn", "zvkg"]), + ("zvknha", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvknhb", Unstable(sym::riscv_target_feature), &["zvknha", "zve64x"]), // Zvknhb ⊃ Zvknha + ("zvks", Unstable(sym::riscv_target_feature), &["zvksed", "zvksh", "zvkb", "zvkt"]), + ("zvksc", Unstable(sym::riscv_target_feature), &["zvks", "zvbc"]), + ("zvksed", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvksg", Unstable(sym::riscv_target_feature), &["zvks", "zvkg"]), + ("zvksh", Unstable(sym::riscv_target_feature), &["zve32x"]), + ("zvkt", Unstable(sym::riscv_target_feature), &[]), + ("zvl32b", Unstable(sym::riscv_target_feature), &[]), + ("zvl64b", Unstable(sym::riscv_target_feature), &["zvl32b"]), + ("zvl128b", Unstable(sym::riscv_target_feature), &["zvl64b"]), + ("zvl256b", Unstable(sym::riscv_target_feature), &["zvl128b"]), + ("zvl512b", Unstable(sym::riscv_target_feature), &["zvl256b"]), + ("zvl1024b", Unstable(sym::riscv_target_feature), &["zvl512b"]), + ("zvl2048b", Unstable(sym::riscv_target_feature), &["zvl1024b"]), + ("zvl4096b", Unstable(sym::riscv_target_feature), &["zvl2048b"]), + ("zvl8192b", Unstable(sym::riscv_target_feature), &["zvl4096b"]), + ("zvl16384b", Unstable(sym::riscv_target_feature), &["zvl8192b"]), + ("zvl32768b", Unstable(sym::riscv_target_feature), &["zvl16384b"]), + ("zvl65536b", Unstable(sym::riscv_target_feature), &["zvl32768b"]), + // tidy-alphabetical-end +]; +static WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("atomics", Unstable(sym::wasm_target_feature), &[]), + ("bulk-memory", Stable, &[]), + ("exception-handling", Unstable(sym::wasm_target_feature), &[]), + ("extended-const", Stable, &[]), + ("gc", Unstable(sym::wasm_target_feature), &["reference-types"]), + ("multivalue", Stable, &[]), + ("mutable-globals", Stable, &[]), + ("nontrapping-fptoint", Stable, &[]), + ("reference-types", Stable, &[]), + ("relaxed-simd", Stable, &["simd128"]), + ("sign-ext", Stable, &[]), + ("simd128", Stable, &[]), + ("tail-call", Stable, &[]), + ("wide-arithmetic", Stable, &[]), + // tidy-alphabetical-end +]; +const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + ("alu32", Unstable(sym::bpf_target_feature), &[]), + ("allows-misaligned-mem-access", Unstable(sym::bpf_target_feature), &[]), +]; +static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("2e3", Unstable(sym::csky_target_feature), &["e2"]), + ("3e3r1", Unstable(sym::csky_target_feature), &[]), + ("3e3r2", Unstable(sym::csky_target_feature), &["3e3r1", "doloop"]), + ("3e3r3", Unstable(sym::csky_target_feature), &["doloop"]), + ("3e7", Unstable(sym::csky_target_feature), &["2e3"]), + ("7e10", Unstable(sym::csky_target_feature), &["3e7"]), + ("10e60", Unstable(sym::csky_target_feature), &["7e10"]), + ("cache", Unstable(sym::csky_target_feature), &[]), + ("doloop", Unstable(sym::csky_target_feature), &[]), + ("dsp1e2", Unstable(sym::csky_target_feature), &[]), + ("dspe60", Unstable(sym::csky_target_feature), &[]), + ("e1", Unstable(sym::csky_target_feature), &["elrw"]), + ("e2", Unstable(sym::csky_target_feature), &["e2"]), + ("edsp", Unstable(sym::csky_target_feature), &[]), + ("elrw", Unstable(sym::csky_target_feature), &[]), + ("float1e2", Unstable(sym::csky_target_feature), &[]), + ("float1e3", Unstable(sym::csky_target_feature), &[]), + ("float3e4", Unstable(sym::csky_target_feature), &[]), + ("float7e60", Unstable(sym::csky_target_feature), &[]), + ("floate1", Unstable(sym::csky_target_feature), &[]), + ("hard-tp", Unstable(sym::csky_target_feature), &[]), + ("high-registers", Unstable(sym::csky_target_feature), &[]), + ("hwdiv", Unstable(sym::csky_target_feature), &[]), + ("mp", Unstable(sym::csky_target_feature), &["2e3"]), + ("mp1e2", Unstable(sym::csky_target_feature), &["3e7"]), + ("nvic", Unstable(sym::csky_target_feature), &[]), + ("trust", Unstable(sym::csky_target_feature), &[]), + ("vdsp2e60f", Unstable(sym::csky_target_feature), &[]), + ("vdspv1", Unstable(sym::csky_target_feature), &[]), + ("vdspv2", Unstable(sym::csky_target_feature), &[]), + // tidy-alphabetical-end + //fpu + // tidy-alphabetical-start + ("fdivdu", Unstable(sym::csky_target_feature), &[]), + ("fpuv2_df", Unstable(sym::csky_target_feature), &[]), + ("fpuv2_sf", Unstable(sym::csky_target_feature), &[]), + ("fpuv3_df", Unstable(sym::csky_target_feature), &[]), + ("fpuv3_hf", Unstable(sym::csky_target_feature), &[]), + ("fpuv3_hi", Unstable(sym::csky_target_feature), &[]), + ("fpuv3_sf", Unstable(sym::csky_target_feature), &[]), + ("hard-float", Unstable(sym::csky_target_feature), &[]), + ("hard-float-abi", Unstable(sym::csky_target_feature), &[]), + // tidy-alphabetical-end +]; +static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("32s", Unstable(sym::loongarch_target_feature), &[]), + ("d", Stable, &["f"]), + ("div32", Stable, &[]), + ("f", Stable, &[]), + ("frecipe", Stable, &[]), + ("lam-bh", Stable, &[]), + ("lamcas", Stable, &[]), + ("lasx", Stable, &["lsx"]), + ("lbt", Stable, &[]), + ("ld-seq-sa", Stable, &[]), + ("lsx", Stable, &["d"]), + ("lvz", Stable, &[]), + ("relax", Unstable(sym::loongarch_target_feature), &[]), + ("scq", Stable, &[]), + ("ual", Unstable(sym::loongarch_target_feature), &[]), + // tidy-alphabetical-end +]; +const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + // For "backchain", https://github.com/rust-lang/rust/issues/142412 is a stabilization blocker + ("backchain", Unstable(sym::s390x_target_feature), &[]), + ("concurrent-functions", Unstable(sym::s390x_target_feature), &[]), + ("deflate-conversion", Unstable(sym::s390x_target_feature), &[]), + ("enhanced-sort", Unstable(sym::s390x_target_feature), &[]), + ("guarded-storage", Unstable(sym::s390x_target_feature), &[]), + ("high-word", Unstable(sym::s390x_target_feature), &[]), + // LLVM does not define message-security-assist-extension versions 1, 2, 6, 10 and 11. + ("message-security-assist-extension3", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension4", Unstable(sym::s390x_target_feature), &[]), + ("message-security-assist-extension5", Unstable(sym::s390x_target_feature), &[]), + ( + "message-security-assist-extension8", + Unstable(sym::s390x_target_feature), + &["message-security-assist-extension3"], + ), + ( + "message-security-assist-extension9", + Unstable(sym::s390x_target_feature), + &["message-security-assist-extension3", "message-security-assist-extension4"], + ), + ("message-security-assist-extension12", Unstable(sym::s390x_target_feature), &[]), + ("miscellaneous-extensions-2", Stable, &[]), + ("miscellaneous-extensions-3", Stable, &[]), + ("miscellaneous-extensions-4", Stable, &[]), + ("nnp-assist", Stable, &["vector"]), + // Pinned down by [`Target::abi_required_features`]. + ( + "soft-float", + InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, + &[], + ), + ("transactional-execution", Unstable(sym::s390x_target_feature), &[]), + ("vector", Stable, &[]), + ("vector-enhancements-1", Stable, &["vector"]), + ("vector-enhancements-2", Stable, &["vector-enhancements-1"]), + ("vector-enhancements-3", Stable, &["vector-enhancements-2"]), + ("vector-packed-decimal", Stable, &["vector"]), + ("vector-packed-decimal-enhancement", Stable, &["vector-packed-decimal"]), + ("vector-packed-decimal-enhancement-2", Stable, &["vector-packed-decimal-enhancement"]), + ("vector-packed-decimal-enhancement-3", Stable, &["vector-packed-decimal-enhancement-2"]), + // tidy-alphabetical-end +]; +const SPARC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("leoncasa", Unstable(sym::sparc_target_feature), &[]), + ( + "soft-float", + InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false }, + &[], + ), + ("v8plus", Unstable(sym::sparc_target_feature), &[]), + // FIXME: It's unclear what this feature means when `v8plus` is disabled on 32-bit SPARC. See + // the discussion around https://github.com/rust-lang/rust/pull/160949#discussion_r3806194355. + ("v9", Unstable(sym::sparc_target_feature), &[]), + // tidy-alphabetical-end +]; +static M68K_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("isa-68000", Unstable(sym::m68k_target_feature), &[]), + ("isa-68010", Unstable(sym::m68k_target_feature), &["isa-68000"]), + ("isa-68020", Unstable(sym::m68k_target_feature), &["isa-68010"]), + ("isa-68030", Unstable(sym::m68k_target_feature), &["isa-68020"]), + ("isa-68040", Unstable(sym::m68k_target_feature), &["isa-68030", "isa-68882"]), + ("isa-68060", Unstable(sym::m68k_target_feature), &["isa-68040"]), + // FPU + ("isa-68881", Unstable(sym::m68k_target_feature), &[]), + ("isa-68882", Unstable(sym::m68k_target_feature), &["isa-68881"]), + // tidy-alphabetical-end +]; +static AVR_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + // tidy-alphabetical-start + ("addsubiw", Unstable(sym::avr_target_feature), &[]), + ("break", Unstable(sym::avr_target_feature), &[]), + ("eijmpcall", Unstable(sym::avr_target_feature), &[]), + ("elpm", Unstable(sym::avr_target_feature), &[]), + ("elpmx", Unstable(sym::avr_target_feature), &[]), + ("ijmpcall", Unstable(sym::avr_target_feature), &[]), + ("jmpcall", Unstable(sym::avr_target_feature), &[]), + ("lowbytefirst", Unstable(sym::avr_target_feature), &[]), + ("lpm", Unstable(sym::avr_target_feature), &[]), + ("lpmx", Unstable(sym::avr_target_feature), &[]), + ("movw", Unstable(sym::avr_target_feature), &[]), + ("mul", Unstable(sym::avr_target_feature), &[]), + ("rmw", Unstable(sym::avr_target_feature), &[]), + ("spm", Unstable(sym::avr_target_feature), &[]), + ("spmx", Unstable(sym::avr_target_feature), &[]), + ( + "sram", + // Pinned down by [`Target::abi_required_features`]. + InternalOnly { reason: "devices that have no SRAM are unsupported", hard_error: false }, + &[], + ), + ("tinyencoding", Unstable(sym::avr_target_feature), &[]), + // tidy-alphabetical-end +]; +const XTENSA_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ + ("bool", Unstable(sym::xtensa_target_feature), &[]), + ("fp", Unstable(sym::xtensa_target_feature), &["bool", "coprocessor"]), + ("coprocessor", Unstable(sym::xtensa_target_feature), &[]), + ("highpriinterrupts", Unstable(sym::xtensa_target_feature), &["interrupt"]), + ("interrupt", Unstable(sym::xtensa_target_feature), &["exception"]), + ( + "windowed", + // Pinned down by [`Target::abi_required_features`]. + InternalOnly { + reason: "windowed changes the Xtensa calling convention", + hard_error: false, + }, + &["exception"], + ), + ("loop", Unstable(sym::xtensa_target_feature), &[]), + ("sext", Unstable(sym::xtensa_target_feature), &[]), + ("nsa", Unstable(sym::xtensa_target_feature), &[]), + ("mul32", Unstable(sym::xtensa_target_feature), &[]), + ("mul32high", Unstable(sym::xtensa_target_feature), &["mul32"]), + ("div32", Unstable(sym::xtensa_target_feature), &[]), + ("mac16", Unstable(sym::xtensa_target_feature), &[]), + ("s32c1i", Unstable(sym::xtensa_target_feature), &[]), + ("threadptr", Unstable(sym::xtensa_target_feature), &[]), + ("extendedl32r", Unstable(sym::xtensa_target_feature), &[]), + ("debug", Unstable(sym::xtensa_target_feature), &["exception"]), + ("exception", Unstable(sym::xtensa_target_feature), &[]), + ("rvector", Unstable(sym::xtensa_target_feature), &["exception"]), + ("prid", Unstable(sym::xtensa_target_feature), &[]), + ("regprotect", Unstable(sym::xtensa_target_feature), &[]), + ("miscsr", Unstable(sym::xtensa_target_feature), &[]), +]; +pub(super) const TARGET_FEATURE_IMPLICATIONS_RAW: &[&[(&str, Stability, ImpliedFeatures)]] = &[ + ARM_FEATURES, + AARCH64_FEATURES, + X86_FEATURES, + HEXAGON_FEATURES, + POWERPC_FEATURES, + MIPS_FEATURES, + NVPTX_FEATURES, + RISCV_FEATURES, + WASM_FEATURES, + BPF_FEATURES, + CSKY_FEATURES, + LOONGARCH_FEATURES, + IBMZ_FEATURES, + SPARC_FEATURES, + M68K_FEATURES, + AVR_FEATURES, + XTENSA_FEATURES, +]; + +#[expect(non_upper_case_globals, reason = "stubs for rustc_target")] +mod sym { + pub(in super::super) const aarch64_unstable_target_feature: () = (); + pub(in super::super) const aarch64_ver_target_feature: () = (); + pub(in super::super) const apx_target_feature: () = (); + pub(in super::super) const arm_target_feature: () = (); + pub(in super::super) const avr_target_feature: () = (); + pub(in super::super) const avx10_target_feature: () = (); + pub(in super::super) const bpf_target_feature: () = (); + pub(in super::super) const clflushopt_target_feature: () = (); + pub(in super::super) const csky_target_feature: () = (); + pub(in super::super) const ermsb_target_feature: () = (); + pub(in super::super) const fma4_target_feature: () = (); + pub(in super::super) const hexagon_target_feature: () = (); + pub(in super::super) const lahfsahf_target_feature: () = (); + pub(in super::super) const loongarch_target_feature: () = (); + pub(in super::super) const m68k_target_feature: () = (); + pub(in super::super) const mips_target_feature: () = (); + pub(in super::super) const movdir64b_target_feature: () = (); + pub(in super::super) const movdiri_target_feature: () = (); + pub(in super::super) const movrs_target_feature: () = (); + pub(in super::super) const nvptx_target_feature: () = (); + pub(in super::super) const powerpc_target_feature: () = (); + pub(in super::super) const prfchw_target_feature: () = (); + pub(in super::super) const riscv_target_feature: () = (); + pub(in super::super) const rtm_target_feature: () = (); + pub(in super::super) const s390x_target_feature: () = (); + pub(in super::super) const sparc_target_feature: () = (); + pub(in super::super) const wasm_target_feature: () = (); + pub(in super::super) const x86_amx_intrinsics: () = (); + pub(in super::super) const x87_target_feature: () = (); + pub(in super::super) const xop_target_feature: () = (); + pub(in super::super) const xtensa_target_feature: () = (); +} +// spellchecker:on diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs index f8a7f1875539a..d4720accc54dd 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen.rs @@ -16,6 +16,7 @@ pub(crate) mod feature_docs; mod grammar; mod lints; mod parser_inline_tests; +mod target_features; impl flags::Codegen { pub(crate) fn run(self, _sh: &Shell) -> anyhow::Result<()> { @@ -26,8 +27,10 @@ impl flags::Codegen { parser_inline_tests::generate(self.check); feature_docs::generate(self.check); diagnostics_docs::generate(self.check); - // lints::generate(self.check) Updating clones the rust repo, so don't run it unless + // Updating clones the rust repo, so don't run these unless // explicitly asked for + // lints::generate(self.check); + // target_features::generate(self.check); } flags::CodegenType::Grammar => grammar::generate(self.check), flags::CodegenType::AssistsDocTests => assists_doc_tests::generate(self.check), @@ -35,6 +38,7 @@ impl flags::Codegen { flags::CodegenType::LintDefinitions => lints::generate(self.check), flags::CodegenType::ParserTests => parser_inline_tests::generate(self.check), flags::CodegenType::FeatureDocs => feature_docs::generate(self.check), + flags::CodegenType::TargetFeatures => target_features::generate(self.check), } Ok(()) } @@ -218,3 +222,24 @@ fn ensure_file_contents(cg: CodegenType, file: &Path, contents: &str, check: boo fn normalize_newlines(s: &str) -> String { s.replace("\r\n", "\n") } + +/// Performs a shallow clone of rust-lang/rust and returns the path to the cloned repository root +fn clone_rust(sh: &Shell) -> PathBuf { + let rust_repo = project_root().join("./target/rust"); + if rust_repo.exists() { + cmd!(sh, "git -C {rust_repo} pull --rebase").run().unwrap(); + } else { + cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}") + .run() + .unwrap(); + } + // need submodules for Cargo to parse the workspace correctly + cmd!( + sh, + "git -C {rust_repo} submodule update --init --recursive --depth=1 -- + compiler library src/tools src/doc/book" + ) + .run() + .unwrap(); + rust_repo +} diff --git a/src/tools/rust-analyzer/xtask/src/codegen/lints.rs b/src/tools/rust-analyzer/xtask/src/codegen/lints.rs index e4eddc5f9f6ba..bd568f19b1702 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/lints.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/lints.rs @@ -13,7 +13,7 @@ use stdx::format_to; use xshell::{Shell, cmd}; use crate::{ - codegen::{add_preamble, ensure_file_contents, reformat}, + codegen::{add_preamble, clone_rust, ensure_file_contents, reformat}, project_root, util::list_files, }; @@ -23,23 +23,7 @@ const DESTINATION: &str = "crates/ide-db/src/generated/lints.rs"; /// This clones rustc repo, and so is not worth to keep up-to-date on a constant basis. pub(crate) fn generate(check: bool) { let sh = &Shell::new().unwrap(); - - let rust_repo = project_root().join("./target/rust"); - if rust_repo.exists() { - cmd!(sh, "git -C {rust_repo} pull --rebase").run().unwrap(); - } else { - cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}") - .run() - .unwrap(); - } - // need submodules for Cargo to parse the workspace correctly - cmd!( - sh, - "git -C {rust_repo} submodule update --init --recursive --depth=1 -- - compiler library src/tools src/doc/book" - ) - .run() - .unwrap(); + let rust_repo = clone_rust(sh); let mut contents = String::from( r" diff --git a/src/tools/rust-analyzer/xtask/src/codegen/target_features.rs b/src/tools/rust-analyzer/xtask/src/codegen/target_features.rs new file mode 100644 index 0000000000000..325eecf2a4578 --- /dev/null +++ b/src/tools/rust-analyzer/xtask/src/codegen/target_features.rs @@ -0,0 +1,110 @@ +//! Extracts the list of target feature implications from rustc_target to a generated file that rust-analyzer can use for implications. + +use std::{collections::BTreeSet, fs, iter::repeat}; + +use itertools::Itertools; +use xshell::Shell; + +use crate::{ + codegen::{add_preamble, clone_rust, ensure_file_contents, reformat}, + project_root, +}; + +const DESTINATION: &str = "crates/hir-ty/src/target_feature/generated.rs"; + +/// This clones the rust repo, and so is not worth to keep up-to-date on a constant basis. +pub(crate) fn generate(check: bool) { + let sh = &Shell::new().unwrap(); + let rust_repo = clone_rust(sh); + let rustc_target_contents = + fs::read_to_string(rust_repo.join("compiler/rustc_target/src/target_features.rs")).unwrap(); + + let mut contents = String::from( + r#" +// spellchecker:off + +#[expect(dead_code, reason = "stubs for rustc_target")] +pub(super) enum Stability { + Stable, + Unstable(()), + InternalOnly { reason: &'static str, hard_error: bool }, +} +use Stability::*; + +type ImpliedFeatures = &'static [&'static str]; + "#, + ); + + // Identifiers of all _FEATURES arrays in rustc_target + let mut array_names = vec![]; + // Identifiers of all Unstable(sym::) feature gates + let mut unstable_feature_gates = BTreeSet::new(); + + // Whether or not the line iterator is currently in the middle of a feature list array + let mut currently_in_feature_list = false; + // Go through the file and do some manual parsing to keep only the lines that are part of a target feature array. + let target_feature_arrays = rustc_target_contents + .lines() + .filter(|line| { + if line.contains("&[(&str, Stability, ImpliedFeatures)]") { + // Start of a new feature list + assert!(!currently_in_feature_list); + currently_in_feature_list = true; + array_names.push(extract_list_ident_to_array_entry(line).unwrap()); + } else if currently_in_feature_list && *line == "];" { + // This is the end of a feature list, so ignore all lines after this one until the start of the next feature list + currently_in_feature_list = false; + return true; + } + + if currently_in_feature_list { + // Keep this line and maybe create a stub feature gate + unstable_feature_gates.extend(extract_to_unstable_feature_gate(line)); + true + } else { + false + } + }) + .interleave_shortest(repeat("\n")); + contents.extend(target_feature_arrays); + + let mut implications_raw = String::from( + "pub(super) const TARGET_FEATURE_IMPLICATIONS_RAW: &[&[(&str, Stability, ImpliedFeatures)]] = &[\n", + ); + implications_raw.extend(array_names); + implications_raw.push_str("];\n"); + contents.push_str(&implications_raw); + + let mut sym = String::from( + r#" +#[expect(non_upper_case_globals, reason = "stubs for rustc_target")] +mod sym { +"#, + ); + sym.extend(unstable_feature_gates); + sym.push_str("}\n// spellchecker:on\n"); + contents.push_str(&sym); + + let contents = add_preamble(crate::flags::CodegenType::TargetFeatures, reformat(contents)); + + let destination = project_root().join(DESTINATION); + ensure_file_contents( + crate::flags::CodegenType::TargetFeatures, + destination.as_path(), + &contents, + check, + ); +} + +/// Extract the identifier of a feature list `const $ARCH_FEATURES:` or `static $ARCH_FEATURES:` to a list entry `$ARCH_FEATURES,` +fn extract_list_ident_to_array_entry(line: &str) -> Option { + let ident = line.split_once(' ')?.1.split_once(':')?.0; + Some(format!("{ident},\n")) +} + +/// Extract the identifier from `Unstable(sym::$IDENT)` and create a new mock identifier with it +fn extract_to_unstable_feature_gate(line: &str) -> Option { + let ident = line.split_once("Unstable(sym::")?.1.split_once(')')?.0; + + Some(format!("pub(in super::super) const {ident}: () = ();\n")) +} diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs index ecf38666934a0..f6040eaf68c51 100644 --- a/src/tools/rust-analyzer/xtask/src/flags.rs +++ b/src/tools/rust-analyzer/xtask/src/flags.rs @@ -210,6 +210,7 @@ pub enum CodegenType { LintDefinitions, ParserTests, FeatureDocs, + TargetFeatures, } impl fmt::Display for CodegenType { @@ -222,6 +223,7 @@ impl fmt::Display for CodegenType { Self::LintDefinitions => write!(f, "lint-definitions"), Self::ParserTests => write!(f, "parser-tests"), Self::FeatureDocs => write!(f, "feature-docs"), + Self::TargetFeatures => write!(f, "target-features"), } } } @@ -237,6 +239,7 @@ impl FromStr for CodegenType { "lint-definitions" => Ok(Self::LintDefinitions), "parser-tests" => Ok(Self::ParserTests), "feature-docs" => Ok(Self::FeatureDocs), + "target-features" => Ok(Self::TargetFeatures), _ => Err("Invalid option".to_owned()), } } From fb8c23e4d858dc1c7b84b405234a23d0e1e841ea Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 22 Oct 2026 20:42:43 +0300 Subject: [PATCH 20/27] Fix status message for clients not supporting `experimental/serverStatusNotification` --- src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index a9759ebed0cf9..5b5f49529fe3c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -821,7 +821,7 @@ impl GlobalState { fn update_status_or_notify(&mut self) { let status = self.current_status(); if self.last_reported_status != status { - self.last_reported_status = status.clone(); + let old_status = std::mem::replace(&mut self.last_reported_status, status.clone()); if self.config.server_status_notification() { self.send_notification::(status); @@ -829,7 +829,7 @@ impl GlobalState { health @ (lsp_ext::Health::Warning | lsp_ext::Health::Error), Some(message), ) = (status.health, &status.message) - && self.last_reported_status.message != status.message + && old_status.message != status.message { let open_log_button = tracing::enabled!(tracing::Level::ERROR) && (self.fetch_build_data_error().is_err() From 4d60702756085e4e07e2182a7e075051aa61bf09 Mon Sep 17 00:00:00 2001 From: Martin Braenne Date: Tue, 20 Oct 2026 10:03:07 +0200 Subject: [PATCH 21/27] fix: Fix `fetch_semantic` logic bug introduced in rust-lang/rust-analyzer#22272. The intent of rust-lang/rust-analyzer#22272 was to change `fetch_semantic` so that semantic diagnostics would only be fetched when build data has been fetched and proc macros have been loaded. Unfortunately, rust-lang/rust-analyzer#22272 contained a logic error: It queried `fetch_build_data_queue.last_op_result()` and `fetch_proc_macros_queue.last_op_result()` with `is_none()` instead of `is_some()`. The result of this is that LSP clients that use push diagnostics no longer got semantic diagnostics once build data had been fetched or proc macros had been loaded (if either the `run_build_scripts` or `fetch_proc_macros` config settings were enabled). Pull diagnostics don't call into `update_diagnostics()`, so clients using pull diagnostics were not affected. I was surprised that this bug appears to have gone unnoticed for ~5 months. (I searched to see if there is an open github issue but couldn't find one.) I assume this is because of a combination of the following: 1. Many editors / IDEs use pull diagnostics and hence aren't affected. 2. Editors / IDEs that do use push diagnostics usually have `checkOnSave` enabled, so users see diagnostics from flycheck and it isn't apparent that rust-analyzer's native diagnostics aren't being shown. 3. AFAICT, all of the existing tests for diagnostics are in crates/rust-analyzer/tests/slow-tests/flycheck.rs; these test flycheck diagnostics and therefore, again, do not trigger the bug. (This PR adds a test that does trigger the bug.) I hit this bug because I use a custom rust-analyzer integration that uses push diagnostics and runs in a non-Cargo (rust-project.json) environment, so `checkOnSave` is turned off. This PR conforms with rust-analyzer's [AI policy](AI_POLICY.md): * I used an AI agent to find the bug, fix it, and write the test. * I traced the mechanics of the bug through the rust-analyzer source code until I was satisfied that I understood the root cause and the fix. * I wrote this entire PR description myself. --- .../crates/rust-analyzer/src/main_loop.rs | 4 +- .../rust-analyzer/tests/slow-tests/main.rs | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index a9759ebed0cf9..ce1d8d5ef0ffa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -719,10 +719,10 @@ impl GlobalState { let fetch_semantic = self.vfs_done && self.fetch_workspaces_queue.last_op_result().is_some() && (!self.config.run_build_scripts(None) - || (self.fetch_build_data_queue.last_op_result().is_none() + || (self.fetch_build_data_queue.last_op_result().is_some() && !self.fetch_build_data_queue.op_in_progress())) && (!self.config.expand_proc_macros() - || (self.fetch_proc_macros_queue.last_op_result().is_none() + || (self.fetch_proc_macros_queue.last_op_result().is_some() && !self.fetch_proc_macros_queue.op_in_progress())); move |sender| { // We aren't observing the semantics token cache here diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 8a3ea34394a31..3ad39c50ec60e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -1681,3 +1681,57 @@ fn test() { assert_eq!(arr.len(), 1); expect![[r#"{"goal":"Goal { param_env: ParamEnv { clauses: [] }, predicate: Binder { value: TraitPredicate(usize: Trait, polarity:Positive), bound_vars: [] } }","result":"Err(NoSolution)","depth":0,"candidates":[]}"#]].assert_eq(&arr[0].to_string()); } + +#[test] +fn test_push_semantic_diagnostics() { + if skip_slow_tests() { + return; + } + + let code = r#" +fn main() { + let _: i32 = true; +} +"#; + let server = Project::with_fixture(&format!( + r#" +//- /Cargo.toml +[package] +name = "foo" +version = "0.0.0" + +//- /src/main.rs +{code}"# + )) + .with_config(serde_json::json!({ + "cargo": { + "buildScripts": { + "enable": true, + }, + }, + "procMacro": { + "enable": true, + }, + })) + .server() + .wait_until_workspace_is_loaded(); + + server.notification::(DidOpenTextDocumentParams { + text_document: TextDocumentItem { + uri: server.doc_id("src/main.rs").uri, + language_id: LanguageKind::Rust, + version: 0, + text: code.to_owned(), + }, + }); + + let diagnostics = server.wait_for_diagnostics(); + assert!( + diagnostics.diagnostics.iter().any(|d| matches!( + &d.message, + lsp_types::Message::String(s) if s.contains("expected i32, found bool") + )), + "expected type mismatch diagnostic, got: {:?}", + diagnostics.diagnostics, + ); +} From c4a7cdf19f2ca2f4ec57e792f51f8f3178bed593 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 25 Sep 2026 16:12:12 +1000 Subject: [PATCH 22/27] Remove `Default` impl for `SpanData` It's unused and there's no real reason for it to exist. --- compiler/rustc_span/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 914cb6f02b577..858892d1134f1 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -733,12 +733,6 @@ impl SpanData { } } -impl Default for SpanData { - fn default() -> Self { - Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None } - } -} - impl Span { #[inline] pub fn lo(self) -> BytePos { From adfda591cbbf681f937d542551030995cd44d5ca Mon Sep 17 00:00:00 2001 From: Yash Aggarwal <68061195+yashaggarwal85d@users.noreply.github.com> Date: Mon, 26 Oct 2026 03:44:46 +0000 Subject: [PATCH 23/27] Use the updated buffer length in UEFI locate_handles --- library/std/src/sys/pal/uefi/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 9db72db606779..35ef6166fd8c6 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -81,7 +81,7 @@ pub(crate) fn locate_handles(mut guid: Guid) -> io::Result { // This is safe because the call will succeed only if buf_len >= required length. // Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written - unsafe { buf.set_len(num_of_handles) }; + unsafe { buf.set_len(buf_len / size_of::()) }; Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect()) } Err(e) => Err(e), From 60196fa4c1095484b9cf05448f48cd147ea7b2e0 Mon Sep 17 00:00:00 2001 From: Web4everyone32 Date: Mon, 26 Oct 2026 11:35:25 +0530 Subject: [PATCH 24/27] uefi: roll back env changes when `start_image` fails `process::output` on UEFI applies the child's environment changes to the process-global UEFI environment and restores them after `start_image`. If `start_image` returned an error, the `?` returned early before the rollback ran, leaking the child's variables (e.g. `path`) into the parent. Restore the environment unconditionally and only then propagate the error. --- library/std/src/sys/process/uefi.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 8c233a0d2024e..2c7b5882f234b 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -195,9 +195,9 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec } } - let stat = cmd.start_image()?; + let stat = cmd.start_image(); - // Rollback any env changes + // Rollback any env changes, even if the image failed to start if let Some(e) = env { for (k, (v, _)) in e { match v { @@ -207,6 +207,8 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec } } + let stat = stat?; + let stdout = cmd.stdout()?; let stderr = cmd.stderr()?; From 7b5a4b39f684104b5ae40821896c6bace10e4ef9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Oct 2026 12:30:14 +1000 Subject: [PATCH 25/27] Remove unnecessary `Span::{data,data_untracked}` calls It's best to use `Span` methods because `SpanData` is mostly an internal detail, and to avoid unnecessary `SPAN_TRACK` calls. In the following cases, removing the `data()` gives identical behaviour: - `span.data().lo` --> `span.lo()` - `span.data().hi` --> `span.hi()` - `span.data().lo` + `span.data().hi` --> `span.lo_hi()` In the following case, removing the `data_untracked()` gives identical behaviour: - `span.data_untracked().parent` --> `span.parent()` In the following case, removing the `data` removes an unnecessary `SPAN_TRACK` call (because `SPAN_TRACK` is only needed for lo/hi accesses): - `span.data().ctxt` --> `span.ctxt()` --- compiler/rustc_errors/src/emitter.rs | 2 +- compiler/rustc_expand/src/proc_macro_server.rs | 8 ++++---- compiler/rustc_interface/src/callbacks.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 14 +++++++------- compiler/rustc_span/src/source_map.rs | 3 +-- .../clippy/clippy_lints/src/empty_line_after.rs | 4 ++-- src/tools/clippy/clippy_lints/src/matches/mod.rs | 8 ++++---- .../src/needless_parens_on_range_literals.rs | 4 +++- .../src/utils/format_args_collector.rs | 7 ++++--- src/tools/clippy/clippy_utils/src/hir_utils.rs | 14 +++++++------- src/tools/clippy/clippy_utils/src/source.rs | 4 ++-- src/tools/rustfmt/src/parse/session.rs | 4 +--- 15 files changed, 41 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index aee5afdfd3b04..af412ef525c95 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -365,7 +365,7 @@ pub trait Emitter { let Some(source_map) = self.source_map() else { return }; let should_hide = |span| { source_map.is_imported(span) || { - let expn = span.data().ctxt.outer_expn_data(); + let expn = span.ctxt().outer_expn_data(); expn.diagnostic_opaque && matches!(expn.kind, ExpnKind::Macro(MacroKind::Bang, _)) } }; diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index e2dca4b988a47..c17faea67b94e 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -527,24 +527,24 @@ impl server::Server for Rustc<'_, '_> { .map_err(|_| String::from("failed to parse to literal"))? .map_err(cancel_diags_into_string)?; - let first_span = parser.token.span.data(); + let (first_span_lo, first_span_hi) = parser.token.span.lo_hi(); let minus_present = parser.eat(exp!(Minus)); - let lit_span = parser.token.span.data(); + let (lit_span_lo, lit_span_hi) = parser.token.span.lo_hi(); let tk::Literal(mut lit) = parser.token.kind else { return Err("not a literal".to_string()); }; // Check no comment or whitespace surrounding the (possibly negative) // literal, or more tokens after it. - if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() { + if (lit_span_hi.0 - first_span_lo.0) as usize != s.len() { return Err("comment or whitespace around literal".to_string()); } if minus_present { // If minus is present, check no comment or whitespace in between it // and the literal token. - if first_span.hi.0 != lit_span.lo.0 { + if first_span_hi.0 != lit_span_lo.0 { return Err("comment or whitespace after minus".to_string()); } diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 2b9170c80de21..9f1b08ce5b079 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -30,7 +30,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { if tracks_deps { let _span = icx.tcx.source_span(def_id); // Sanity check: relative span's parent must be an absolute span. - debug_assert_eq!(_span.data_untracked().parent, None); + debug_assert_eq!(_span.parent(), None); } } }) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d4ddc46b43a56..ebcc6e2146917 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2369,7 +2369,7 @@ impl<'a> Parser<'a> { let move_kw_span = self.prev_token.span; // Check for `move async` and recover if self.check_keyword(exp!(Async)) { - let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + let move_async_span = self.token.span.with_lo(self.prev_token.span.lo()); Err(self.dcx().create_err(crate::diagnostics::AsyncMoveOrderIncorrect { span: move_async_span, })) @@ -2381,7 +2381,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span); // Check for `use async` and recover if self.check_keyword(exp!(Async)) { - let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + let use_async_span = self.token.span.with_lo(self.prev_token.span.lo()); Err(self.dcx().create_err(crate::diagnostics::AsyncUseOrderIncorrect { span: use_async_span, })) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2011f8646346e..45bae73deda8d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -109,7 +109,7 @@ impl<'a> Parser<'a> { } } - let inject_use_span = post_attr_lo.data().with_hi(post_attr_lo.lo()); + let inject_use_span = post_attr_lo.with_hi(post_attr_lo.lo()); let mod_spans = ModSpans { inner_span: lo.to(self.prev_token.span), inject_use_span }; Ok((attrs, items, mod_spans)) } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7a7078deaadc4..58d6b8005c787 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1745,7 +1745,7 @@ impl<'tcx> Resolver<'_, 'tcx> { } // A relative span's parent must be an absolute span. - debug_assert_eq!(span.data_untracked().parent, None); + debug_assert_eq!(span.parent(), None); let _id = self.tcx.untracked().source_span.push(span); debug_assert_eq!(_id, def_id); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 858892d1134f1..1e6f938ad2820 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1273,7 +1273,7 @@ impl Span { // Don't return something if it's marked with `#[diagnostic::opaque]`. // This already accounts for `-Zmacro-backtrace`. - if within.data().ctxt.outer_expn_data().diagnostic_opaque { + if within.ctxt().outer_expn_data().diagnostic_opaque { return None; } @@ -1414,9 +1414,9 @@ pub trait SpanEncoder: Encoder { impl SpanEncoder for FileEncoder<'_> { fn encode_span(&mut self, span: Span) { - let span = span.data(); - span.lo.encode(self); - span.hi.encode(self); + let (lo, hi) = span.lo_hi(); + lo.encode(self); + hi.encode(self); } fn encode_symbol(&mut self, sym: Symbol) { @@ -1451,9 +1451,9 @@ impl SpanEncoder for FileEncoder<'_> { impl SpanEncoder for MemEncoder { fn encode_span(&mut self, span: Span) { - let span = span.data(); - span.lo.encode(self); - span.hi.encode(self); + let (lo, hi) = span.lo_hi(); + lo.encode(self); + hi.encode(self); } fn encode_symbol(&mut self, sym: Symbol) { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f394765ab9f8e..caad0da329261 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -943,8 +943,7 @@ impl SourceMap { /// Returns a new span representing just the first character of the given span. pub fn start_point(&self, sp: Span) -> Span { let width = { - let sp = sp.data(); - let local_begin = self.lookup_byte_offset(sp.lo); + let local_begin = self.lookup_byte_offset(sp.lo()); let start_index = local_begin.pos.to_usize(); let src = local_begin.sf.external_src.read(); diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index 805f5dca1bf5d..1df1dea12db10 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -9,7 +9,7 @@ use rustc_ast::{AssocItemKind, AttrKind, AttrStyle, Attribute, Crate, Item, Item use rustc_errors::{Applicability, Diag, SuggestionStyle}; use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext as _, impl_lint_pass}; -use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol, kw, sym}; +use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, Symbol, kw, sym}; declare_clippy_lint! { /// ### What it does @@ -244,7 +244,7 @@ impl Stop { } fn from_attr(cx: &EarlyContext<'_>, attr: &Attribute) -> Option { - let SpanData { lo, hi, .. } = attr.span.data(); + let (lo, hi) = attr.span.lo_hi(); let file = cx.sess().source_map().lookup_source_file(lo); Some(Self { diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 994d4e8937273..71456bfdd941c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1252,8 +1252,8 @@ fn walk_intra_arm_text( mut f: impl FnMut(&str), ) -> bool { if let Some(src) = match_sp.get_source_range(cx) - && let scrutinee_sp = scrutinee_sp.source_callsite().data() - && let block_start = (scrutinee_sp.hi.0 - src.sf.start_pos.0) as usize + && let scrutinee_sp_hi = scrutinee_sp.source_callsite().hi() + && let block_start = (scrutinee_sp_hi.0 - src.sf.start_pos.0) as usize && let Some(src_text) = src.sf.src.as_ref().map(|x| &***x) && let Some(block_text) = src_text.get(block_start..src.range.end) && let Some(stripped_text) = block_text.trim_start_matches(is_whitespace).strip_prefix('{') @@ -1263,8 +1263,8 @@ fn walk_intra_arm_text( .strip_suffix('}') .map(|s| src.range.end - (stripped_text.len() - s.len())) && let Some(range) = arms.iter().try_fold(arms_start..arms_end, |range, arm| { - let arm_sp: rustc_span::SpanData = arm.span.source_callsite().data(); - let arm_range = (arm_sp.lo.0 - src.sf.start_pos.0) as usize..(arm_sp.hi.0 - src.sf.start_pos.0) as usize; + let (arm_sp_lo, arm_sp_hi) = arm.span.source_callsite().lo_hi(); + let arm_range = (arm_sp_lo.0 - src.sf.start_pos.0) as usize..(arm_sp_hi.0 - src.sf.start_pos.0) as usize; if range.start <= arm_range.start && arm_range.end <= range.end && let Some(src) = src_text.get(range.start..arm_range.start) diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs index 1ee87f3f4f2fa..3dc578b7aaada 100644 --- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs @@ -55,7 +55,9 @@ fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) { } if let ExprKind::Lit(literal) = e.kind // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ - && (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo) + && let (literal_span_lo, literal_span_hi) = literal.span.lo_hi() + && let (e_span_lo, e_span_hi) = e.span.lo_hi() + && literal_span_hi - literal_span_lo != e_span_hi - e_span_lo // inspect the source code of the expression for parenthesis && snippet_enclosed_in_parenthesis(&snippet(cx, e.span, "")) { diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index f5e07cc5c1d88..277ec25137b13 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -109,9 +109,10 @@ impl FormatArgsCollector { .explicit_args() .iter() .try_fold(src.range.end, |start, arg| { - let expr_sp = walk_span_to_context(arg.expr.span, fmt_sp.ctxt)?.data(); - let expr_start = (expr_sp.lo.0 - src.sf.start_pos.0) as usize; - let expr_end = (expr_sp.hi.0 - src.sf.start_pos.0) as usize; + let (expr_sp_lo, expr_sp_hi) = + walk_span_to_context(arg.expr.span, fmt_sp.ctxt)?.lo_hi(); + let expr_start = (expr_sp_lo.0 - src.sf.start_pos.0) as usize; + let expr_end = (expr_sp_hi.0 - src.sf.start_pos.0) as usize; let mut tks = tokenize(src_text.get(start..expr_start)?, FrontmatterAllowed::No) .map(|x| x.kind) .filter(|x| { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3075589deb803..8957968e9decb 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -425,26 +425,26 @@ impl HirEqInterExpr<'_, '_, '_> { let Some(rstmt_span) = walk_span_to_context(right.span, rspan.ctxt) else { return false; }; - let lstmt_span = lstmt_span.data(); - let rstmt_span = rstmt_span.data(); + let (lstmt_span_lo, lstmt_span_hi) = lstmt_span.lo_hi(); + let (rstmt_span_lo, rstmt_span_hi) = rstmt_span.lo_hi(); - if lstmt_span.lo < lstart && rstmt_span.lo < rstart { + if lstmt_span_lo < lstart && rstmt_span_lo < rstart { // Can happen when macros expand to multiple statements, or rearrange statements. // Nothing in between the statements to check in this case. continue; } - if lstmt_span.lo < lstart || rstmt_span.lo < rstart { + if lstmt_span_lo < lstart || rstmt_span_lo < rstart { // Only one of the blocks had a weird macro. return false; } - if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { + if !eq_span_tokens(self.inner.cx, lstart..lstmt_span_lo, rstart..rstmt_span_lo, |t| { !matches!(t, Whitespace | Semi) }) { return false; } - lstart = lstmt_span.hi; - rstart = rstmt_span.hi; + lstart = lstmt_span_hi; + rstart = rstmt_span_hi; } let (lend, rend) = match (left.expr, right.expr) { diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 80c38904ea54a..69d679bba09b6 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -63,8 +63,8 @@ pub trait SpanRange: Sized { } impl SpanRange for Span { fn into_range(self) -> Range { - let data = self.data(); - data.lo..data.hi + let (lo, hi) = self.lo_hi(); + lo..hi } } impl SpanRange for SpanData { diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index c61b43492ce9e..0df194066072e 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -195,9 +195,7 @@ impl ParseSess { } pub(crate) fn span_to_file_contents(&self, span: Span) -> Arc { - self.raw_psess - .source_map() - .lookup_source_file(span.data().lo) + self.raw_psess.source_map().lookup_source_file(span.lo()) } pub(crate) fn span_to_first_line_string(&self, span: Span) -> String { From ecf162287aabccd3acb690ad56d0e6bf75ed3633 Mon Sep 17 00:00:00 2001 From: panstromek Date: Sun, 25 Oct 2026 21:23:40 +0100 Subject: [PATCH 26/27] ref: remove redundant vec and duplicate indexing in find_noop_landing_pads --- .../src/remove_noop_landing_pads.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index c340d82d0a80b..61c2a3c337807 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -172,15 +172,9 @@ fn find_noop_landing_pads<'tcx>( // This is a post-order traversal, so that if A post-dominates B // then A will be visited before B. - let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect(); - for bb in postorder { - let is_nop_landing_pad = RemoveNoopLandingPads.is_nop_landing_pad( - tcx, - &body.basic_blocks[bb], - body, - &nop_landing_pads, - extra, - ); + for (bb, bb_data) in traversal::postorder(body) { + let is_nop_landing_pad = + RemoveNoopLandingPads.is_nop_landing_pad(tcx, bb_data, body, &nop_landing_pads, extra); if is_nop_landing_pad { nop_landing_pads.insert(bb); } From 0ca3407c57a6684da242358dc1ab5c3fea47130a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Oct 2026 09:48:54 +0100 Subject: [PATCH 27/27] thread_local::guard: update comments a bit --- library/std/src/sys/thread_local/guard/key.rs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/thread_local/guard/key.rs b/library/std/src/sys/thread_local/guard/key.rs index 1d4e4c76a47a8..d9666cb08a05e 100644 --- a/library/std/src/sys/thread_local/guard/key.rs +++ b/library/std/src/sys/thread_local/guard/key.rs @@ -1,6 +1,6 @@ -//! A lot of UNIX platforms don't have a specialized way to register TLS -//! destructors for native TLS. Instead, we use one TLS key with a destructor -//! that will run all native TLS destructors in the destructor list. +//! A lot of UNIX platforms don't have a specialized way to register TLS destructors for native TLS +//! (i.e., `#[thread_local] static`). Instead, we use one TLS key with a destructor that will run +//! all native TLS destructors in the destructor list. It also runs `rt::thread_cleanup`. #[cfg(target_thread_local)] pub fn enable() { @@ -18,12 +18,13 @@ pub fn enable() { unsafe extern "C" fn run(_: *mut u8) { unsafe { + // Rust thread-local destructors should run *before* `rt::thread_cleanup`. destructors::run(); - // On platforms with `__cxa_thread_atexit_impl`, `destructors::run` - // does nothing on newer systems as the TLS destructors are - // registered with the system. But because all of those platforms - // call the destructors of TLS keys after the registered ones, this - // function will still be run last (at the time of writing). + // On platforms with `__cxa_thread_atexit_impl`, `destructors::run` does nothing as the + // TLS destructors are registered with the system. But because all of those platforms + // call the destructors of TLS keys *after* the registered "atexit" ones, this function + // will still be run last (at the time of writing). The `thread_current_in_dtor` test + // confirms this. crate::rt::thread_cleanup(); } } @@ -42,9 +43,10 @@ mod key_based { static CLEANUP: LazyKey = LazyKey::new(Some(run)); - /// On platforms with key-based TLS, the system runs the destructors for us. - /// We still have to make sure that [`crate::rt::thread_cleanup`] is called, - /// however. This is done by deferring the execution of a TLS destructor to + /// On platforms with key-based TLS, the system runs the destructors for us, so we don't have to + /// call `destructors::run`. We still have to make sure that [`crate::rt::thread_cleanup`] is + /// called, however. And we should make sure that it is called *last*, after dropping all + /// regular Rust thread-locals. This is done by deferring the execution of a TLS destructor to /// the next round of destruction inside the TLS destructors. pub fn enable() { unsafe { set(CLEANUP.force(), DEFER) }